Browse Source

todo: 分发

GTong 8 months ago
parent
commit
bff89949a7

+ 10 - 1
TODO.text

@@ -11,4 +11,13 @@
       如果对应第二种情况,可以考虑下单独的信息校验按钮,如果已生成了license的表单点击该按钮发现数据存在变更,则需重新生成等等。  
   6.之前提到过的生成和分发单独进行的功能。可操作性更强,生成了不一定及时分发,可先生成后分发。 
   
-  7.不同权限用户访问粒度控制,以及指定用户查询与自己相关license进展的问题。
+  7.不同权限用户访问粒度控制,以及指定用户查询与自己相关license进展的问题。
+
+
+
+  权限应该有层级划分, 我看你创建了个roletest的权限, 他可以给其他用户分配admin的权限。 这个点位不靠谱。
+
+
+   发送license到邮箱,那个license名称是没有标识的吧? 如果一个项目生成N个license,后续项目上怎么去对应license呢?
+
+   提供下载license按钮

+ 1 - 0
internal/api/license_api.go

@@ -49,6 +49,7 @@ type GenerateLicenseStrRequest struct {
 // 分发license给用户
 type DistributeLicenseRequest struct {
 	LicenseUniqueID  string   `json:"LicenseUniqueID"`
+	OaRequestId      string   `json:"Oa_request_id"`
 	OperatorUniqueID string   `json:"OperatorUniqueID"`
 	UserUniqueIDs    []string `json:"UserUniqueIDs"`
 	UserAccounts     []string `json:"UserAccounts"`

+ 84 - 19
internal/controllers/OALicenseInfo_controllers.go

@@ -11,6 +11,7 @@ import (
 	"xugu_license/internal/global"
 	middlewares "xugu_license/internal/middleware"
 	"xugu_license/internal/models"
+	"xugu_license/internal/module/capture"
 	"xugu_license/internal/module/email"
 	"xugu_license/internal/utils"
 
@@ -598,6 +599,10 @@ func generateLicenseStrSub(UniqueID string) error {
 // 	//如果不一致,则修改源数据
 // }
 
+/*
+对单条lic或是申请单的处理
+检测lic是否以及分发过给用户
+*/
 func DistributeOALicenseController(c *gin.Context) {
 
 	//判断是否发邮件
@@ -610,33 +615,57 @@ func DistributeOALicenseController(c *gin.Context) {
 		})
 		return
 	}
-	fmt.Println("DistributeLicenseRequest", request)
 
-	//查询该license是否已经分发给了该用户
 	var licToUser []string
-	for i, v := range request.UserUniqueIDs {
-		fmt.Println("request.UserUniqueIDs", request.LicenseUniqueID, v)
-		if isTurn, err := models.CheckLicenseToUser(request.LicenseUniqueID, v); err != nil {
-			global.Logger.Errorln("该license查询是否分发给用户失败 ", v, err.Error())
+	if request.OaRequestId != "" {
+		//获取该license申请单的所有子信息
+		datas, _, err := models.GetOALicenseInfo(0, 0, "", "", "", request.OaRequestId)
+		if err != nil {
+			global.Logger.Errorln("license分发请求查询license申请单的所有子信息失败  %s", err.Error())
 			c.JSON(400, gin.H{
-				"success": false,
-				"error":   fmt.Sprintf("该license查询是否分发给用户失败: %s", v, err.Error()),
+				"error": fmt.Sprintf("license分发请求解析失败  %s", err.Error()),
 			})
 			return
-		} else if isTurn {
-			global.Logger.Info("该license已经分发给了该用户 ", v)
-			licToUser = append(licToUser, request.UserNames[i])
 		}
 
-	}
+		for _, oaLicInfo := range *datas {
+			users, err := checkDistributeToUser(&oaLicInfo, request.UserUniqueIDs, request.UserNames)
+			if err != nil {
+				global.Logger.Errorln("license分发请求检测是否已发放给用户失败  %s", err.Error())
+				c.JSON(400, gin.H{
+					"error": fmt.Sprintf("license分发请求解析失败  %s", err.Error()),
+				})
+				return
+			}
+
+			if len(users) != 0 {
+				c.JSON(400, gin.H{
+					"success": false,
+					"error":   fmt.Sprintf("该license已经分发给了该用户: %s\n", licToUser),
+				})
+				return
+			}
+
+		}
+
+	} else if request.LicenseUniqueID != "" {
+		//查询该license是否已经分发给了该用户
+		for i, v := range request.UserUniqueIDs {
+			fmt.Println("request.UserUniqueIDs", request.LicenseUniqueID, v)
+			if isTurn, err := models.CheckLicenseToUser(request.LicenseUniqueID, v); err != nil {
+				global.Logger.Errorln("该license查询是否分发给用户失败 ", v, err.Error())
+				c.JSON(400, gin.H{
+					"success": false,
+					"error":   fmt.Sprintf("该license查询是否分发给用户失败: %s", v, err.Error()),
+				})
+				return
+			} else if isTurn {
+				global.Logger.Info("该license已经分发给了该用户 ", v)
+				licToUser = append(licToUser, request.UserNames[i])
+			}
+
+		}
 
-	//返回已经分发过的用户
-	if len(licToUser) != 0 {
-		c.JSON(400, gin.H{
-			"success": false,
-			"error":   fmt.Sprintf("该license已经分发给了该用户: %s\n", licToUser),
-		})
-		return
 	}
 
 	applications, _, err := models.GetOALicenseInfo(1, 1, "", request.LicenseUniqueID, "", "")
@@ -894,3 +923,39 @@ func DelLicenseInfoRow(c *gin.Context) {
 	})
 
 }
+
+// 主动抓取一次license信息到支撑库
+func CaptureLicenseOnceToDb(c *gin.Context) {
+	if err := capture.CaptureOnce(global.OaDB, global.XuguDB); err != nil {
+		global.Logger.Errorln("主动抓取license信息到支撑库失败:  ", err.Error())
+		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("主动抓取license信息数据失败: %s", err.Error())})
+		return
+	}
+	c.JSON(http.StatusOK, gin.H{
+		"success": true,
+	})
+}
+
+func SearchLicInfoToDb(c *gin.Context) {
+
+	// var request string
+	// if err := c.ShouldBindJSON(&request); err != nil {
+	// 	c.JSON(400, gin.H{
+	// 		"error": err.Error(),
+	// 	})
+	// 	return
+	// }
+	request := c.Param("data")
+
+	if datas, err := models.SearchLicInfoToDb(request); err != nil {
+		global.Logger.Errorln("搜索license信息失败:  ", err.Error())
+		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("搜索license信息失败失败: %s", err.Error())})
+		return
+	} else {
+		c.JSON(http.StatusOK, gin.H{
+			"success": true,
+			"data":    datas,
+		})
+	}
+
+}

+ 30 - 0
internal/controllers/OALicenseInfo_sub_controllers.go

@@ -0,0 +1,30 @@
+package controllers
+
+import (
+	"xugu_license/internal/global"
+	"xugu_license/internal/models"
+)
+
+func checkDistributeToUser(oaLicInfo *models.OALicenseInfo, UserUniqueIDs []string, UserNames []string) (licToUser []string, err error) {
+
+	for i, v := range UserUniqueIDs {
+
+		if !oaLicInfo.LicInfo.UniqueID.Valid {
+			global.Logger.Errorln("获取到的申请单单行UniqueID为空,请联系管理员 ")
+
+			return
+		}
+
+		//查询该license是否已经分发给了该用户
+		if isTurn, err := models.CheckLicenseToUser(oaLicInfo.LicInfo.UniqueID.String, v); err != nil {
+			global.Logger.Errorln("该license查询是否分发给用户失败 ", v, err.Error())
+
+			return nil, err
+		} else if isTurn {
+			global.Logger.Info("该license已经分发给了该用户 ", v, UserNames[i])
+			licToUser = append(licToUser, UserNames[i])
+		}
+
+	}
+	return licToUser, nil
+}

+ 16 - 9
internal/middleware/auth.go

@@ -36,7 +36,8 @@ const (
 	DeleteLicense     Permission = "delete_license"      //删除license
 	// 消息分发权限
 	DispatLicense Permission = "dispat_license" //分发license
-
+	// 主动抓取oaLicense到支撑库
+	CaptureLicenseOnceToDb Permission = "capture_license_once_to_db" //主动抓取oaLicense到支撑库
 	// 获得用户信息
 	//GetUserInfo1 Permission = "get_user_info" //获得用户信息
 	// 用户管理权限
@@ -54,14 +55,16 @@ const (
 
 // 定义映射
 var permissionMap = map[string]Permission{
-	"generate_license":    GenerateLicense,
-	"upload_license":      UploadLicense,
-	"read_license":        ReadLicense,
-	"read_all_license":    ReadAllLicense,
-	"read_license_record": ReadlicenseRecord,
-	"update_license":      UpdateLicense,
-	"delete_license":      DeleteLicense,
-	"dispat_license":      DispatLicense,
+	"generate_license":           GenerateLicense,
+	"upload_license":             UploadLicense,
+	"read_license":               ReadLicense,
+	"read_all_license":           ReadAllLicense,
+	"read_license_record":        ReadlicenseRecord,
+	"update_license":             UpdateLicense,
+	"delete_license":             DeleteLicense,
+	"dispat_license":             DispatLicense,
+	"capture_license_once_to_db": CaptureLicenseOnceToDb,
+
 	//"get_user_info":    GetUserInfo1,
 	"create_user": CreateUser,
 	"read_user":   ReadUser,
@@ -113,6 +116,7 @@ var AdminRole = Role{
 		UpdateLicense,
 		DeleteLicense,
 		DispatLicense,
+		CaptureLicenseOnceToDb,
 		//GetUserInfo1,
 		ReadlicenseRecord,
 		CreateUser,
@@ -136,6 +140,9 @@ var SupportRole = Role{
 		//GetUserInfo1,
 		ReadlicenseRecord,
 		ReadUser,
+		UpdateUser,
+		DeleteUser,
+		CreateRole,
 		UploadLicense,
 	},
 }

+ 63 - 144
internal/models/license_oa_models.go

@@ -724,154 +724,73 @@ where fmd.id  = ?
 	return true, nil
 }
 
-func compareAndCopy(sqlResult SQLResult, target *TargetOALicenseInfo) bool {
-	// 标志位,初始为 true,表示默认所有值相等
-	isEqual := true
-
-	// 比较 OARequestName
-	if sqlResult.OARequestName != target.OARequestName {
-		target.OARequestName = sqlResult.OARequestName
-		isEqual = false
-	}
-
-	// 比较 OARequestNameNew
-	if sqlResult.OARequestNameNew != target.OARequestNameNew {
-		target.OARequestNameNew = sqlResult.OARequestNameNew
-		isEqual = false
-	}
-
-	// 比较 OARequestNameHTMLNew
-	if sqlResult.OARequestNameHTMLNew != target.OARequestNameHTMLNew {
-		target.OARequestNameHTMLNew = sqlResult.OARequestNameHTMLNew
-		isEqual = false
-	}
-
-	// 比较 OAGLXMID
-	if sqlResult.OAGLXMID != target.OAGLXMID {
-		target.OAGLXMID = sqlResult.OAGLXMID
-		isEqual = false
-	}
-
-	// 比较 OAGLXMName
-	if sqlResult.OAGLXMName != target.OAGLXMName {
-		target.OAGLXMName = sqlResult.OAGLXMName
-		isEqual = false
-	}
-
-	// 比较 OASQSJ
-	if sqlResult.OASQSJ != target.OASQSJ {
-		target.OASQSJ = sqlResult.OASQSJ
-		isEqual = false
-	}
-
-	// 比较 OASalespersonName
-	if sqlResult.OASalespersonName != target.OASalespersonName {
-		target.OASalespersonName = sqlResult.OASalespersonName
-		isEqual = false
-	}
-
-	// 比较 OAOperationsPersonName
-	if sqlResult.OAOperationsPersonName != target.OAOperationsPersonName {
-		target.OAOperationsPersonName = sqlResult.OAOperationsPersonName
-		isEqual = false
-	}
-
-	// 比较 OAXSJSYX
-	if sqlResult.OAXSJSYX != target.OAXSJSYX {
-		target.OAXSJSYX = sqlResult.OAXSJSYX
-		isEqual = false
-	}
-
-	// 比较 OAJFJSYX
-	if sqlResult.OAJFJSYX != target.OAJFJSYX {
-		target.OAJFJSYX = sqlResult.OAJFJSYX
-		isEqual = false
-	}
-
-	// 比较 OASYDW
-	if sqlResult.OASYDW != target.OASYDW {
-		target.OASYDW = sqlResult.OASYDW
-		isEqual = false
-	}
-
-	// 比较 OAXMXXMS
-	if sqlResult.OAXMXXMS != target.OAXMXXMS {
-		target.OAXMXXMS = sqlResult.OAXMXXMS
-		isEqual = false
-	}
-
-	// 比较 OAJDS
-	if sqlResult.OAJDS != target.OAJDS {
-		target.OAJDS = sqlResult.OAJDS
-		isEqual = false
-	}
-
-	// 比较 OANodeCount
-	if sqlResult.OANodeCount != target.OANodeCount {
-		target.OANodeCount = sqlResult.OANodeCount
-		isEqual = false
-	}
-
-	// 比较 OAProductCode
-	// if sqlResult.OAProductCode != target.OAProductCode {
-	// 	target.OAProductCode = sqlResult.OAProductCode
-	// 	isEqual = false
-	// }
-
-	// 比较 OAProductVersion
-	if sqlResult.OAProductVersion != target.OAProductVersion {
-		target.OAProductVersion = sqlResult.OAProductVersion
-		isEqual = false
-	}
-
-	// 比较 CLQ
-	if sqlResult.CLQ != target.OACPU {
-		target.OACPU = sqlResult.CLQ
-		isEqual = false
-	}
-
-	// 比较 CZXT
-	if sqlResult.CZXT != target.OAOperatingSystem {
-		target.OAOperatingSystem = sqlResult.CZXT
-		isEqual = false
-	}
-
-	// 比较 IP
-	if sqlResult.IP != target.OAMainMAC {
-		target.OAMainMAC = sqlResult.IP
-		isEqual = false
-	}
-
-	// 比较 MAC
-	if sqlResult.MAC != target.OASecondMAC {
-		target.OASecondMAC = sqlResult.MAC
-		isEqual = false
-	}
-
-	// 比较 OACreationDate
-	if sqlResult.OACreationDate != target.OACreationDate {
-		target.OACreationDate = sqlResult.OACreationDate
-		isEqual = false
+func SearchLicInfoToDb(userInput string) ([]TargetOALicenseInfo, error) {
+	query := fmt.Sprintf(`
+		SELECT 
+			ID, UNIQUE_ID, OA_REQUESTID, OA_REQUESTNAME, OA_REQUESTNAMENEW, OA_REQUESTNAMEHTMLNEW,
+			OA_GLXMID, OA_GLXMNAME, OA_SQSJ, OA_SALESPERSONNAME, OA_XSJSYX, OA_OPERATIONSPERSONNAME,
+			OA_JFJSYX, OA_SYDW, OA_XMXXMS, OA_JDS, OA_NODECOUNT, OA_PRODUCTCODE, OA_PRODUCTNAME,
+			OA_PRODUCTVERSION, OA_CPU, OA_OPERATINGSYSTEM, OA_MAINMAC, OA_SECONDMAC, 
+			OA_CREATIONDATE, OA_CREATIONTIME, OA_LASTOPERATEDATE, OA_LASTOPERATETIME
+		FROM SYSDBA.TARGET_OA_LICENSE
+		WHERE 
+			UNIQUE_ID LIKE '%%%s%%' OR
+			OA_REQUESTNAME LIKE '%%%s%%' OR
+			OA_REQUESTNAMENEW LIKE '%%%s%%' OR
+			OA_REQUESTNAMEHTMLNEW LIKE '%%%s%%' OR
+			OA_GLXMNAME LIKE '%%%s%%' OR
+			OA_SQSJ LIKE '%%%s%%' OR
+			OA_SALESPERSONNAME LIKE '%%%s%%' OR
+			OA_XSJSYX LIKE '%%%s%%' OR
+			OA_OPERATIONSPERSONNAME LIKE '%%%s%%' OR
+			OA_JFJSYX LIKE '%%%s%%' OR
+			OA_SYDW LIKE '%%%s%%' OR
+			OA_XMXXMS LIKE '%%%s%%' OR
+			OA_PRODUCTCODE LIKE '%%%s%%' OR
+			OA_PRODUCTNAME LIKE '%%%s%%' OR
+			OA_PRODUCTVERSION LIKE '%%%s%%' OR
+			OA_CPU LIKE '%%%s%%' OR
+			OA_OPERATINGSYSTEM LIKE '%%%s%%' OR
+			OA_MAINMAC LIKE '%%%s%%' OR
+			OA_SECONDMAC LIKE '%%%s%%' OR
+			OA_CREATIONDATE LIKE '%%%s%%' OR
+			OA_CREATIONTIME LIKE '%%%s%%' OR
+			OA_LASTOPERATEDATE LIKE '%%%s%%' OR
+			OA_LASTOPERATETIME LIKE '%%%s%%';
+	`, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput, userInput)
+
+	rows, err := global.XuguDB.Query(query)
+	if err != nil {
+		return nil, err
 	}
+	defer rows.Close()
 
-	// 比较 OACreationTime
-	if sqlResult.OACreationTime != target.OACreationTime {
-		target.OACreationTime = sqlResult.OACreationTime
-		isEqual = false
+	// 处理查询结果
+	var licenses []TargetOALicenseInfo
+	for rows.Next() {
+		var license TargetOALicenseInfo
+		err := rows.Scan(
+			&license.ID, &license.UniqueID, &license.OARequestID, &license.OARequestName,
+			&license.OARequestNameNew, &license.OARequestNameHTMLNew, &license.OAGLXMID,
+			&license.OAGLXMName, &license.OASQSJ, &license.OASalespersonName, &license.OAXSJSYX,
+			&license.OAOperationsPersonName, &license.OAJFJSYX, &license.OASYDW, &license.OAXMXXMS,
+			&license.OAJDS, &license.OANodeCount, &license.OAProductCode, &license.OAProductName,
+			&license.OAProductVersion, &license.OACPU, &license.OAOperatingSystem, &license.OAMainMAC,
+			&license.OASecondMAC, &license.OACreationDate, &license.OACreationTime, &license.OALastOperateDate,
+			&license.OALastOperateTime,
+		)
+		if err != nil {
+			log.Fatal(err)
+		}
+		licenses = append(licenses, license)
 	}
-
-	// 比较 OALastOperateDate
-	if sqlResult.OALastOperateDate != target.OALastOperateDate {
-		target.OALastOperateDate = sqlResult.OALastOperateDate
-		isEqual = false
+	if err != nil {
+		log.Fatal(err)
 	}
 
-	// 比较 OALastOperateTime
-	if sqlResult.OALastOperateTime != target.OALastOperateTime {
-		target.OALastOperateTime = sqlResult.OALastOperateTime
-		isEqual = false
+	// 检查错误
+	if err := rows.Err(); err != nil {
+		log.Fatal(err)
 	}
-
-	// 返回标志位
-	return isEqual
+	return licenses, nil
 }

+ 153 - 0
internal/models/models_util.go

@@ -0,0 +1,153 @@
+package models
+
+func compareAndCopy(sqlResult SQLResult, target *TargetOALicenseInfo) bool {
+	// 标志位,初始为 true,表示默认所有值相等
+	isEqual := true
+
+	// 比较 OARequestName
+	if sqlResult.OARequestName != target.OARequestName {
+		target.OARequestName = sqlResult.OARequestName
+		isEqual = false
+	}
+
+	// 比较 OARequestNameNew
+	if sqlResult.OARequestNameNew != target.OARequestNameNew {
+		target.OARequestNameNew = sqlResult.OARequestNameNew
+		isEqual = false
+	}
+
+	// 比较 OARequestNameHTMLNew
+	if sqlResult.OARequestNameHTMLNew != target.OARequestNameHTMLNew {
+		target.OARequestNameHTMLNew = sqlResult.OARequestNameHTMLNew
+		isEqual = false
+	}
+
+	// 比较 OAGLXMID
+	if sqlResult.OAGLXMID != target.OAGLXMID {
+		target.OAGLXMID = sqlResult.OAGLXMID
+		isEqual = false
+	}
+
+	// 比较 OAGLXMName
+	if sqlResult.OAGLXMName != target.OAGLXMName {
+		target.OAGLXMName = sqlResult.OAGLXMName
+		isEqual = false
+	}
+
+	// 比较 OASQSJ
+	if sqlResult.OASQSJ != target.OASQSJ {
+		target.OASQSJ = sqlResult.OASQSJ
+		isEqual = false
+	}
+
+	// 比较 OASalespersonName
+	if sqlResult.OASalespersonName != target.OASalespersonName {
+		target.OASalespersonName = sqlResult.OASalespersonName
+		isEqual = false
+	}
+
+	// 比较 OAOperationsPersonName
+	if sqlResult.OAOperationsPersonName != target.OAOperationsPersonName {
+		target.OAOperationsPersonName = sqlResult.OAOperationsPersonName
+		isEqual = false
+	}
+
+	// 比较 OAXSJSYX
+	if sqlResult.OAXSJSYX != target.OAXSJSYX {
+		target.OAXSJSYX = sqlResult.OAXSJSYX
+		isEqual = false
+	}
+
+	// 比较 OAJFJSYX
+	if sqlResult.OAJFJSYX != target.OAJFJSYX {
+		target.OAJFJSYX = sqlResult.OAJFJSYX
+		isEqual = false
+	}
+
+	// 比较 OASYDW
+	if sqlResult.OASYDW != target.OASYDW {
+		target.OASYDW = sqlResult.OASYDW
+		isEqual = false
+	}
+
+	// 比较 OAXMXXMS
+	if sqlResult.OAXMXXMS != target.OAXMXXMS {
+		target.OAXMXXMS = sqlResult.OAXMXXMS
+		isEqual = false
+	}
+
+	// 比较 OAJDS
+	if sqlResult.OAJDS != target.OAJDS {
+		target.OAJDS = sqlResult.OAJDS
+		isEqual = false
+	}
+
+	// 比较 OANodeCount
+	if sqlResult.OANodeCount != target.OANodeCount {
+		target.OANodeCount = sqlResult.OANodeCount
+		isEqual = false
+	}
+
+	// 比较 OAProductCode
+	// if sqlResult.OAProductCode != target.OAProductCode {
+	// 	target.OAProductCode = sqlResult.OAProductCode
+	// 	isEqual = false
+	// }
+
+	// 比较 OAProductVersion
+	if sqlResult.OAProductVersion != target.OAProductVersion {
+		target.OAProductVersion = sqlResult.OAProductVersion
+		isEqual = false
+	}
+
+	// 比较 CLQ
+	if sqlResult.CLQ != target.OACPU {
+		target.OACPU = sqlResult.CLQ
+		isEqual = false
+	}
+
+	// 比较 CZXT
+	if sqlResult.CZXT != target.OAOperatingSystem {
+		target.OAOperatingSystem = sqlResult.CZXT
+		isEqual = false
+	}
+
+	// 比较 IP
+	if sqlResult.IP != target.OAMainMAC {
+		target.OAMainMAC = sqlResult.IP
+		isEqual = false
+	}
+
+	// 比较 MAC
+	if sqlResult.MAC != target.OASecondMAC {
+		target.OASecondMAC = sqlResult.MAC
+		isEqual = false
+	}
+
+	// 比较 OACreationDate
+	if sqlResult.OACreationDate != target.OACreationDate {
+		target.OACreationDate = sqlResult.OACreationDate
+		isEqual = false
+	}
+
+	// 比较 OACreationTime
+	if sqlResult.OACreationTime != target.OACreationTime {
+		target.OACreationTime = sqlResult.OACreationTime
+		isEqual = false
+	}
+
+	// 比较 OALastOperateDate
+	if sqlResult.OALastOperateDate != target.OALastOperateDate {
+		target.OALastOperateDate = sqlResult.OALastOperateDate
+		isEqual = false
+	}
+
+	// 比较 OALastOperateTime
+	if sqlResult.OALastOperateTime != target.OALastOperateTime {
+		target.OALastOperateTime = sqlResult.OALastOperateTime
+		isEqual = false
+	}
+
+	// 返回标志位
+	return isEqual
+}

+ 51 - 28
internal/module/capture/capture.go

@@ -41,41 +41,46 @@ type OALicRecord struct {
 }
 
 func StartCapture(sourceDB, targetDB *sql.DB) {
+	InitLogs("./logs/capture", "info")
+
 	tableName := "target_OA_license"
 
 	// 读取上次同步时间
 	lastSyncTime, err := getLastSyncTime(targetDB, tableName)
 	if err != nil {
-		log.Fatal("Failed to retrieve last sync time from target DB:", err)
+		Logger.Fatal("获取上次同步时间错误 Failed to retrieve last sync time from target DB:", err)
 	}
 
 	// 启动数据同步,每隔15分钟运行一次
 	for {
-		fmt.Println("Start capturing data...")
-
+		Logger.Println("Start capturing data...")
 		checkTemp, err := checkSourceOaLicTime(sourceDB, lastSyncTime)
 		if err != nil {
-			log.Println("Failed to checkSourceOaLicTime:", err)
+			Logger.Error("Failed to checkSourceOaLicTime:", err)
+			continue
 		}
 		if !checkTemp {
 			time.Sleep(15 * time.Second)
 			continue
 		}
-		fmt.Println("有新数据")
+
+		Logger.Println("有新数据")
 		lastSyncTime1, count, err := captureData(sourceDB, targetDB, lastSyncTime)
 		lastSyncTime = lastSyncTime1
 		if err != nil {
-			log.Println("Failed to capture data:", err)
+			Logger.Error("抓取源数据错误 Failed to capture data:", err)
 		}
-		fmt.Println("抓完一次数据")
+
 		if err := insertSyncMetadata(targetDB, tableName, lastSyncTime); err != nil {
-			log.Println("Failed to insert sync metadata into target DB:", err)
+			Logger.Error("插入同步时间表错误 Failed to insert sync metadata into target DB:", err)
 		}
-		fmt.Println("插入时间: ", lastSyncTime)
+		Logger.Println("插入时间: ", lastSyncTime)
 		if count > 0 {
 			//lic关联用户表
-			insertLicToUser(count, targetDB)
-
+			err := insertLicToUser(count, targetDB)
+			if err != nil {
+				Logger.Error("关联用户表错误 Failed to insertLicToUser:", err)
+			}
 		}
 		time.Sleep(15 * time.Second)
 	}
@@ -87,16 +92,16 @@ func insertLicToUser(count int, targetDB *sql.DB) error {
 
 	rows, err := targetDB.Query(query, count)
 	if err != nil {
-		log.Println("Failed to execute query on source DB:", err)
+		Logger.Println("查询源库最新数据错误 Failed to execute query on source DB:", err)
 		return err
 	}
 	defer rows.Close()
-	fmt.Println("查询到最新的count条数据 ", count)
+	Logger.Println("查询到最新的count条数据 ", count)
 	for rows.Next() {
 		var licUniqueID, salesPersonName, operationsPersonName sql.NullString
 		err := rows.Scan(&licUniqueID, &salesPersonName, &operationsPersonName)
 		if err != nil {
-			log.Println("insertLicToUser find newdata Failed to scan row:", err)
+			Logger.Error("插入到目标库错误 insertLicToUser find newdata Failed to scan row:", err)
 			continue
 		}
 
@@ -106,12 +111,15 @@ func insertLicToUser(count int, targetDB *sql.DB) error {
 						(USERNAME = ?  OR USERNAME = ? )
 						and (role = 'ADMIN'  OR  role = 'supportRole' OR  role = 'salesRole');`
 		err = targetDB.QueryRow(queryLIC_USER, salesPersonName, operationsPersonName).Scan(&userUNIQUEID, &userACCOUNT)
+		if err == sql.ErrNoRows {
+			Logger.Warn("No rows were returned")
+			continue
+		}
 		if err != nil {
-			log.Println("find user name Failed to scan row :", err)
+			Logger.Error("find user name Failed to scan row :", err)
 			continue
 		}
-		fmt.Println("salesPersonName and operationsPersonName ", salesPersonName, operationsPersonName)
-		fmt.Println("userUNIQUEID and userACCOUNT ", userUNIQUEID, userACCOUNT)
+
 		//fmt.Println("关联到用户 ", userUNIQUEID, userACCOUNT)
 		insertQuery := "INSERT  INTO LICENSERECORDTOUSER(LICENSE_UNIQUEID,USER_UNIQUEID,USER_ACCOUNT,OPERATOR_UNIQUEID,UP_TIME) VALUES(?,?,?,'SYSTEM_AUTO',?)"
 		_, err = targetDB.Exec(insertQuery,
@@ -122,7 +130,7 @@ func insertLicToUser(count int, targetDB *sql.DB) error {
 		)
 
 		if err != nil {
-			log.Println("Failed to sql2 insert record into target DB:", err)
+			Logger.Error("lic关联到目标库用户错误 Failed to sql2 insert record into target DB:", err)
 		}
 	}
 
@@ -130,22 +138,37 @@ func insertLicToUser(count int, targetDB *sql.DB) error {
 }
 
 // CaptureOnce 主动触发一次数据抓取
-func CaptureOnce(sourceDB, targetDB *sql.DB) {
+func CaptureOnce(sourceDB, targetDB *sql.DB) error {
 	tableName := "target_OA_license"
 
 	// 读取上次同步时间
 	lastSyncTime, err := getLastSyncTime(targetDB, tableName)
 	if err != nil {
-		log.Println("Failed to retrieve last sync time from target DB:", err)
-		return
+		Logger.Error("Failed to retrieve last sync time from target DB:", err)
+		return err
 	}
 
 	// 执行一次数据抓取
 	lastSyncTime, count, err := captureData(sourceDB, targetDB, lastSyncTime)
+	if err != nil {
+		Logger.Error("Failed to capture data:", err)
+		return err
+	}
 	if err := insertSyncMetadata(targetDB, tableName, lastSyncTime); err != nil {
-		log.Println("Failed to insert sync metadata into target DB:", err)
+		Logger.Error("Failed to insert sync metadata into target DB:", err)
+		return err
 	}
-	fmt.Println("Captured", count, "records.")
+	Logger.Println("Captured", count, "records.")
+
+	if count > 0 {
+		//lic关联用户表
+		err := insertLicToUser(count, targetDB)
+		if err != nil {
+			Logger.Error("insertLicToUser Failed to insert record into target DB:", err)
+			return err
+		}
+	}
+	return nil
 }
 
 // getLastSyncTime 从数据库中获取指定表的上次同步时间
@@ -182,11 +205,11 @@ where
 TO_TIMESTAMP(wr.CREATEDATE || ' ' || wr.CREATETIME, 'YYYY-MM-DD HH24:MI:SS') > TO_TIMESTAMP(?, 'YYYY-MM-DD HH24:MI:SS');`
 	error := sourceDB.QueryRow(checkTime, lastSyncTime).Scan(&checkCount)
 	if error != nil {
-		log.Println("Failed to check count:", error)
+		Logger.Println("Failed to check count:", error)
 		return false, error
 	}
 	if checkCount == 0 {
-		fmt.Println("没有新数据需要同步")
+		Logger.Println("没有新数据需要同步")
 		return false, nil
 	}
 	return true, nil
@@ -239,7 +262,7 @@ func captureData(sourceDB, targetDB *sql.DB, lastSyncTime time.Time) (time.Time,
 	var count int
 	rows, err := sourceDB.Query(query, lastSyncTime.Format("2006-01-02 15:04:05"))
 	if err != nil {
-		log.Println("Failed to execute query on source DB:", err)
+		Logger.Println("Failed to execute query on source DB:", err)
 		return lastSyncTime, 0, err
 	}
 	defer rows.Close()
@@ -290,7 +313,7 @@ func captureData(sourceDB, targetDB *sql.DB, lastSyncTime time.Time) (time.Time,
 		// 插入新数据到目标数据库
 		err := insertOALicRecordIntoTargetDB(targetDB, record)
 		if err != nil {
-			log.Println("Failed to insert record into target DB:", err)
+			Logger.Println("Failed to insert record into target DB:", err)
 			return lastSyncTime, 0, err
 		}
 		//fmt.Printf("Inserted record with OA_REQUESTID %d into target DB.\n", record.OA_REQUESTID.Int32)
@@ -412,7 +435,7 @@ func insertOALicRecordIntoTargetDB(targetDB *sql.DB, record OALicRecord) error {
 	)
 
 	if err != nil {
-		log.Println("Failed to sql2 insert record into target DB:", err)
+		Logger.Println("Failed to sql2 insert record into target DB:", err)
 		return err
 	}
 

+ 123 - 0
internal/module/capture/capture_log.go

@@ -0,0 +1,123 @@
+package capture
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"time"
+
+	"github.com/sirupsen/logrus"
+)
+
+var Logger *logrus.Logger
+
+// Hook 结构体定义了一个日志钩子,用于将日志条目输出到指定的 Writer,并使用指定的 Formatter 格式化日志条目。
+// Level 字段是一个包含日志级别的切片,用于指定该钩子应处理的日志级别。
+type Hook struct {
+	Writer    io.Writer
+	Formatter logrus.Formatter
+	Level     []logrus.Level
+}
+
+// Fire 方法是 logrus.Hook 接口的实现。当日志条目符合钩子的日志级别时,
+// 这个方法会被调用。它首先使用 Formatter 将日志条目格式化为字节切片,
+// 然后将其写入 Writer。此版本增强了日志条目,添加了错误发生的文件名和行号。
+func (h *Hook) Fire(entry *logrus.Entry) error {
+	// 获取错误发生的文件名和行号
+	if entry.HasCaller() {
+		entry.Data["file"] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
+	}
+
+	line, err := h.Formatter.Format(entry)
+	if err != nil {
+		return err
+	}
+	h.Writer.Write(line)
+	return nil
+}
+
+// Levels 方法返回该钩子支持的日志级别切片。
+// logrus 在写入日志时会调用这个方法来决定是否使用这个钩子。
+func (h *Hook) Levels() []logrus.Level {
+	return h.Level
+}
+
+// newHook 函数用于创建一个新的 Hook 实例。它接收一个 Writer,
+// 一个 Formatter 和一个最低的日志级别 level 作为参数。
+// 函数会为低于或等于指定级别的所有日志级别创建一个 Hook,
+// 并返回该 Hook 实例。
+func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *Hook {
+	var levels []logrus.Level
+	for _, l := range logrus.AllLevels {
+		if l <= level {
+			levels = append(levels, l)
+		}
+	}
+	return &Hook{
+		Writer:    writer,
+		Formatter: formatter,
+		Level:     levels,
+	}
+}
+
+// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录(默认为 ./logs/)。
+// 如果目录不存在,它会创建该目录。
+func InitLogs(logFilePath string, logLevelStr string) *logrus.Logger {
+	//dir := "./logs/"
+	// 检查目录是否存在
+	if _, err := os.Stat(logFilePath); os.IsNotExist(err) {
+		// 目录不存在,创建目录
+		err := os.MkdirAll(logFilePath, os.ModePerm)
+		if err != nil {
+			fmt.Println("Error creating directory:", err)
+			return nil
+		}
+		fmt.Println("Directory created:", logFilePath)
+	}
+
+	// 尝试将 logLevelStr 转换为 logrus.Level。如果转换失败,则默认使用 InfoLevel 级别。
+	logLevel, err := logrus.ParseLevel(logLevelStr)
+	if err != nil {
+		logLevel = logrus.InfoLevel
+		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr)
+	}
+
+	// 初始化 Logger 实例,并将其输出设置为 io.Discard,即默认情况下不输出任何日志。
+	// 这是为了强制所有日志输出都通过钩子来处理。
+	Logger = logrus.New()
+	Logger.SetOutput(io.Discard)
+
+	// 启用记录调用者信息,这样可以记录错误发生的位置(文件名和行号)。
+	Logger.SetReportCaller(true)
+
+	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD.log`
+	currentDate := time.Now().Format("2006-01-02")
+	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
+
+	// 打开或创建日志文件。日志文件的路径由 logFilePath 参数指定。
+	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	if err != nil {
+		log.Printf("Failed to open log file: %s", logFileName)
+		panic(err)
+	}
+
+	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化。
+	Logger.AddHook(newHook(
+		logFile,
+		&logrus.JSONFormatter{},
+		logLevel,
+	))
+
+	// 添加另一个 Hook,将日志输出到标准错误输出(通常是控制台),
+	// 并使用 TextFormatter 格式化日志,显示完整时间戳并强制使用颜色。
+	Logger.AddHook(newHook(
+		os.Stderr,
+		&logrus.TextFormatter{
+			FullTimestamp: true,
+			ForceColors:   true,
+		},
+		logLevel,
+	))
+	return Logger
+}

+ 6 - 0
internal/router.go

@@ -79,11 +79,17 @@ func SetupRouter() *gin.Engine {
 		//lincense
 		//protected.GET("/LicenseInfo", controllers.GetLicenseInfo)
 		protected.POST("/distributeLicense", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeOALicenseController)
+		//上传文件的license 弃用
 		protected.GET("/distributeLicenseByUserInfo", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeLicenseByUser)
 		//获取指定license信息
 		protected.GET("/GetSingleSlicenseInfo", middlewares.PermissionMiddleware(middlewares.ReadLicense), controllers.GetSingleLicenseInfoController)
 		//获取全部license信息 new
 		protected.GET("/GetAllLicenseInfo", middlewares.PermissionMiddleware(middlewares.ReadLicense), controllers.GetAllLicenseInfoController)
+		//主动抓取一次oalicense到支撑库
+		protected.GET("/GetCaptureLicenseOnce", middlewares.PermissionMiddleware(middlewares.CaptureLicenseOnceToDb), controllers.CaptureLicenseOnceToDb)
+		//搜索license
+		protected.GET("/GetSearchLicInfoToDb", middlewares.PermissionMiddleware(middlewares.ReadLicense), controllers.SearchLicInfoToDb)
+
 		//生成license new
 		protected.POST("/GenerateLicense", middlewares.PermissionMiddleware(middlewares.GenerateLicense), controllers.GenerateOALicenseStrController)
 

+ 83 - 20
static/license_info/license_info - 副本.html → static/license_info/license_info copy 2.html

@@ -1062,6 +1062,7 @@ tr:last-child td:last-child {
     </div>
     <table id="users-table">
         <thead>
+        
             <tr>
                 <th>用户名</th>
                 <th>电话</th>
@@ -1266,9 +1267,11 @@ tr:last-child td:last-child {
 <script>
         let currentPage = 1;
         let pageSize = 10;
-        let LisOffset = 0;
+        let LisOffset = 1;
         let totalPages = 0; // 存储总页数
         let selectedPage =1;
+        let nextPage =1;
+        let prevPage = 10;
         const token = localStorage.getItem('Authorization');
         let selectedRowData = null;
         let isAscending = true;
@@ -1313,7 +1316,8 @@ function fetchApplications(page, size) {
         tableHead.innerHTML = `
             <th></th> <!-- 添加一个空的表头用于放置下拉按钮 -->
             <th>创建人</th>
-            <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>
+            <th>申请日期 </th> 
+               <!--   <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>-->
             <th>关联项目</th>
             <th>销售人员</th>
             <th>技服人员</th>
@@ -1467,19 +1471,42 @@ function fetchApplications(page, size) {
             // });
             row.addEventListener('click', (event) => {
     if (!event.target.closest('button')) { // 如果点击的不是按钮
+        // const isExpanded = detailCell.style.display === 'table-cell';
+        // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+        // row.classList.toggle('expanded-row', !isExpanded);
+        // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
+        if (!event.target.closest('button')) {
         const isExpanded = detailCell.style.display === 'table-cell';
+        
+        // 收回其他行
+        closeAllExpandedRows();
+
+        // 展开/收起当前行
         detailCell.style.display = isExpanded ? 'none' : 'table-cell';
         row.classList.toggle('expanded-row', !isExpanded);
-        dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+        dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
+    }
     }
 });
 
 dropdownButton.addEventListener('click', (event) => {
+    // event.stopPropagation(); // 阻止事件冒泡到行点击事件
+    // const isExpanded = detailCell.style.display === 'table-cell';
+    // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+    // row.classList.toggle('expanded-row', !isExpanded);
+    // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
     event.stopPropagation(); // 阻止事件冒泡到行点击事件
     const isExpanded = detailCell.style.display === 'table-cell';
+    
+    // 收回其他行
+    closeAllExpandedRows();
+
+    // 展开/收起当前行
     detailCell.style.display = isExpanded ? 'none' : 'table-cell';
     row.classList.toggle('expanded-row', !isExpanded);
-    dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+    dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
 });
 
         });
@@ -1512,6 +1539,9 @@ dropdownButton.addEventListener('click', (event) => {
     });
 }
 
+let currentOffset = 1;
+const itemsPerPage = 10;
+
 // 添加页数选择框的事件监听器
 document.getElementById('page-selector').addEventListener('change', (event) => {
      selectedPage = parseInt(event.target.value, 10);
@@ -1521,6 +1551,8 @@ document.getElementById('page-selector').addEventListener('change', (event) => {
     LisOffset = selectedPage
     pageSize = LisOffset* 10; 
     currentPage = selectedPage 
+    currentOffset = startRecord
+    endOffset = endRecord
     fetchApplications(startRecord, endRecord);
 });
 
@@ -1529,19 +1561,27 @@ document.getElementById('prev-page').addEventListener('click', () => {
     if (currentPage > 1) {
         currentPage--;
         selectedPage--
-        LisOffset -= pageSize-LisOffset;
-        pageSize -= 10; // 减少一页时也减小 pageSize,规则可自定义
-        fetchApplications(LisOffset, pageSize);
+    
+        currentOffset -= itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
     }
 });
 
+
 document.getElementById('next-page').addEventListener('click', () => {
     if (currentPage < totalPages) {
         currentPage++
         selectedPage++
         LisOffset += pageSize-LisOffset;
         pageSize += 10; // 增加页数时,增加 pageSize,规则可自定义
-        fetchApplications(LisOffset, pageSize);
+
+  
+        currentOffset += itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
     }
 });
 
@@ -1564,6 +1604,24 @@ fetchApplications(LisOffset,pageSize);
 // }
 
 
+// 关闭所有已经展开的行
+function closeAllExpandedRows() {
+    const allExpandedRows = document.querySelectorAll('.expanded-row');
+    allExpandedRows.forEach(expandedRow => {
+        const detailCell = expandedRow.nextElementSibling.querySelector('td');
+        if (detailCell && detailCell.style.display === 'table-cell') {
+            detailCell.style.display = 'none';
+            expandedRow.classList.remove('expanded-row');
+            const dropdownButton = expandedRow.querySelector('.arrow-icon');
+            if (dropdownButton) {
+                dropdownButton.classList.remove('rotate-arrow');
+            }
+        }
+    });
+}
+
+
+
 
 // 创建带省略号的文本,并在鼠标悬停时显示完整内容
 function createEllipsisText(text) {
@@ -1604,7 +1662,10 @@ function generateLicense(id, isParentRow) {
     .then(data => {
         if (data.success) {
             alert('License生成成功!');
-            fetchApplications(LisOffset, pageSize);
+            const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+        //    fetchApplications(LisOffset, pageSize);
         } else {
             alert('License生成失败:' + data.error);
         }
@@ -2060,7 +2121,10 @@ function confirmDeleteUser(uniqueID) {
                 if (response.ok) {
                     alert('删除成功');
                     closeModal('confirmDeleteModal');
-                    fetchApplications(LisOffset, pageSize);
+                  //  fetchApplications(LisOffset, pageSize);
+                  const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
                 } else {
                     alert('删除失败');
                 }
@@ -2314,7 +2378,10 @@ function saveLicenseChanges() {
     .then(data => {
         if (data.success) {
             alert('License信息更新成功!');
-            fetchApplications(LisOffset, pageSize);
+          //  fetchApplications(LisOffset, pageSize);
+          const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
             closeModal('modifyLicenseModal');
         } else {
             alert('License信息更新失败:' + data.error);
@@ -3324,6 +3391,7 @@ function toggleUserInfo() {
             }
 
             userInfoContent.innerHTML = `
+               <h2> 个人信息</h2>
     <div class="apple-modal-content">
         <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p>
         <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p>
@@ -3432,14 +3500,6 @@ function toggleSidebar() {
 
 
 
-// document.getElementById('prev-page').addEventListener('click', () => {
-//             if (currentPage > 1) {
-//                 fetchApplications(currentPage - 1, pageSize);
-//             }
-//         });
-//  document.getElementById('next-page').addEventListener('click', () => {
-//             fetchApplications(currentPage + 1, pageSize);
-//         });
 
  function fetchUsername() {
     fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
@@ -3457,7 +3517,10 @@ function toggleSidebar() {
         // 使用获取到的角色,调用获取权限的接口
         fetchPermissionsByRole(currentUserRole)
             .then(() => {
-                fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                //fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
                 // 检查用户是否有 upload_license 权限
                 const hasUploadLicensePermission = userPermissions.includes('upload_license');
 

+ 3655 - 0
static/license_info/license_info copy 3.html

@@ -0,0 +1,3655 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>License 分发管理</title>
+    <style>
+        /* 保持样式不变 */
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+            background-color: #f8f8f8;
+            margin: 0;
+            padding: 0;
+            display: flex;
+        }
+        header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 20px;
+    background-color: #1169ff;
+    color: white;
+    width: 100%;
+    margin: 0; /* 移除上下左右的空隙 */
+    box-sizing: border-box; /* 确保padding不会影响元素的宽度 */
+    border: 4px solid #1169ff; /* 确保红框颜色填满 */
+    border-width: 4px 0 4px 0; /* 只显示上下的红框颜色 */
+    border-radius: 10px; /* 设置圆角 */
+  
+}
+
+h1 {
+            font-size: 24px;
+            font-weight: 600;
+            margin: 0;
+        }
+      
+/* 扁平风格的选择框 */
+.flat-select {
+    background-color: transparent; /* 背景色透明 */
+    border: 1px solid #007aff; /* 边框颜色与按钮一致 */
+    border-radius: 15px; /* 圆角边框 */
+    padding: 5px 10px; /* 内边距 */
+    font-size: 16px; /* 字体大小 */
+    color: #007aff; /* 文字颜色 */
+    outline: none; /* 移除默认的焦点样式 */
+    appearance: none; /* 移除默认的下拉箭头样式 */
+    -webkit-appearance: none; /* 对部分浏览器的兼容性处理 */
+    -moz-appearance: none; /* 对部分浏览器的兼容性处理 */
+    cursor: pointer; /* 鼠标指针样式 */
+    margin-left: 10px; /* 添加左边距,使选择框与前面的元素有些距离 */
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */
+}
+
+/* 选择框在悬停时的效果 */
+.flat-select:hover {
+    background-color: #007aff; /* 背景色变为蓝色 */
+    color: white; /* 文字颜色变为白色 */
+}
+
+/* 选择框在聚焦时的效果 */
+.flat-select:focus {
+    background-color: #e0f7ff; /* 聚焦时的背景颜色 */
+    border-color: #0056b3; /* 聚焦时的边框颜色 */
+}
+
+/* 添加下拉箭头的样式 */
+.flat-select::after {
+    content: '▼'; /* 使用字符作为下拉箭头 */
+    position: absolute;
+    right: 10px;
+    pointer-events: none; /* 确保下拉箭头不会遮挡选择框 */
+}
+
+
+/* 扁平圆角风格的按钮样式 */
+.flat-rounded-button {
+    background-color: white;
+    color: #007aff;
+    border: 2px solid #007aff;
+    padding: 10px 20px;
+    border-radius: 15px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s;
+    margin: 5px; /* 添加按钮之间的间距 */
+}
+
+/* 悬停时的效果 */
+.flat-rounded-button:hover {
+    background-color: #0eb3ff;
+    color: white;
+}
+
+/*lic 展示页 主行展开后变化*/
+.expanded-row {
+    background-color: #0eb3ff; /* 展开时的背景颜色 */
+    border-color: #04aa9c; /* 展开时的边框颜色 */
+    border-width: 4px; /* 边框宽度 */
+    border-radius: 35px; /* 边框圆角 */
+    transition: all 0.2s ease; /* 添加过渡效果 */
+}
+
+/*苹果风格模态框*/
+.apple-modal-content {
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+    padding: 20px;
+    border-radius: 12px;
+    background-color: white;
+    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+    margin-bottom: 20px;
+}
+
+.apple-modal-title {
+    font-size: 24px;
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 10px;
+}
+
+.apple-modal-subtitle {
+    font-size: 20px;
+    font-weight: 500;
+    color: #555;
+    margin-top: 20px;
+    margin-bottom: 10px;
+}
+/* 苹果风格的文字样式 */
+.apple-modal-text {
+    font-size: 16px;
+    color: #555;
+    line-height: 1.6;
+    margin-bottom: 10px;
+    
+}
+
+/* 强调部分 */
+.apple-modal-text strong {
+    color: #333;
+}
+
+/* 苹果风格的模态框关闭按钮 */
+
+.apple-close {
+    color: #aaa;
+    font-size: 24px; /* 调整字体大小 */
+    font-weight: bold;
+    cursor: pointer;
+    transition: color 0.3s;
+}
+
+.apple-close:hover {
+    color: black;
+}
+
+/* 苹果风格的退出按钮 */
+.apple-logout-button {
+    background-color: #007aff; /* 苹果风格的蓝色 */
+    color: white;
+    border: none;
+    padding: 8px 16px; /* 减小内边距,使按钮更小 */
+    border-radius: 10px; /* 圆角稍微减小 */
+    font-size: 14px; /* 调整字体大小 */
+    font-weight: 500;
+    cursor: pointer;
+    transition: background-color 0.3s, transform 0.3s;
+}
+
+.apple-logout-button:hover {
+    background-color: #005bb5; /* 悬停时按钮颜色变深 */
+    transform: scale(1.05); /* 悬停时按钮略微放大 */
+}
+
+.apple-logout-button:active {
+    background-color: #003e7e; /* 点击时按钮颜色更深 */
+    transform: scale(0.98); /* 点击时按钮略微缩小 */
+}
+
+
+.upload-button, .user-button {
+            background-color: white;
+            color: #007aff;
+            border: none;
+            padding: 10px 20px;
+            border-radius: 10px;
+            cursor: pointer;
+            font-size: 16px;
+            font-weight: 500;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            transition: background-color 0.3s;
+        }
+ .upload-button:hover, .user-button:hover {
+            background-color: #f0f0f0;
+        }
+        .sidebar {
+            width: 200px;
+            background-color: #f1f1f1;
+            padding: 20px;
+            box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
+            height: 100vh;
+            transition: transform 0.3s ease;
+        }
+        .sidebar.hidden {
+            transform: translateX(-100%);
+        }
+        .sidebar button {
+            width: 100%;
+            padding: 10px;
+            margin-bottom: 10px;
+            background-color: white;
+            color: #007aff;
+            border: none;
+            border-radius: 10px;
+            cursor: pointer;
+            font-size: 16px;
+            font-weight: 500;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            transition: background-color 0.3s;
+        }
+        .sidebar button:hover {
+            background-color: #e0e0e0;
+        }
+        .content {
+            flex-grow: 1;
+            padding: 20px;
+            transition: margin-left 0.3s ease;
+        }
+        .content.expanded {
+            margin-left: -200px;
+        }
+        .toggle-sidebar {
+    position: fixed;
+    top: 50%; /* 垂直居中 */
+    transform: translateY(-50%); /* 调整为居中对齐 */
+    left: 0; /* 靠左对齐 */
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 10px;
+    cursor: pointer;
+    border-radius: 0 10px 10px 0; /* 右侧圆角,左侧保持平直 */
+    width: 30px; /* 长条形箭头的宽度 */
+    height: 60px; /* 长条形箭头的高度 */
+    z-index: 1000;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.3s ease; /* 添加动效 */
+}
+
+.sidebar.hidden + .content .toggle-sidebar {
+            left: 0;
+            transform: translateX(0) translateY(-50%);
+        }
+
+
+ /* 通用按钮样式 */
+.license-status-btn {
+    display: inline-block;
+    padding: 5px 15px;
+    font-size: 14px;
+    font-weight: bold;
+    color: white;
+    text-align: center;
+    border-radius: 15px; /* 圆角样式 */
+    cursor: pointer;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+    transition: background-color 0.3s;
+    border: none; /* 移除按钮边框 */
+}
+
+/* 分发按钮样式 */
+.license-status-btn.distribute {
+    background-color: #007bff; /* 蓝色背景 */
+}
+
+.license-status-btn.distribute:hover {
+    background-color: #0056b3; /* 悬停时的颜色 */
+}
+
+/* 生成按钮样式 */
+.license-status-btn.generate {
+    background-color: #ffc107; /* 黄色背景 */
+}
+
+.license-status-btn.generate:hover {
+    background-color: #e0a800; /* 悬停时的颜色 */
+}
+
+/* 默认状态下的箭头图标 */
+.arrow-icon {
+    width: 10px;
+    height: 10px;
+    border: solid #007aff;
+    border-width: 0 3px 3px 0;
+    display: inline-block;
+    padding: 3px;
+    transform: rotate(45deg); /* 初始方向向下 */
+    transition: transform 0.3s ease; /* 添加旋转过渡效果 */
+    cursor: pointer;
+}
+
+/* 当行展开时旋转箭头图标 */
+.rotate-arrow {
+    transform: rotate(-135deg); /* 旋转方向向上 */
+}
+
+
+
+/*分发历史样式*/
+#distributionHistoryModal .centered-modal-content {
+    background-color: #ffffff;
+    border: none;
+    border-radius: 15px;
+    padding: 20px;
+    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+    text-align: center;
+    width: 30%;  /* 设置宽度为屏幕的80% */
+    max-width: 90%;  /* 最大宽度设置为90%屏幕宽度 */
+    height: auto;  /* 高度自适应内容 */
+    max-height: 80vh;  /* 设置最大高度为屏幕的80% */
+    overflow-y: auto;  /* 如果内容超出则添加垂直滚动条 */
+    overflow-x: hidden;  /* 水平不出现滚动条 */
+    margin: 0 auto;  /* 居中显示 */
+}
+
+/* lic查看详细按钮样式 */
+.license-status-btn.view-details {
+    background-color: #add8e6; /* 浅蓝色背景 */
+    color: white; /* 白色文字 */
+    border: none; /* 移除按钮边框 */
+    padding: 8px 16px; /* 调整内边距,与“生成”按钮保持一致 */
+    border-radius: 20px; /* 调整圆角,确保形状一致 */
+    cursor: pointer;
+    font-size: 14px; /* 调整字体大小,确保一致 */
+    font-weight: 500; /* 字体权重,确保一致 */
+    margin-left: 10px; /* 与其他按钮的间隔 */
+    transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */
+}
+
+.license-status-btn.view-details:hover {
+    background-color: #87ceeb; /* 悬停时颜色变深 */
+}
+
+
+
+
+/* 表格样式 */
+/* 表格容器 */
+/* 表格容器 */
+
+table {
+    width: 100%;
+    border-collapse: separate;
+    border-spacing: 0 4px; /* 设置行间距为4px */
+   /*  background-color: transparent; 使表格背景透明,突出行间距效果 */
+    margin: 20px 0;
+}
+
+th, td {
+    padding: 15px 20px; /* 设置单元格内边距 */
+    text-align: left;
+    font-size: 16px;
+  /*   background-color: white; 单元格背景色 */
+   
+}
+
+
+/* 鼠标悬停时改变边框颜色 */
+tr:hover {
+    background-color: #e6f7ff; /* 设置悬停时的背景颜色 */
+    border-color: #1169ff; /* 设置悬停时的边框颜色 */
+    border-width: 4px; /* 设置悬停时的边框大小 */
+    border-radius: 15px; /* 设置悬停时的圆角 */
+}
+th {
+    background-color: #f8f8f8; /* 表头背景色 */
+    font-weight: bold;
+    color: #333;
+}
+
+td {
+    color: #555;
+}
+
+/* 表格行样式 */
+tr {
+    background-color: white; /* 每行背景色 */
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 设置阴影效果 */
+    border-radius: 10px; /* 设置每行的圆角 */
+    overflow: hidden; /* 确保圆角效果生效 */
+    border: 2px solid transparent; /* 默认边框为透明 */
+    transition: all 0.3s ease; /* 添加过渡效果 */
+    
+}
+/* 确保单元格也适应行的圆角 */
+tr:first-child td:first-child {
+    border-top-left-radius: 10px;
+}
+tr:first-child td:last-child {
+    border-top-right-radius: 10px;
+}
+tr:last-child td:first-child {
+    border-bottom-left-radius: 10px;
+}
+tr:last-child td:last-child {
+    border-bottom-right-radius: 10px;
+}
+
+
+
+
+
+/*添加用户样式*/
+.flat-rounded-input {
+    width: calc(100% - 40px); /* 与其他输入框一致的宽度 */
+    padding: 15px 20px;  /* 更大的内边距 */
+    font-size: 18px;  /* 更大的字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆角边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+.flat-rounded-input:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+.flat-rounded-button {
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 15px 20px;
+    border-radius: 25px;
+    cursor: pointer;
+    font-size: 18px;
+    font-weight: bold;
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s;
+}
+
+.flat-rounded-button:hover {
+    background-color: #005bb5;
+}
+.form-group {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+}
+
+.form-group label {
+    flex: 0 0 80px; /* 固定标签宽度 */
+    text-align: right;
+    margin-right: 10px; /* 标签与输入框之间的间距 */
+}
+
+.form-group input {
+    flex: 1; /* 输入框占据剩余空间 */
+}
+
+
+
+/* 分页按钮样式 */
+.pagination button {
+    padding: 10px 20px;
+    margin: 0 5px;
+    cursor: pointer;
+    border: none;
+    border-radius: 15px;
+    background-color: #007aff;
+    color: white;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: background-color 0.3s;
+}
+
+.pagination button:disabled {
+    background-color: #b0c4de;
+    cursor: not-allowed;
+}
+
+.pagination button:not(:disabled):hover {
+    background-color: #005bb5;
+}
+
+
+
+
+        .modal {
+            display: none;
+            position: fixed;
+            z-index: 1;
+            left: 0;
+            top: 0;
+            width: 100%;
+            height: 100%;
+            overflow: auto;
+            background-color: rgba(0, 0, 0, 0.4);
+        }
+.modal-content {
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background-color: #fefefe;
+            padding: 20px;
+            border: 1px solid #888;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            max-width: 100%;
+            max-height: 90%;
+
+            overflow-y: auto;
+        }
+
+
+/*修改license信息的样式*/
+.modify-license-modal-content {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background-color: #fefefe;
+    padding: 50px;
+    border: 1px solid #888;
+    border-radius: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    width: 400px;
+    height: 80%; /* 设置为你希望的高度 */
+    overflow-y: auto;
+    text-align: center;
+}
+
+.modify-license-modal-content input[type="number"],
+.modify-license-modal-content input[type="date"],
+.modify-license-modal-content input[type="text"],
+.modify-license-modal-content input[type="email"],
+.modify-license-modal-content input[type="password"],
+.modify-license-modal-content textarea,
+.modify-license-modal-content select {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 更大内边距 */
+    font-size: 18px;  /* 更大字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆形边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色更浅 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+.modify-license-modal-content input[type="number"]:focus,
+.modify-license-modal-content input[type="date"]:focus,
+.modify-license-modal-content input[type="text"]:focus,
+.modify-license-modal-content input[type="email"]:focus,
+.modify-license-modal-content input[type="password"]:focus,
+.modify-license-modal-content textarea:focus,
+.modify-license-modal-content select:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+.modify-license-modal-content button {
+    width: 100%;
+    padding: 15px 20px;
+    font-size: 18px;
+    font-weight: bold;
+    color: white;
+    background-color: #007aff;
+    border: none;
+    border-radius: 25px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.modify-license-modal-content button:hover {
+    background-color: #005bb5;  /* 鼠标悬停时的颜色变化 */
+}
+
+.modify-license-modal-content .close {
+    color: #aaa;
+    float: right;
+    font-size: 30px;
+    font-weight: bold;
+}
+
+.modify-license-modal-content .close:hover,
+.modify-license-modal-content .close:focus {
+    color: black;
+    text-decoration: none;
+    cursor: pointer;
+}
+
+.modify-license-modal-content .extra-info {
+    padding: 20px;
+    background-color: white;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    margin-top: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    line-height: 1.5; /* 增加行高,保证字段间距 */
+}
+
+
+
+.modal-content input[type="number"] {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 与其他输入框的内边距一致 */
+    font-size: 18px;  /* 与其他输入框的字体大小一致 */
+    border: 2px solid #e0e0e0;  /* 与其他输入框的边框颜色一致 */
+    border-radius: 25px;  /* 与其他输入框的圆角一致 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 与其他输入框的背景色一致 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 与其他输入框的过渡效果一致 */
+}
+
+.modal-content input[type="number"]:focus {
+    border-color: #007aff;  /* 与其他输入框获得焦点时的边框颜色一致 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 与其他输入框获得焦点时的阴影效果一致 */
+    outline: none;  /* 移除默认的焦点轮廓 */
+}
+
+
+.modal-content input[type="date"] {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 与其他输入框的内边距一致 */
+    font-size: 18px;  /* 与其他输入框的字体大小一致 */
+    border: 2px solid #e0e0e0;  /* 与其他输入框的边框颜色一致 */
+    border-radius: 25px;  /* 与其他输入框的圆角一致 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 与其他输入框的背景色一致 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 与其他输入框的过渡效果一致 */
+}
+
+.modal-content input[type="date"]:focus {
+    border-color: #007aff;  /* 与其他输入框获得焦点时的边框颜色一致 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 与其他输入框获得焦点时的阴影效果一致 */
+    outline: none;  /* 移除默认的焦点轮廓 */
+}
+
+
+        /* 输入框样式 */
+.modal-content input[type="text"],
+.modal-content input[type="email"],
+.modal-content input[type="password"],
+.modal-content textarea,
+.modal-content select {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 更大内边距 */
+    font-size: 18px;  /* 更大字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆形边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色更浅 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+/* 输入框聚焦时的样式 */
+.modal-content input[type="text"]:focus,
+.modal-content input[type="email"]:focus,
+.modal-content input[type="password"]:focus,
+.modal-content textarea:focus,
+.modal-content select:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+
+
+/* 按钮样式 */
+.modal-content button {
+    width: 100%;
+    padding: 15px 20px;
+    font-size: 18px;
+    font-weight: bold;
+    color: white;
+    background-color: #007aff;
+    border: none;
+    border-radius: 25px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.modal-content button:hover {
+    background-color: #005bb5;  /* 鼠标悬停时的颜色变化 */
+}
+
+        .close {
+            color: #aaa;
+            float: right;
+            font-size: 30px;
+            font-weight: bold;
+            text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
+        }
+        .close:hover {
+    color: #000; /* 悬停时颜色变为黑色 */
+    transform: scale(1.1); /* 悬停时稍微放大 */
+}
+
+        .close:focus {
+            color: black;
+            text-decoration: none;
+            cursor: pointer;
+        }
+        .extra-info {
+    padding: 20px;
+    background-color: white;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    margin-top: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    line-height: 1.5; /* 增加行高,保证字段间距 */
+}
+.extra-info p {
+    margin: 10px 0; /* 每个字段的间距 */
+    word-wrap: break-word; /* 允许在单词内断行 */
+    word-break: break-all; /* 允许在任何字符处断行 */
+    white-space: pre-wrap; /* 保持空格和换行符 */
+    border-bottom: 1px solid #f0f0f0; /* 每个字段下方加上细线 */
+    padding-bottom: 8px; /* 加大下方内边距 */
+}
+
+/* 修改运维邮箱和销售邮箱的勾选框样式 */
+#emailInputs {
+    display: flex;
+    flex-direction: column; /* 确保每一行都垂直排列 */
+    gap: 10px; /* 增加每行之间的间距 */
+}
+
+#emailInputs div {
+    display: flex;
+    align-items: center; /* 垂直居中 */
+}
+
+#emailInputs input[type="checkbox"] {
+    appearance: none;
+    background-color: #fff;
+    margin: 0;
+    font: inherit;
+    color: #007aff;
+    width: 1.15em;
+    height: 1.15em;
+    border: 0.15em solid #007aff;
+    border-radius: 0.15em;
+    transform: translateY(-0.075em);
+    display: grid;
+    place-content: center;
+}
+
+#emailInputs input[type="checkbox"]::before {
+    content: "";
+    width: 0.65em;
+    height: 0.65em;
+    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 22%, 80% 0%, 43% 62%);
+    transform: scale(0);
+    transform-origin: bottom left;
+    transition: transform 0.15s ease-in-out;
+    box-shadow: inset 1em 1em #007aff;
+    /* 使用淡蓝色与主题颜色匹配 */
+    background-color: CanvasText;
+}
+
+#emailInputs input[type="checkbox"]:checked::before {
+    transform: scale(1);
+}
+
+
+        .user-info {
+            position: absolute;
+            width: 300px;
+            background-color: white;
+            padding: 20px;
+            border: 1px solid #ddd;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            display: none;
+        }
+        .user-info .close {
+            position: absolute;
+            top: 10px;
+            right: 10px;
+            color: #aaa;
+            font-size: 24px;
+            font-weight: bold;
+            cursor: pointer;
+        }
+        .user-info .close:hover,
+        .user-info .close:focus {
+            color: black;
+            text-decoration: none;
+        }
+        .centered-modal-content {
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background-color: #fefefe;
+            padding: 50px;
+            border: 1px solid #888;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            width: 400px;
+            height: 400px;
+            overflow-y: auto;
+            text-align: center;
+        }
+        .ios-button {
+            width: 100%;
+            padding: 10px;
+            margin: 0;
+            border: none;
+            border-radius: 0;
+            font-size: 16px;
+            font-weight: 600;
+            color: #007aff;
+            background-color: transparent;
+            text-align: center;
+            cursor: pointer;
+            transition: background-color 0.3s;
+        }
+        .ios-button:active {
+            background-color: rgba(0, 122, 255, 0.1);
+        }
+        .email-modal-label {
+            font-size: 18px;
+            margin-bottom: 10px;
+            display: block;
+        }
+        .email-modal-input {
+            width: calc(100% - 20px);
+            padding: 10px;
+            font-size: 16px;
+            border: 1px solid #ccc;
+            border-radius: 5px;
+            margin-bottom: 10px;
+        }
+        .email-modal .modal-content {
+    width: 90%; /* 修改宽度 */
+    max-width: 600px; /* 最大宽度 */
+    height: auto; /* 自适应高度 */
+    max-height: 80%; /* 最大高度,防止内容溢出屏幕 */
+    overflow-y: auto; /* 添加垂直滚动条,如果内容超出 */
+}
+
+
+        .add-email-button {
+            display: block;
+            width: 100%;
+            padding: 10px 20px;
+            margin-bottom: 10px;
+            background-color: #007aff;
+            color: white;
+            border: none;
+            text-align: center;
+            font-size: 16px;
+            cursor: pointer;
+            border-radius: 5px;
+            transition: background-color 0.3s;
+        }
+        .add-email-button:hover {
+            background-color: #005bb5;
+        }
+        .action-modal-content {
+            display: flex;
+            flex-direction: column;
+            align-items: flex-start;
+        }
+        .action-modal-content button {
+            width: auto;
+            padding: 10px 20px;
+            margin: 5px 0;
+            background-color: white;
+            color: black;
+            border: none;
+            text-align: left;
+            font-size: 16px;
+            cursor: pointer;
+            border-radius: 5px;
+            transition: background-color 0.3s;
+        }
+        .action-modal-content button:hover {
+            background-color: #f0f0f0;
+        }
+        .sort-button {
+            background-color: transparent;
+            border: none;
+            color: #007aff;
+            font-size: 16px;
+            cursor: pointer;
+            padding: 5px 10px;
+            border-radius: 15px;
+            transition: background-color 0.3s;
+        }
+        .sort-button:hover {
+            background-color: rgba(0, 122, 255, 0.1);
+        }
+        #confirmGenerateModal .centered-modal-content {
+            background-color: #ffffff;
+            border: none;
+            border-radius: 15px;
+            padding: 20px;
+            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+            text-align: center;
+        }
+        #confirmGenerateModal .centered-modal-content button {
+            background-color: #007aff;
+            color: white;
+            border: none;
+            border-radius: 10px;
+            padding: 10px 20px;
+            cursor: pointer;
+            font-size: 16px;
+            margin: 10px;
+            transition: all 0.3s;
+        }
+        #confirmGenerateModal .centered-modal-content button:hover {
+            background-color: #005bb5;
+            border: 1px solid #007aff;
+        }
+
+        #role-management {
+    padding: 20px;
+    background-color: white;
+    border-radius: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 角色项的默认样式 */
+.role-item {
+    background-color: white; /* 默认背景色 */
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+    border-radius: 10px; /* 圆角效果 */
+    overflow: hidden; /* 确保圆角效果生效 */
+    border: 2px solid transparent; /* 默认边框为透明 */
+    transition: all 0.3s ease; /* 过渡效果 */
+    margin-bottom: 20px; /* 每个角色之间的间距 */
+    padding: 10px; /* 内边距 */
+}
+
+/* 置顶角色的样式 */
+.role-item.top-role {
+    background-color: #d3d3d3; /* 灰色背景 */
+}
+
+/* 鼠标悬停时的样式 */
+.role-item:hover {
+    background-color: #e6f7ff; /* 悬停时背景色 */
+    border-color: #1169ff; /* 悬停时边框颜色 */
+    border-width: 4px; /* 悬停时边框大小 */
+    border-radius: 15px; /* 悬停时的圆角 */
+}
+
+/* 置顶角色在悬停时的样式 */
+.role-item.top-role:hover {
+    background-color: #d3d3d3; /* 保持灰色背景不变 */
+    border-color: #1169ff; /* 悬停时边框颜色 */
+    border-width: 4px; /* 悬停时边框大小 */
+    border-radius: 15px; /* 悬停时的圆角 */
+}
+
+
+.role-item h3 {
+    margin-top: 0;
+}
+
+.role-item ul {
+    padding-left: 20px;
+}
+
+.create-role-button {
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 10px 20px;
+    border-radius: 10px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: background-color 0.3s;
+    margin-left: 20px; /* 与标题之间的间距 */
+}
+.create-role-button:hover {
+    background-color: #005bb5;
+}
+
+    </style>
+</head>
+<body>
+    <div class="sidebar" id="sidebar">
+        <button onclick="showTable()">License 管理</button>
+        <button onclick="showUserManagement()">用户管理</button>
+        <button onclick="showRoleManagement()">角色管理</button>
+    </div>
+    <div class="content" id="content">
+        <button class="toggle-sidebar" onclick="toggleSidebar()">←</button>
+        <header>
+            <h1>License 管理平台</h1>
+            <div>
+             <!--   <button class="upload-button" onclick="window.location.href='/static/upload_xlsx/index.html'" style="display: none;">Upload File</button> --> <!-- 默认隐藏 -->
+                <button class="user-button" onclick="toggleUserInfo()" id="username">User</button>
+            </div>
+            
+        </header>
+        <div id="table-container">
+            <table id="applications-table">
+                <thead>
+                    <tr>
+                        <th>创建人</th>
+                        <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>
+                        <th>关联项目</th>
+                        <th>销售人员</th>
+                        <th>技服人员</th>
+                        <th>总节点数</th>
+                        <th>使用单位</th>
+                        <th>产品名称</th>
+                        <th>版本</th>
+                        <th>节点数</th>
+                        <th>License状态</th>
+                    </tr>
+                </thead>
+                <tbody>
+                </tbody>
+            </table>
+            <div class="pagination">
+                <button id="prev-page">上一页</button>
+                <button id="next-page">下一页</button>
+                <select id="page-selector" class="flat-select"></select>
+                <span id="pagination-info">第 1 页,共 0 页</span> <!-- 新增信息显示区域 -->
+             
+            </div>
+        </div>
+<!-- License 详细信息的模态框 -->
+<div id="detailsModal" class="modal">
+    <div class="modal-content">
+        <span class="close" onclick="closeModal('detailsModal')">&times;</span>
+        <h3>License 详细信息</h3>
+        <div id="detailsContent"></div>
+        <button class="close-button" onclick="closeModal('detailsModal')">关闭</button>
+    </div>
+</div>
+
+
+ <!-- 用户管理的添加用户 -->
+<div id="user-management" style="display: none;">
+    <div style="display: flex; align-items: center; justify-content: space-between;">
+        <h2>用户管理</h2>
+        <button id="addUserButton" class="create-role-button" style="display: none;">添加用户</button> <!-- 默认隐藏 -->
+    </div>
+    <table id="users-table">
+        <thead>
+        
+            <tr>
+                <th>用户名</th>
+                <th>电话</th>
+                <th>邮箱</th>
+                <th>权限</th>
+                <th>账号</th>
+            </tr>
+        </thead>
+        <tbody>
+        </tbody>
+    </table>
+</div>
+
+        
+            <!-- 新增的角色管理容器 -->
+    <div id="role-management" style="display: none;">
+        <div style="display: flex; align-items: center; justify-content: space-between;">
+            <h2>角色管理</h2>
+            <button id="createRoleButton" class="create-role-button">创建角色</button>
+        </div>
+        <div id="roles-container"></div>
+    </div>
+    </div>
+
+    <!-- License 管理的弹出菜单 -->
+    <div id="licenseActionModal" class="modal">
+        <div class="modal-content action-modal-content" id="licenseActionModalContent">
+            <span class="close" onclick="closeModal('licenseActionModal')">&times;</span>
+            <!-- <button onclick="showExtraInfo()">查看额外信息</button>
+            <button onclick="modifyLicenseInfo()">修改信息</button> 新增的修改信息按钮 -->
+            <!-- <button onclick="showDistributionHistory()">分发历史</button>
+            <button onclick="confirmDelete()">删除</button> -->
+        </div>
+    </div>
+
+<!-- 修改信息的表单框 -->
+<div id="modifyLicenseModal" class="modal">
+    <div class="modify-license-modal-content">
+        <span class="close" onclick="closeModal('modifyLicenseModal')">&times;</span>
+        <h3>修改License信息</h3>
+        <form id="modifyLicenseForm">
+            <label for="creator">创建人:</label>
+            <input type="text" id="creator" name="creator" required><br><br>
+
+            <label for="applicationDate">申请日期:</label>
+            <input type="date" id="applicationDate" name="applicationDate" class="form-control" required><br><br>
+            
+
+            <label for="associatedProject">关联项目:</label>
+            <input type="text" id="associatedProject" name="associatedProject" required><br><br>
+
+            <label for="salesPerson">销售人员:</label>
+            <input type="text" id="salesPerson" name="salesPerson" required><br><br>
+
+            <label for="salesEmail">销售邮箱:</label>
+            <input type="email" id="salesEmail" name="salesEmail" required><br><br>
+
+            <label for="supportPerson">技服人员:</label>
+            <input type="text" id="supportPerson" name="supportPerson" required><br><br>
+
+            <label for="supportEmail">技服邮箱:</label>
+            <input type="email" id="supportEmail" name="supportEmail" required><br><br>
+
+            <label for="totalNodes">总节点数:</label>
+            <input type="number" id="totalNodes" name="totalNodes" class="form-control" required><br><br>
+
+            <label for="company">使用单位:</label>
+            <input type="text" id="company" name="company" required><br><br>
+
+            <label for="productName">产品名称:</label>
+            <input type="text" id="productName" name="productName" required><br><br>
+
+            <label for="version"> 数据库版本: </label>
+            <input type="text" id="version" name="version" required><br><br>
+
+            <label for="nodeCount">节点数:</label>
+            <input type="number" id="nodeCount" name="nodeCount" class="form-control" required><br><br>
+
+            <button type="button" onclick="saveLicenseChanges()">保存</button>
+        </form>
+    </div>
+</div>
+
+
+
+    <!-- 用户管理的弹出菜单 -->
+    <div id="userActionModal" class="modal">
+        <div class="modal-content action-modal-content" id="userActionModalContent">
+            <span class="close" onclick="closeModal('userActionModal')">&times;</span>
+            <button onclick="showMoreUserInfo()">更多用户信息</button>
+            <button onclick="showUserLicenseHistory()">查看license分发记录</button>
+            <button onclick="modifyUser()">修改用户</button>
+        </div>
+    </div>
+
+<!-- 用户管理的添加用户 -->
+<div id="addUserModal" class="modal">
+    <div class="centered-modal-content" style="height: 50vh; overflow-y: auto;">
+        <span class="close" onclick="closeModal('addUserModal')">&times;</span>
+        <h3>添加用户</h3>
+        <form id="addUserForm">
+            <div class="form-group">
+                <label for="addUsername">用户名:</label>
+                <input type="text" id="addUsername" name="username" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addPassword">密码:</label>
+                <input type="password" id="addPassword" name="password" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addAccount">账号:</label>
+                <input type="text" id="addAccount" name="account" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addTelephone">电话:</label>
+                <input type="text" id="addTelephone" name="telephone" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addEmail">邮箱:</label>
+                <input type="email" id="addEmail" name="email" class="flat-rounded-input" required>
+            </div>
+
+            <button type="button" onclick="saveNewUser()" class="flat-rounded-button">保存</button>
+        </form>
+    </div>
+</div>
+
+
+    
+
+    <!-- 邮箱和用户选择弹出框 -->
+    <div id="emailModal" class="modal">
+        <div class="modal-content centered-modal-content" style="height: 45vh; overflow-y: auto;">
+            <span class="close" onclick="closeModal('emailModal')">&times;</span>
+    
+            <!-- 邮箱输入部分 -->
+            <label for="emailInput1" class="email-modal-label">选中要发送的邮箱:</label>
+            <div id="emailInputs">
+                <input type="text" id="emailInput1" class="email-modal-input">
+            </div>
+            <br>
+            <button onclick="addEmailInput()" class="add-email-button">添加邮箱</button>
+    
+            <!-- 用户选择部分 -->
+            <label for="userSelect1" class="email-modal-label">选择要分发的用户:</label>
+            <div id="userInputs"></div>
+            <button onclick="addUserInput()" class="add-email-button">添加用户</button>
+    
+            <!-- 发送按钮 -->
+            <button onclick="sendEmail()" class="ios-button">发送</button>
+        </div>
+    </div>
+    
+    
+    <!-- 其他模态框不变 -->
+    <div id="extraInfoModal" class="modal">
+        <div class="modal-content">
+            <span class="close" onclick="closeModal('extraInfoModal')">&times;</span>
+            <div id="extraInfoContent" class="extra-info"></div>
+        </div>
+    </div>
+
+    <div id="userModal" class="user-info">
+        <span class="close apple-close" onclick="closeUserInfo()">&times;</span> <!-- 关闭按钮 -->
+        <div id="userInfoContent"></div>
+        <br>
+        <button class="apple-logout-button" onclick="logout()">退出</button>
+    </div>
+    
+
+        <!-- license删除模态框-->
+    <div id="confirmDeleteModal" class="modal">
+        <div class="centered-modal-content">
+            <span class="close" onclick="closeModal('confirmDeleteModal')">&times;</span>
+            
+        </div>
+    </div>
+    
+    
+
+    <div id="confirmGenerateModal" class="modal">
+        <div class="centered-modal-content" style="height: 15vh; overflow-y: auto;">
+            <span class="close" onclick="closeModal('confirmGenerateModal')">&times;</span>
+            <p>确认生成License吗?</p>
+            <button id="confirm-generate-button">确认</button>
+            <button onclick="closeModal('confirmGenerateModal')">取消</button>
+        </div>
+    </div>
+
+    <div id="distributionHistoryModal" class="modal">
+        <div class="centered-modal-content">
+            <span class="close" onclick="closeModal('distributionHistoryModal')">&times;</span>
+            <h3>分发历史</h3>
+            <div id="distributionHistoryContent" class="extra-info"></div>
+        </div>
+    </div>
+
+<script>
+        let currentPage = 1;
+        let pageSize = 10;
+        let LisOffset = 1;
+        let totalPages = 0; // 存储总页数
+        let selectedPage =1;
+        let nextPage =1;
+        let prevPage = 10;
+        const token = localStorage.getItem('Authorization');
+        let selectedRowData = null;
+        let isAscending = true;
+        let userMap = {}; // 用于存储用户名和用户ID的映射
+        let currentUserRole = ''; // 新增变量存储当前用户的权限
+        let currentUserName = ''; // 新增变量存储当前用户的名字
+        let userPermissions = [];// 全局变量,用于存储用户权限
+        let LicApplicationData = []; // 全局变量存储数据
+        let currentRolePermissions = []; // 这是您获取的当前角色的权限列表
+
+        
+function checkPermission(permission) {
+            console.log(`检查权限: ${permission} - ${hasPermission ? '有权限' : '无权限'}`);
+    return userPermissions.includes(permission);
+}
+
+//获取license展示信息
+function fetchApplications(page, size) {
+    fetch(`http://127.0.0.1:8080/api/admin/GetAllLicenseInfo?page=${page}&pageSize=${size}`, {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        LicApplicationData = data.data; // 将接收到的数据存储到全局变量
+        console.log(data); // 输出获取的数据结构
+
+        const hasGeneratePermission = userPermissions.includes("generate_license");
+        const hasDistributePermission = userPermissions.includes("dispat_license");
+ // 更新总页数
+ //totalPages = Math.ceil(data.total / 10);
+        // 在控制台打印权限结果
+        console.log(`hasGeneratePermission: ${hasGeneratePermission}, hasDistributePermission: ${hasDistributePermission}`);
+        totalPages = Math.ceil(data.total / 10);
+        const tableBody = document.querySelector('#applications-table tbody');
+        const tableHead = document.querySelector('#applications-table thead tr');
+
+        tableBody.innerHTML = '';
+        tableHead.innerHTML = `
+            <th></th> <!-- 添加一个空的表头用于放置下拉按钮 -->
+            <th>创建人</th>
+            <th>申请日期 </th> 
+               <!--   <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>-->
+            <th>关联项目</th>
+            <th>销售人员</th>
+            <th>技服人员</th>
+            <th>总节点数</th>
+            <th>使用单位</th>
+            <th>操作</th> <!-- 新增的表头用于显示操作按钮 -->
+        `;
+
+        data.data.forEach(applicationArray => {
+            const firstApplication = applicationArray[0];
+            let showGenerateButton = false;
+
+            // Check if any child row has LicenseFlage as "未生成"
+            applicationArray.forEach(detail => {
+                if (detail.LicenseFlage === "未生成") {
+                    showGenerateButton = true;
+                }
+            });
+
+            // 创建主行
+            const row = document.createElement('tr');
+            const dropdownButton = document.createElement('button');
+        // 使用CSS创建一个箭头图标
+            dropdownButton.innerHTML = '';
+            dropdownButton.classList.add('arrow-icon');
+            dropdownButton.style.cursor = 'pointer';
+
+            row.innerHTML = `
+                <td></td> <!-- 空的单元格用于放置下拉按钮 -->
+                <td>${createEllipsisText(firstApplication.Creator)}</td>
+                <td>${createEllipsisText(firstApplication.ApplicationDate)}</td>
+                <td>${createEllipsisText(firstApplication.GlxmName)}</td>
+                <td>${createEllipsisText(firstApplication.SalesPerson)}</td>
+                <td>${createEllipsisText(firstApplication.SupportPerson)}</td>
+                <td>${firstApplication.TotalNodes}</td>
+                <td>${createEllipsisText(firstApplication.Company)}</td>
+            `;
+            row.querySelector('td').appendChild(dropdownButton);
+
+            // 添加 License 状态按钮 (父级行)
+          
+    if (hasGeneratePermission || hasDistributePermission) {
+        const licenseStatusCell = document.createElement('td');
+
+        if (hasGeneratePermission && showGenerateButton) {
+            licenseStatusCell.innerHTML += `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${firstApplication.oa_request_id}', true)">生成</button>`;
+        } else if (hasDistributePermission && firstApplication.LicenseFlage === "已生成") {
+            licenseStatusCell.innerHTML += `<button class="license-status-btn distribute" onclick="showEmailModal('${firstApplication.SupportEmail}', '${firstApplication.SalesEmail}', '${firstApplication.UniqueID}')">分发</button>`;
+        }
+
+        // 添加一个分隔符
+        licenseStatusCell.innerHTML += `<span style="margin: 0 10px; display: inline-block; width: 1px; height: 20px; background-color: #ccc;"></span>`;
+
+        // 在这里添加“查看详情”按钮
+        licenseStatusCell.innerHTML += `<button class="license-status-btn view-details" onclick="showDetailsModal('${firstApplication.UniqueID}')">查看详情</button>`;
+
+        row.appendChild(licenseStatusCell);
+}
+
+
+            tableBody.appendChild(row);
+
+            // 多行内容及表头 (子行)
+            const detailRow = document.createElement('tr');
+            const detailCell = document.createElement('td');
+            detailCell.colSpan = 11; // 占满所有列
+            detailCell.style.display = 'none';
+            const detailTable = document.createElement('table');
+
+            // 添加表头
+            const detailTableHeader = document.createElement('tr');
+            detailTableHeader.innerHTML = `
+                <th>产品名称</th>
+                <th>版本</th>
+                <th>节点数</th>
+                <th>处理器</th>
+                <th>操作系统</th>
+                <th>主MAC地址</th>
+                <th>副MAC地址</th>
+                <th>   查看</th>
+            `;
+            detailTable.appendChild(detailTableHeader);
+
+            // 添加详细信息行 (子行)
+            applicationArray.forEach(detail => {
+                const detailInnerRow = document.createElement('tr');
+                detailInnerRow.innerHTML = `
+                    <td>${createEllipsisText(detail.ProductName)}</td>
+                    <td>${createEllipsisText(detail.ProductVersion)}</td>
+                    <td>${detail.NodeCount}</td>
+                    <td>${createEllipsisText(detail.oa_cpu)}</td>
+                    <td>${createEllipsisText(detail.oa_operating_system)}</td>
+                    <td>${createEllipsisText(detail.oa_main_mac)}</td>
+                    <td>${createEllipsisText(detail.oa_second_mac)}</td>
+                `;
+//保留这里的代码,涉及到子行的单独申请
+                // 添加 License 状态按钮 (子行) 
+                // if (hasGeneratePermission || hasDistributePermission) {
+                //     const licenseStatusDetailCell = document.createElement('td');
+
+                //     if (hasGeneratePermission && detail.LicenseFlage === "未生成") {
+                //         // 子行点击生成按钮时,传递 UniqueID 和 false 表示这是子行
+                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${detail.UniqueID}', false)">生成</button>`;
+                //     } else if (hasDistributePermission && detail.LicenseFlage === "已生成") {
+                //         // 子行点击分发按钮时,传递 UniqueID 用于分发操作
+                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn distribute" onclick="showEmailModal('${detail.SupportEmail}', '${detail.SalesEmail}', '${detail.UniqueID}')">分发</button>`;
+                //     }
+
+                //     detailInnerRow.appendChild(licenseStatusDetailCell);
+                // }
+
+                detailTable.appendChild(detailInnerRow);
+        // 添加“查看详情”按钮 (子行)
+        const viewDetailsCell = document.createElement('td');
+        viewDetailsCell.innerHTML = `<button class="license-status-btn view-details" onclick="showDetailsModal('${detail.UniqueID}', true)">查看详情</button>`;
+        detailInnerRow.appendChild(viewDetailsCell);
+
+    detailTable.appendChild(detailInnerRow);
+
+
+                // 为每个详细信息行添加点击事件 (子行)
+                detailInnerRow.addEventListener('click', (event) => {
+                    if (!event.target.closest('button')) {
+                        openActionModal(event, detail, 'licenseActionModal');
+                    }
+                });
+
+                detailInnerRow.addEventListener('contextmenu', (event) => {
+                    event.preventDefault();
+                    if (!event.target.closest('button')) {
+                        openActionModal(event, detail, 'licenseActionModal');
+                    }
+                });
+            });
+
+            detailCell.appendChild(detailTable);
+            detailRow.appendChild(detailCell);
+            tableBody.appendChild(detailRow);
+
+            // 主行的点击事件,用于切换下拉菜单的显示隐藏
+            // row.addEventListener('click', (event) => {
+            //     if (!event.target.closest('button')) { // 如果点击的不是按钮
+            //         detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none';
+            //     }
+            // });
+
+            // // 点击下拉按钮切换显示隐藏
+            // dropdownButton.addEventListener('click', (event) => {
+            //     event.stopPropagation(); // 阻止事件冒泡到行点击事件
+            //     detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none';
+            // });
+            row.addEventListener('click', (event) => {
+    if (!event.target.closest('button')) { // 如果点击的不是按钮
+        // const isExpanded = detailCell.style.display === 'table-cell';
+        // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+        // row.classList.toggle('expanded-row', !isExpanded);
+        // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
+        if (!event.target.closest('button')) {
+        const isExpanded = detailCell.style.display === 'table-cell';
+        
+        // 收回其他行
+        closeAllExpandedRows();
+
+        // 展开/收起当前行
+        detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+        row.classList.toggle('expanded-row', !isExpanded);
+        dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
+    }
+    }
+});
+
+dropdownButton.addEventListener('click', (event) => {
+    // event.stopPropagation(); // 阻止事件冒泡到行点击事件
+    // const isExpanded = detailCell.style.display === 'table-cell';
+    // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+    // row.classList.toggle('expanded-row', !isExpanded);
+    // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
+    event.stopPropagation(); // 阻止事件冒泡到行点击事件
+    const isExpanded = detailCell.style.display === 'table-cell';
+    
+    // 收回其他行
+    closeAllExpandedRows();
+
+    // 展开/收起当前行
+    detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+    row.classList.toggle('expanded-row', !isExpanded);
+    dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
+});
+
+        });
+
+        // 分页和其他控制逻辑
+  // 更新分页信息
+      //  totalPages = Math.ceil(data.total / pageSize);
+        document.getElementById('pagination-info').textContent = `第 ${currentPage} 页,共 ${totalPages} 页`;
+        document.getElementById('prev-page').disabled = currentPage <= 1;
+        document.getElementById('next-page').disabled = currentPage >= totalPages;
+
+        const pageSelector = document.getElementById('page-selector');
+        pageSelector.innerHTML = '';
+        for (let i = 1; i <= totalPages; i++) {
+            const option = document.createElement('option');
+            option.value = i;
+            option.text = i;
+            if (i === selectedPage) {
+                option.selected = true;
+                document.getElementById('pagination-info').textContent = `第 ${selectedPage} 页,共 ${totalPages} 页`;
+                // LisOffset = selectedPage
+                // pageSize = LisOffset + 10;
+                // document.getElementById('prev-page').disabled = currentPage <= 1;
+                // document.getElementById('next-page').disabled = currentPage >= totalPages;
+            }
+            pageSelector.appendChild(option);
+        }
+        
+        
+    });
+}
+
+let currentOffset = 1;
+const itemsPerPage = 10;
+
+// 添加页数选择框的事件监听器
+document.getElementById('page-selector').addEventListener('change', (event) => {
+     selectedPage = parseInt(event.target.value, 10);
+     
+    const startRecord = (selectedPage - 1) * 10 + 1;
+    const endRecord = startRecord + 10;
+    LisOffset = selectedPage
+    pageSize = LisOffset* 10; 
+    currentPage = selectedPage 
+    currentOffset = startRecord
+    endOffset = endRecord
+    fetchApplications(startRecord, endRecord);
+});
+
+// 分页按钮事件监听器
+document.getElementById('prev-page').addEventListener('click', () => {
+    if (currentPage > 1) {
+        currentPage--;
+        selectedPage--
+    
+        currentOffset -= itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
+    }
+});
+
+
+document.getElementById('next-page').addEventListener('click', () => {
+    if (currentPage < totalPages) {
+        currentPage++
+        selectedPage++
+        LisOffset += pageSize-LisOffset;
+        pageSize += 10; // 增加页数时,增加 pageSize,规则可自定义
+
+  
+        currentOffset += itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
+    }
+});
+
+// 页面加载时默认调用第一页的数据
+//fetchApplications(1);
+// 页面初始化时调用 fetchUsername 函数
+fetchUsername();
+fetchApplications(LisOffset,pageSize);
+
+//排序
+// function sortTableByDate() {
+//     applicationData.sort((a, b) => {
+//         const dateTimeA = `${a[0].ApplicationDate} ${a[0].ApplicationTime}`;
+//         const dateTimeB = `${b[0].ApplicationDate} ${b[0].ApplicationTime}`;
+//         return isAscending ? dateTimeA.localeCompare(dateTimeB) : dateTimeB.localeCompare(dateTimeA);
+//     });
+
+//     renderTable(applicationData); // 排序后重新渲染表格
+//     isAscending = !isAscending; // 切换排序顺序
+// }
+
+
+// 关闭所有已经展开的行
+function closeAllExpandedRows() {
+    const allExpandedRows = document.querySelectorAll('.expanded-row');
+    allExpandedRows.forEach(expandedRow => {
+        const detailCell = expandedRow.nextElementSibling.querySelector('td');
+        if (detailCell && detailCell.style.display === 'table-cell') {
+            detailCell.style.display = 'none';
+            expandedRow.classList.remove('expanded-row');
+            const dropdownButton = expandedRow.querySelector('.arrow-icon');
+            if (dropdownButton) {
+                dropdownButton.classList.remove('rotate-arrow');
+            }
+        }
+    });
+}
+
+
+
+
+// 创建带省略号的文本,并在鼠标悬停时显示完整内容
+function createEllipsisText(text) {
+    const maxLength = 20; // 最大显示字符数
+    if (text == null || typeof text !== 'string') {
+        return ''; // 如果 text 是 null、undefined 或不是字符串,返回空字符串
+    }
+    if (text.length > maxLength) {
+        const span = document.createElement('span');
+        span.textContent = text.substring(0, maxLength) + '...';
+        span.title = text; // 鼠标悬停时显示完整内容
+        return span.outerHTML;
+    }
+    return text;
+}
+
+//生成licensestr
+function confirmGenerateLicense(id, isParentRow) {
+    const confirmGenerateModal = document.getElementById('confirmGenerateModal');
+    confirmGenerateModal.style.display = 'block';
+    document.getElementById('confirm-generate-button').onclick = function() {
+        generateLicense(id, isParentRow);
+    };
+}
+
+function generateLicense(id, isParentRow) {
+    const payload = isParentRow ? { oa_request_id: id } : { uniqueID: id };
+    
+    fetch('http://127.0.0.1:8080/api/admin/GenerateLicense', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(payload)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('License生成成功!');
+            const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+        //    fetchApplications(LisOffset, pageSize);
+        } else {
+            alert('License生成失败:' + data.error);
+        }
+        closeModal('confirmGenerateModal');
+    });
+}
+
+
+
+
+
+
+//查看lic所有信息
+function showDetailsModal(uniqueID, isChildRow = false) {
+    let selectedData = null;
+
+    if (isChildRow) {
+        // 查找子行数据
+        for (let applicationArray of LicApplicationData) {
+            selectedData = applicationArray.find(data => data.UniqueID === uniqueID);
+            if (selectedData) {
+                break;
+            }
+        }
+
+        if (!selectedData) {
+            console.error('未找到对应的子行记录,UniqueID:', uniqueID);
+            alert('未找到对应的子行记录,请检查数据');
+            return;
+        }
+
+        // 准备在模态框中显示的子行内容
+        let detailsHtml = `<div class="apple-modal-content">`;
+        detailsHtml += `<h3 class="apple-modal-title">详细信息</h3>`;
+        detailsHtml += `
+            <p class="apple-modal-text"><strong>产品名称:</strong> ${selectedData.ProductName}</p>
+            <p class="apple-modal-text"><strong>版本:</strong> ${selectedData.ProductVersion}</p>
+            <p class="apple-modal-text"><strong>节点数:</strong> ${selectedData.NodeCount}</p>
+            <p class="apple-modal-text"><strong>处理器:</strong> ${selectedData.oa_cpu}</p>
+            <p class="apple-modal-text"><strong>操作系统:</strong> ${selectedData.oa_operating_system}</p>
+            <p class="apple-modal-text"><strong>主MAC地址:</strong> ${selectedData.oa_main_mac}</p>
+            <p class="apple-modal-text"><strong>副MAC地址:</strong> ${selectedData.oa_second_mac}</p>
+        `;
+        detailsHtml += `</div>`;
+
+        // 显示模态框
+        document.getElementById('detailsContent').innerHTML = detailsHtml;
+        document.getElementById('detailsModal').style.display = 'block';
+
+    } else {
+        // 查找主行数据
+        let selectedApplicationArray = null;
+
+        for (let applicationArray of LicApplicationData) {
+            if (applicationArray.some(data => data.UniqueID === uniqueID)) {
+                selectedApplicationArray = applicationArray;
+                break;
+            }
+        }
+
+        if (!selectedApplicationArray) {
+            console.error('未找到对应的记录,UniqueID:', uniqueID);
+            alert('未找到对应的记录,请检查数据');
+            return;
+        }
+
+        // 准备在模态框中显示的主行和子行的全部内容
+        let detailsHtml = `<div class="apple-modal-content">`;
+        detailsHtml += `<h3 class="apple-modal-title">项目信息</h3>`;
+        
+        // 显示主行的第一条记录信息
+        const firstData = selectedApplicationArray[0];
+        detailsHtml += `
+            <p class="apple-modal-text"><strong>创建人:</strong> ${firstData.Creator}</p>
+            <p class="apple-modal-text"><strong>申请日期:</strong> ${firstData.ApplicationDate}</p>
+            <p class="apple-modal-text"><strong>关联项目:</strong> ${firstData.GlxmName}</p>
+            <p class="apple-modal-text"><strong>销售人员:</strong> ${firstData.SalesPerson}</p>
+            <p class="apple-modal-text"><strong>技服人员:</strong> ${firstData.SupportPerson}</p>
+            <p class="apple-modal-text"><strong>总节点数:</strong> ${firstData.TotalNodes}</p>
+            <p class="apple-modal-text"><strong>使用单位:</strong> ${firstData.Company}</p>
+        `;
+
+        // 显示子行的每条记录信息
+        detailsHtml += `<h3 class="apple-modal-title">集群信息</h3>`;
+        selectedApplicationArray.forEach((data, index) => {
+            detailsHtml += `
+                <h4 class="apple-modal-subtitle">集群 ${index + 1}</h4>
+                <p class="apple-modal-text"><strong>产品名称:</strong> ${data.ProductName}</p>
+                <p class="apple-modal-text"><strong>版本:</strong> ${data.ProductVersion}</p>
+                <p class="apple-modal-text"><strong>节点数:</strong> ${data.NodeCount}</p>
+                <p class="apple-modal-text"><strong>处理器:</strong> ${data.oa_cpu}</p>
+                <p class="apple-modal-text"><strong>操作系统:</strong> ${data.oa_operating_system}</p>
+                <p class="apple-modal-text"><strong>主MAC地址:</strong> ${data.oa_main_mac}</p>
+                <p class="apple-modal-text"><strong>副MAC地址:</strong> ${data.oa_second_mac}</p>
+                <h4 class="apple-modal-subtitle"> -------------------------------</h4>
+            `;
+        });
+
+        detailsHtml += `</div>`;
+
+        // 显示模态框
+        document.getElementById('detailsContent').innerHTML = detailsHtml;
+        document.getElementById('detailsModal').style.display = 'block';
+    }
+}
+
+
+// 用户管理菜单栏
+function openUserActionModal(event, data, modalId) {
+    selectedRowData = data;
+    let modal = document.getElementById(modalId);
+    const modalContent = modal.querySelector('.modal-content');
+
+    // 清空之前的内容
+    modalContent.innerHTML = `
+        <span class="close" onclick="closeModal('${modalId}')">&times;</span>
+    `;
+
+    // 动态生成更多用户信息按钮
+    if (userPermissions.includes('read_user')) {
+        modalContent.innerHTML += `<button onclick="showMoreUserInfo(); closeModal('${modalId}');">更多用户信息</button>`;
+    }
+
+    // 检查是否有 `update_user` 权限,决定是否显示修改用户按钮
+    if (userPermissions.includes('update_user')) {
+        modalContent.innerHTML += `<button onclick="modifyUser(); closeModal('${modalId}');">修改用户</button>`;
+    }
+
+    // 检查是否有 `delete_user` 权限,决定是否显示删除按钮
+    if (userPermissions.includes('delete_user')) {
+        modalContent.innerHTML += `<button onclick="confirmDeleteUser('${data.UniqueID}'); closeModal('${modalId}');">删除用户</button>`;
+    }
+
+    // 显示菜单位置
+    modalContent.style.top = `${event.clientY}px`;
+    modalContent.style.left = `${event.clientX}px`;
+    modal.style.display = 'block';
+}
+
+
+
+// 为用户管理界面的每一行添加点击和右键事件监听器
+function fetchUsers() {
+    fetch('http://127.0.0.1:8080/api/admin/userInfoAll', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const tableBody = document.querySelector('#users-table tbody');
+        tableBody.innerHTML = '';
+        data.data.forEach(user => {
+            // 如果 ACCOUNT 字段为 'admin',则跳过这一行
+            if (user.Account === 'admin') {
+                return;
+            }
+
+            const row = document.createElement('tr');
+            row.innerHTML = `
+                <td>${user.Username}</td>
+                <td>${user.Telephone}</td>
+                <td>${user.Email}</td>
+                <td>${user.Role}</td>
+                <td>${user.Account}</td>
+            `;
+
+            row.addEventListener('click', (event) => {
+                if (!event.target.classList.contains('ios-button')) {
+                    openUserActionModal(event, user, 'userActionModal');
+                }
+            });
+            row.addEventListener('contextmenu', (event) => {
+                event.preventDefault();
+                if (!event.target.classList.contains('ios-button')) {
+                    openUserActionModal(event, user, 'userActionModal');
+                }
+            });
+
+            tableBody.appendChild(row);
+        });
+    });
+}
+
+//查看用户lic历史
+function showUserLicenseHistory() {
+    fetch(`http://127.0.0.1:8080/api/admin/GetlicenseRecordInfoByUser`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+            Id: selectedRowData.Id,
+            UserName: selectedRowData.Username,
+            Page: 1,
+            PageSize: 10
+        })
+    })
+    .then(response => response.json())
+    .then(data => {
+        const extraInfoContent = document.getElementById('extraInfoContent');
+        extraInfoContent.innerHTML = `<h3>License 分发记录</h3>`;
+        
+        if (data.data && data.data.length > 0) {
+            const table = document.createElement('table');
+            table.style.width = '100%';
+            table.style.borderCollapse = 'collapse';
+            table.style.marginTop = '10px';
+
+            const thead = document.createElement('thead');
+            const headerRow = document.createElement('tr');
+            const headers = ['分发日期', '关联项目', '产品名称', '版本', '节点数', 'Company'];
+
+            headers.forEach(headerText => {
+                const th = document.createElement('th');
+                th.textContent = headerText;
+                th.style.border = '1px solid #ddd';
+                th.style.padding = '8px';
+                th.style.backgroundColor = '#f1f1f1';
+                headerRow.appendChild(th);
+            });
+
+            thead.appendChild(headerRow);
+            table.appendChild(thead);
+
+            const tbody = document.createElement('tbody');
+            data.data.forEach(record => {
+                const row = document.createElement('tr');
+
+                const cells = [
+                    record.up_time.Time,
+                    record.AssociatedProject,
+                    record.ProductName,
+                    record.Version,
+                    record.NodeCount,
+                    record.Company
+                ];
+
+                cells.forEach(cellText => {
+                    const td = document.createElement('td');
+                    td.textContent = cellText;
+                    td.style.border = '1px solid #ddd';
+                    td.style.padding = '8px';
+                    row.appendChild(td);
+                });
+
+                tbody.appendChild(row);
+            });
+
+            table.appendChild(tbody);
+            extraInfoContent.appendChild(table);
+        } else {
+            extraInfoContent.innerHTML += `<p>没有找到分发记录。</p>`;
+        }
+
+        document.getElementById('extraInfoModal').style.display = 'block';
+    });
+}
+
+
+//用户菜单栏
+function openActionModal(event, data, modalId) {
+    selectedRowData = data;
+    let modal = document.getElementById(modalId);
+    const modalContent = modal.querySelector('.modal-content');
+
+    // 清空之前的内容
+    modalContent.innerHTML = `
+        <span class="close" onclick="closeModal('${modalId}')">&times;</span>
+    `;
+
+
+
+    // 动态生成查看分发记录
+    if (userPermissions.includes('read_license_record')) {
+        modalContent.innerHTML += `
+            <button onclick="showDistributionHistory(); closeModal('${modalId}');">查看分发记录</button>
+        `;
+    }
+     // 动态生成查看额外信息
+     if (userPermissions.includes('read_license')) {
+        modalContent.innerHTML += `
+            <button onclick="showExtraInfo(); closeModal('${modalId}');">查看额外信息</button>
+        `;
+    }
+
+    // 检查是否有 `update_license` 权限,决定是否显示修改信息按钮
+    if (userPermissions.includes('update_license')) {
+        modalContent.innerHTML += `<button onclick="modifyLicenseInfo(); closeModal('${modalId}');">修改信息</button>`;
+    }
+
+    // 检查是否有 `delete_license` 权限,决定是否显示删除按钮
+    if (userPermissions.includes('delete_license')) {
+        modalContent.innerHTML += `<button onclick="confirmDelete(); closeModal('${modalId}');">删除</button>`;
+    }
+
+    // 显示菜单位置
+    modalContent.style.top = `${event.clientY}px`;
+    modalContent.style.left = `${event.clientX}px`;
+    modal.style.display = 'block';
+}
+
+
+
+
+
+function closeModal(modalId) {
+            document.getElementById(modalId).style.display = 'none';
+        }
+
+
+// function closeUserInfo() {
+//             document.getElementById('userModal').style.display = 'none';
+//         }
+
+function confirmDelete() {
+    const confirmDeleteModal = document.getElementById('confirmDeleteModal');
+    confirmDeleteModal.innerHTML = `
+ <div class="centered-modal-content">
+    <span class="close" onclick="closeModal('confirmDeleteModal')" style="font-size: 24px; font-weight: bold; color: #555; cursor: pointer;">&times;</span>
+    <div style="margin-bottom: 15px; border: 1px solid #ddd; padding: 10px; border-radius: 10px;">
+        <p><strong>申请日期:</strong> ${selectedRowData.ApplicationDate}</p>
+        <p><strong>关联项目:</strong> ${selectedRowData.AssociatedProject}</p>
+        <p><strong>使用单位:</strong> ${selectedRowData.Company}</p>
+    </div>
+    <p>确认删除此行数据吗?</p>
+    <button class="flat-rounded-button" onclick="deleteRow()">确认</button>
+    <button class="flat-rounded-button" onclick="closeModal('confirmDeleteModal')">取消</button>
+</div>
+
+    `;
+    confirmDeleteModal.style.display = 'block';
+}
+
+//添加用户
+document.getElementById('addUserButton').addEventListener('click', function() {
+    document.getElementById('addUserModal').style.display = 'block';
+});
+//添加用户
+function saveNewUser() {
+    const username = document.getElementById('addUsername').value.trim();
+    const password = document.getElementById('addPassword').value.trim();
+    const account = document.getElementById('addAccount').value.trim();
+    const telephone = document.getElementById('addTelephone').value.trim();
+    const email = document.getElementById('addEmail').value.trim();
+
+    // 验证每个字段都不能为空
+    if (!username || !password || !account || !telephone || !email) {
+        alert('有空选项未填写');
+        return;
+    }
+
+    // 验证电话是否为11位数字
+    const phonePattern = /^\d{11}$/;
+    if (!phonePattern.test(telephone)) {
+        alert('电话必须是11位数字');
+        return;
+    }
+
+    // 验证密码长度是否至少为6位
+    if (password.length < 6) {
+        alert('密码长度必须至少为6位');
+        return;
+    }
+
+    // 验证邮箱是否包含@符号
+    if (!email.includes('@')) {
+        alert('邮箱必须包含@符号');
+        return;
+    }
+
+    // 验证账号长度是否至少为3位
+    if (account.length < 3) {
+        alert('账号长度必须至少为3位');
+        return;
+    }
+
+    const newUser = {
+        Username: username,
+        Password: password,
+        Account: account,
+        Telephone: telephone,
+        Email: email
+    };
+
+    fetch('http://127.0.0.1:8080/api/register', {  // 修改为实际的API路径
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(newUser)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('用户创建成功!');
+            fetchUsers(); // 重新加载用户列表
+            closeModal('addUserModal'); // 关闭模态框
+        } else {
+            alert('用户创建失败:' + data.error);
+        }
+    });
+}
+
+
+
+
+
+
+function deleteUser(uniqueID) {
+    fetch('http://127.0.0.1:8080/api/admin/deleteUser', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ UniqueID: uniqueID })
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('用户删除成功!');
+            fetchUsers(); // 重新加载用户列表
+        } else {
+            alert('用户删除失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        console.error('Error deleting user:', error);
+        alert('删除用户时发生错误,请稍后再试。');
+    });
+}
+function confirmDeleteUser(uniqueID) {
+    const confirmed = confirm("确认删除此用户吗?");
+    if (confirmed) {
+        deleteUser(uniqueID);
+    }
+}
+
+ function deleteRow() {
+            fetch(`http://127.0.0.1:8080/api/admin/deleteLicRow`, {
+                method: 'POST',
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
+            }).then(response => {
+                if (response.ok) {
+                    alert('删除成功');
+                    closeModal('confirmDeleteModal');
+                  //  fetchApplications(LisOffset, pageSize);
+                  const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+                } else {
+                    alert('删除失败');
+                }
+            });
+        }
+
+
+
+function showEmailModal(supportEmail, salesEmail, uniqueID) {
+    // 清空并设置默认值
+    document.getElementById('emailInputs').innerHTML = `
+        <div>
+            <input type="checkbox" id="supportEmailCheckbox" value="${supportEmail}" checked>
+            <label for="supportEmailCheckbox">  运维邮箱: ${supportEmail}</label>
+        </div>
+        <div>
+            <input type="checkbox" id="salesEmailCheckbox" value="${salesEmail}" checked>
+            <label for="salesEmailCheckbox">  销售邮箱: ${salesEmail}</label>
+        </div>
+ 
+    `;
+    document.getElementById('userInputs').innerHTML = ''; // 清空用户输入
+
+    // 获取用户信息并填充第一个用户输入框
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const userSelect = document.createElement('select');
+        userSelect.id = 'userSelect1';
+        userSelect.className = 'email-modal-input';
+        
+        data.data.forEach(user => {
+            userMap[user.Username] = {// 存储用户名和用户ID的映射
+            Account: user.Account,
+            UniqueID: user.UniqueID,
+            Username: user.Username,
+            Email: user.Email,
+            Role: user.Role,
+            Telephone:user.Telephone
+        };
+            const option = document.createElement('option');
+            option.value = user.Username;
+            option.textContent = user.Username;
+            userSelect.appendChild(option);
+        });
+
+        //document.getElementById('userInputs').appendChild(userSelect);
+    });
+
+    document.getElementById('emailModal').style.display = 'block';
+    selectedRowData = { ...selectedRowData, UniqueID: uniqueID };
+}
+
+function addEmailInput() {
+    const emailInputs = document.getElementById('emailInputs');
+    const newInputDiv = document.createElement('div');
+    newInputDiv.style.display = 'flex';
+    newInputDiv.style.alignItems = 'center';
+    newInputDiv.style.marginBottom = '10px';
+
+    const newInput = document.createElement('input');
+    newInput.type = 'text';
+    newInput.className = 'email-modal-input';
+    newInput.style.flexGrow = '1';
+    newInputDiv.appendChild(newInput);
+
+    const deleteButton = document.createElement('button');
+    deleteButton.textContent = '✕';
+    deleteButton.style.background = 'none';
+    deleteButton.style.border = 'none';
+    deleteButton.style.color = '#007aff';
+    deleteButton.style.cursor = 'pointer';
+    deleteButton.style.fontSize = '12px'; /* 再次缩小字体大小 */
+    deleteButton.style.padding = '0'; /* 移除内边距 */
+    deleteButton.style.marginLeft = '3px'; /* 减少与输入框的间距 */
+    deleteButton.style.width = '20px'; /* 限制按钮宽度 */
+    deleteButton.style.height = '20px'; /* 限制按钮高度 */
+    deleteButton.onclick = () => {
+        newInputDiv.remove();
+    };
+
+    newInputDiv.appendChild(deleteButton);
+    emailInputs.appendChild(newInputDiv);
+}
+
+function addUserInput() {
+    const userInputs = document.getElementById('userInputs');
+    const newUserDiv = document.createElement('div');
+    newUserDiv.className = 'user-select-container';
+    newUserDiv.style.display = 'flex';
+    newUserDiv.style.alignItems = 'center';
+    newUserDiv.style.marginBottom = '10px';
+
+    const newUserSelect = document.createElement('select');
+    newUserSelect.className = 'email-modal-input';
+    newUserSelect.style.flexGrow = '1';
+    newUserSelect.style.marginRight = '5px';
+
+    // 添加一个默认的空白选项
+    const defaultOption = document.createElement('option');
+    defaultOption.value = '';
+    defaultOption.textContent = '请选择用户';
+    newUserSelect.appendChild(defaultOption);
+
+    // 获取当前已选择的用户
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    // 获取用户列表并填充到选择框中
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        data.data.forEach(user => {
+            // 仅显示未被选中的用户,并且过滤掉admin用户
+            if (!selectedValues.includes(user.Username) && user.Username !== 'admin') {
+                const option = document.createElement('option');
+                option.value = user.Username;
+                option.textContent = user.Username;
+                newUserSelect.appendChild(option);
+            }
+        });
+    });
+
+    const deleteButton = document.createElement('button');
+    deleteButton.textContent = '✕';
+    deleteButton.style.background = 'none';
+    deleteButton.style.border = 'none';
+    deleteButton.style.color = '#007aff';
+    deleteButton.style.cursor = 'pointer';
+    deleteButton.style.fontSize = '12px';
+    deleteButton.style.padding = '0';
+    deleteButton.style.marginLeft = '3px';
+    deleteButton.style.width = '20px';
+    deleteButton.style.height = '20px';
+    deleteButton.onclick = () => {
+        newUserDiv.remove();
+        updateUserOptions(); // 更新其他下拉框中的选项
+    };
+
+    newUserSelect.addEventListener('change', updateUserOptions);
+
+    newUserDiv.appendChild(newUserSelect);
+    newUserDiv.appendChild(deleteButton);
+    userInputs.appendChild(newUserDiv);
+        // 设置空白选项为默认选项
+    newUserSelect.selectedIndex = 0;
+}
+
+function updateUserOptions() {
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    document.querySelectorAll('.user-select-container select').forEach(select => {
+        const currentValue = select.value;
+        select.innerHTML = ''; // 清空现有选项
+
+        // 添加一个默认的空白选项
+        const defaultOption = document.createElement('option');
+        defaultOption.value = '';
+        defaultOption.textContent = '请选择用户';
+        select.appendChild(defaultOption);
+
+        fetch('http://127.0.0.1:8080/api/admin/userInfoAll', {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            data.data.forEach(user => {
+                if (!selectedValues.includes(user.Username) || user.Username === currentValue) {
+                    if (user.Username !== 'admin') { // 过滤掉admin用户
+                        const option = document.createElement('option');
+                        option.value = user.Username;
+                        option.textContent = user.Username;
+                        select.appendChild(option);
+                    }
+                }
+            });
+
+            select.value = currentValue;
+        });
+    });
+}
+
+
+
+// 打开修改信息表单框
+function modifyLicenseInfo() {
+    const form = document.getElementById('modifyLicenseForm');
+    
+    // 将选中的行数据填充到表单中
+    form.creator.value = selectedRowData.Creator;
+    form.applicationDate.value = selectedRowData.ApplicationDate;
+    form.associatedProject.value = selectedRowData.GlxmName;
+    form.salesPerson.value = selectedRowData.SalesPerson;
+    form.salesEmail.value = selectedRowData.SalesEmail;
+    form.supportPerson.value = selectedRowData.SupportPerson;
+    form.supportEmail.value = selectedRowData.SupportEmail;
+    form.totalNodes.value = selectedRowData.TotalNodes;
+    form.company.value = selectedRowData.Company;
+    form.productName.value = selectedRowData.ProductName;
+    form.version.value = selectedRowData.ProductVersion;
+    form.nodeCount.value = selectedRowData.NodeCount;
+    
+    document.getElementById('modifyLicenseModal').style.display = 'block';
+}
+
+// 保存修改后的数据
+function saveLicenseChanges() {
+    const form = document.getElementById('modifyLicenseForm');
+    const updatedData = {
+        UniqueID: selectedRowData.UniqueID,
+        Creator: form.creator.value,
+        ApplicationDate: form.applicationDate.value,
+        AssociatedProject: form.associatedProject.value,
+        SalesPerson: form.salesPerson.value,
+        SalesEmail: form.salesEmail.value,
+        SupportPerson: form.supportPerson.value,
+        SupportEmail: form.supportEmail.value,
+        TotalNodes: parseInt(form.totalNodes.value, 10), // 将 TotalNodes 转换为整数
+        Company: form.company.value,
+        ProductName: form.productName.value,
+        Version: form.version.value,
+        NodeCount: parseInt(form.nodeCount.value, 10), // 将 NodeCount 转换为整数
+    };
+    
+    fetch(`http://127.0.0.1:8080/api/admin/UpdateLicense`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(updatedData)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('License信息更新成功!');
+          //  fetchApplications(LisOffset, pageSize);
+          const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+            closeModal('modifyLicenseModal');
+        } else {
+            alert('License信息更新失败:' + data.error);
+        }
+    });
+}
+
+
+
+
+function updateUserOptions() {
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    document.querySelectorAll('.user-select-container select').forEach(select => {
+        const currentValue = select.value;  // 保留当前选择值
+        select.innerHTML = ''; // 清空现有选项
+        
+        fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            data.data.forEach(user => {
+                // 保留当前值,并排除已经在其他下拉框中选中的值
+                if (!selectedValues.includes(user.Username) || user.Username === currentValue) {
+                    const option = document.createElement('option');
+                    option.value = user.Username;
+                    option.textContent = user.Username;
+                    if (user.Username === currentValue) {
+                        option.selected = true;  // 保持当前选择
+                    }
+                    select.appendChild(option);
+                }
+            });
+        });
+    });
+}
+
+//lic分发给用户 与邮件
+function sendEmail() {
+    console.log('Send button clicked');
+
+    const emailInputs = document.querySelectorAll('.email-modal-input[type="text"]');
+    let emails = Array.from(emailInputs)
+        .map(input => input.value.trim())
+        .filter(email => email && email.includes('@'))
+        .join(',');
+
+    const supportEmailChecked = document.getElementById('supportEmailCheckbox').checked;
+    const salesEmailChecked = document.getElementById('salesEmailCheckbox').checked;
+
+    const emailArray = emails ? [emails] : [];
+
+    if (supportEmailChecked) {
+        emailArray.push(document.getElementById('supportEmailCheckbox').value);
+    }
+    if (salesEmailChecked) {
+        emailArray.push(document.getElementById('salesEmailCheckbox').value);
+    }
+
+    emails = emailArray.join(',');
+
+    // if (!emails) {
+    //     alert('请至少选择一个邮箱地址。');
+    //     return;
+    // }
+
+    console.log('Emails to send:', emails);
+
+    const userInputs = document.querySelectorAll('select.email-modal-input');
+    console.log('userMap:', userMap);
+    
+    const users = Array.from(userInputs)
+        .map(select => userMap[select.value].Account)
+        .join(',');
+
+    const userIds = Array.from(userInputs)
+        .map(select => userMap[select.value].UniqueID)
+        .join(',');
+
+    const userNames = Array.from(userInputs)
+        .map(select => userMap[select.value].Username);
+
+
+
+    const operatorUniqueID = userMap[currentUserName].UniqueID;
+    console.log('User IDs:', userIds);
+    console.log('Users:', users);
+    console.log(' selectedRowData.UniqueID:',  selectedRowData.UniqueID);
+
+    if (!userIds) {
+        alert('请至少选择一个用户。');
+        return;
+    }
+
+    const requestData = {
+        LicenseUniqueID: selectedRowData.UniqueID,
+        UserUniqueIDs: userIds.split(','), 
+        UserAccounts: users.split(','), 
+        Emails: emails,
+        UserNames: userNames,
+        OperatorUniqueID: operatorUniqueID
+    };
+    console.log('requestData:', requestData);
+
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicense', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(requestData)
+    })
+    .then(response => {
+        console.log('Response received');
+        return response.json();
+    })
+    .then(data => {
+        if (data.success) {
+            alert('分发成功!');
+            closeModal('emailModal');
+        } else {
+            // 检查是否有 error 字段,并提示用户详细的错误信息
+            const errorMessage = data.error || '分发失败。';
+            alert(`分发失败: ${errorMessage}`);
+        }
+   
+    })
+    .catch(error => {
+        console.error('Error occurred during email distribution:', error);
+        alert('分发失败,请检查网络或后端服务。');
+    });
+}
+
+
+
+
+
+
+function showDistributionHistory() {
+    fetch('http://127.0.0.1:8080/api/admin/GetlicenseRecord', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
+    })
+    .then(response => response.json())
+    .then(data => {
+        const distributionHistoryContent = document.getElementById('distributionHistoryContent');
+        const { license_record_to_user, license_record_to_emails } = data.data;
+
+        // 确保 license_record_to_user 和 license_record_to_emails 存在并且是数组
+        const userRecords = Array.isArray(license_record_to_user) ? license_record_to_user : [];
+        const emailRecords = Array.isArray(license_record_to_emails) ? license_record_to_emails : [];
+
+        if (userRecords.length > 0 || emailRecords.length > 0) {
+            const userHistoryHtml = userRecords.map(record => `
+                <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">
+                    <p><strong>已转发给用户:</strong> ${record.user_account}</p>
+                    <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p>
+                </div>
+            `).join('');
+
+            const emailHistoryHtml = emailRecords.map(record => `
+                <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">
+                    <p><strong>已发给邮箱:</strong> ${record.emails}</p>
+                    <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p>
+                </div>
+            `).join('');
+
+            distributionHistoryContent.innerHTML = userHistoryHtml + emailHistoryHtml;
+        } else {
+            distributionHistoryContent.innerHTML = `<p>没有分发历史记录。</p>`;
+        }
+
+        // 显示模态框
+        const distributionHistoryModal = document.getElementById('distributionHistoryModal');
+        distributionHistoryModal.style.display = 'block';
+    });
+}
+
+
+
+
+
+ function showMoreUserInfo() {
+            const extraInfoContent = document.getElementById('extraInfoContent');
+            extraInfoContent.innerHTML = `
+                <p><strong>用户名:</strong> ${selectedRowData.Username}</p>
+                <p><strong>电话:</strong> ${selectedRowData.Telephone}</p>
+                <p><strong>邮箱:</strong> ${selectedRowData.Email}</p>
+                <p><strong>权限:</strong> ${selectedRowData.Role}</p>
+            `;
+            document.getElementById('extraInfoModal').style.display = 'block';
+        }
+
+function modifyUser() {
+            const userInfoContent = document.getElementById('extraInfoContent');
+            userInfoContent.innerHTML = `
+                <p><strong>用户名:</strong> ${selectedRowData.Username}</p>
+                <p><strong>电话:</strong> ${selectedRowData.Telephone}</p>
+                <p><strong>邮箱:</strong> ${selectedRowData.Email}</p>
+                <p><strong>权限:</strong> ${selectedRowData.Role}</p>
+                <button onclick="showEditUserForm()">编辑用户信息</button>
+            `;
+            document.getElementById('extraInfoModal').style.display = 'block';
+        }
+
+//查看额外信息
+function showExtraInfo() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+    
+    // 清空之前的内容
+    extraInfoContent.innerHTML = '';
+
+    // 使用预定义的字段名和中文翻译
+    const fieldTranslations = {
+        id: "ID",
+        user_id: "用户ID",
+        up_user: "上传用户",
+        up_time: "上传时间",
+        del_time: "删除时间",
+        License1: "License 1",
+        License2: "License 2",
+        LicenseFlage: "License 状态",
+        UniqueID: "唯一标识符",
+        Creator: "创建人",
+        ApplicationDate: "申请日期",
+        AssociatedProject: "关联项目",
+        SalesPerson: "销售人员",
+        SalesEmail: "销售邮箱",
+        SupportPerson: "支持人员",
+        SupportEmail: "支持邮箱",
+        TotalNodes: "总节点数",
+        Company: "公司",
+        ProductName: "产品名称",
+        Version: "版本",
+        NodeCount: "节点数",
+        Processor: "处理器",
+        OperatingSystem: "操作系统",
+        MasterMacAddress: "主MAC地址",
+        SecondaryMasterMacAddress: "备用主MAC地址"
+    };
+
+    // 使用指定的字段进行展示
+    const fieldsToShow = [
+        "id", "user_id", "up_user", "up_time", "del_time", "License1", "License2", 
+        "LicenseFlage", "UniqueID", "Creator", "ApplicationDate", "AssociatedProject", 
+        "SalesPerson", "SalesEmail", "SupportPerson", "SupportEmail", "TotalNodes", 
+        "Company", "ProductName", "Version", "NodeCount", "Processor", "OperatingSystem", 
+        "MasterMacAddress", "SecondaryMasterMacAddress"
+    ];
+
+    fieldsToShow.forEach(key => {
+        if (selectedRowData.hasOwnProperty(key)) {
+            let value = selectedRowData[key];
+            
+            // 特殊处理 up_time 和 del_time
+            if (key === 'up_time' || key === 'del_time') {
+                if (value.Valid) {
+                    value = new Date(value.Time).toLocaleString(); // 格式化日期时间
+                } else {
+                    value = '无';
+                }
+            }
+
+            // 处理 License1 和 License2,提取字符串字段
+            if (key === 'License1' || key === 'License2') {
+                // 假设 License 对象包含一个名为 'Details' 的字符串字段
+                value = value.String || '[无数据]';
+            }
+
+            // 处理 MasterMacAddress 和 SecondaryMasterMacAddress,提取字符串字段
+            // if (key === 'MasterMacAddress' || key === 'SecondaryMasterMacAddress') {
+            //     // 假设 License 对象包含一个名为 'Details' 的字符串字段
+            //     value = value.String || '[无数据]';
+            // }
+
+            const infoElement = document.createElement('p');
+            infoElement.innerHTML = `<strong>${fieldTranslations[key]}:</strong> ${value}`;
+            extraInfoContent.appendChild(infoElement);
+        }
+    });
+
+    // 显示 modal
+    document.getElementById('extraInfoModal').style.display = 'block';
+}
+
+
+function showRoleManagement() {
+    document.getElementById('table-container').style.display = 'none';
+    document.getElementById('user-management').style.display = 'none'; // 隐藏用户管理页面
+    document.getElementById('role-management').style.display = 'block';;
+
+    fetchRoles();
+}
+
+function fetchRoles() {
+    fetch('http://127.0.0.1:8080/api/admin/GetRoles', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ Name: " " })  // 发送空的 Name 参数
+    })
+    .then(response => response.json())
+    .then(data => {
+        const roleContainer = document.getElementById('roles-container');
+        roleContainer.innerHTML = ''; // 清空之前的内容
+
+        const permissionMap = {
+            'generate_license': '生成许可证',
+            'upload_license': '上传许可证',
+            'read_license': '读取许可证',
+            'read_license_record': '读取许可证分发记录',
+            'update_license': '修改许可证',
+            'delete_license': '删除许可证',
+            'dispat_license': '分发许可证',
+            'create_user': '创建用户',
+            'read_user': '读取用户',
+            'update_user': '更新用户',
+            'delete_user': '删除用户',
+            'create_role': '创建角色',
+            'delete_role': '删除角色',
+            'update_role': '更新角色',
+            'get_role': '获取角色'
+        };
+
+        // 检查用户是否有 create_role 权限
+        const hasCreateRolePermission = userPermissions.includes('create_role');
+
+        // 如果有权限则显示“创建角色”按钮
+        if (hasCreateRolePermission) {
+            document.getElementById('createRoleButton').style.display = 'block';
+        } else {
+            document.getElementById('createRoleButton').style.display = 'none';
+        }
+
+        // 处理置顶角色和其他角色的渲染(代码不变)
+        const topRoles = ['admin', 'guest', 'supportRole'];
+
+        topRoles.forEach(role => {
+            if (data.data[role]) {
+                renderRole(roleContainer, data.data[role], permissionMap, true);
+            }
+        });
+
+        Object.keys(data.data).forEach(role => {
+            if (!topRoles.includes(role)) {
+                renderRole(roleContainer, data.data[role], permissionMap, false);
+            }
+        });
+    });
+}
+
+
+function renderRole(container, roleInfo, permissionMap, isTopRole) {
+    const roleDiv = document.createElement('div');
+    roleDiv.className = 'role-item';
+    roleDiv.style.position = 'relative';  // 确保弹出菜单能够正确定位
+
+    if (isTopRole) {
+        roleDiv.classList.add('top-role'); // 应用置顶角色的样式
+    }
+
+    let permissions = roleInfo.Permissions.map(permission => permissionMap[permission]);
+    let permissionsHtml = permissions.join(',');  // 使用逗号分隔并合并为一行
+
+    roleDiv.innerHTML = `
+        <h3>${roleInfo.Name}</h3>
+        <p>${permissionsHtml}</p>
+    `;
+    container.appendChild(roleDiv);
+
+    // 添加事件监听器,处理点击和右键点击弹出菜单
+    roleDiv.addEventListener('click', function(event) {
+        event.stopPropagation();  // 阻止事件冒泡
+        event.preventDefault();   // 阻止默认行为
+        showRoleActionMenu(event, roleInfo.Name);
+    });
+
+    roleDiv.addEventListener('contextmenu', function(event) {
+        event.preventDefault();
+        showRoleActionMenu(event, roleInfo.Name);
+    });
+}
+
+function showRoleActionMenu(event, roleName) {
+    const existingMenu = document.getElementById('role-action-menu');
+    if (existingMenu) {
+        existingMenu.remove();
+    }
+
+    const menu = document.createElement('div');
+    menu.id = 'role-action-menu';
+    menu.style.position = 'absolute';
+    menu.style.top = `${event.clientY}px`;
+    menu.style.left = `${event.clientX}px`;
+    menu.style.backgroundColor = '#fff';
+    menu.style.border = '1px solid #ccc';
+    menu.style.borderRadius = '5px';
+    menu.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)';
+    menu.style.padding = '10px';
+    menu.style.zIndex = '1000';
+
+    const topRoles = ['admin', 'guest', 'support'];
+
+    if (topRoles.includes(roleName)) {
+        // 为 admin, guest, supportRole 设置灰色和不可点击样式
+        const disabledButton = document.createElement('button');
+        disabledButton.textContent = '不可操作';
+        disabledButton.style.display = 'block';
+        disabledButton.style.width = '100%';
+        disabledButton.style.padding = '10px 20px';
+        disabledButton.style.border = 'none';
+        disabledButton.style.borderRadius = '15px';
+        disabledButton.style.cursor = 'not-allowed';
+        disabledButton.style.backgroundColor = '#d3d3d3';  // 灰色背景
+        disabledButton.style.color = '#999';  // 灰色文字
+
+        menu.appendChild(disabledButton);
+    } else {
+        // 检查用户是否有 update_role 和 delete_role 权限
+        const hasUpdateRolePermission = userPermissions.includes('update_role');
+        const hasDeleteRolePermission = userPermissions.includes('delete_role');
+
+        // 创建和添加修改角色按钮
+        if (hasUpdateRolePermission) {
+            const modifyButton = document.createElement('button');
+            modifyButton.textContent = '修改角色';
+            modifyButton.style.display = 'block';
+            modifyButton.style.marginBottom = '10px';
+            modifyButton.style.width = '100%';
+            modifyButton.style.padding = '10px 20px';
+            modifyButton.style.border = 'none';
+            modifyButton.style.borderRadius = '15px';
+            modifyButton.style.cursor = 'pointer';
+            modifyButton.style.transition = 'background-color 0.3s, color 0.3s';
+            modifyButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
+            modifyButton.style.backgroundColor = '#007aff';
+            modifyButton.style.color = '#fff';
+
+            modifyButton.addEventListener('mouseenter', function () {
+                modifyButton.style.backgroundColor = '#005bb5';
+            });
+
+            modifyButton.addEventListener('mouseleave', function () {
+                modifyButton.style.backgroundColor = '#007aff';
+            });
+
+            modifyButton.addEventListener('click', function () {
+                modifyRole(roleName);
+                menu.remove(); // 点击按钮后,关闭菜单栏
+            });
+
+            menu.appendChild(modifyButton);
+        }
+
+        // 创建和添加删除角色按钮
+        if (hasDeleteRolePermission) {
+            const deleteButton = document.createElement('button');
+            deleteButton.textContent = '删除角色';
+            deleteButton.style.display = 'block';
+            deleteButton.style.width = '100%';
+            deleteButton.style.padding = '10px 20px';
+            deleteButton.style.border = 'none';
+            deleteButton.style.borderRadius = '15px';
+            deleteButton.style.cursor = 'pointer';
+            deleteButton.style.transition = 'background-color 0.3s, color 0.3s';
+            deleteButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
+            deleteButton.style.backgroundColor = '#ff3b30';
+            deleteButton.style.color = '#fff';
+
+            deleteButton.addEventListener('mouseenter', function () {
+                deleteButton.style.backgroundColor = '#c23321';
+            });
+
+            deleteButton.addEventListener('mouseleave', function () {
+                deleteButton.style.backgroundColor = '#ff3b30';
+            });
+
+            deleteButton.addEventListener('click', function () {
+                deleteRole(roleName);
+                menu.remove(); // 点击按钮后,关闭菜单栏
+            });
+
+            menu.appendChild(deleteButton);
+        }
+
+        // 如果用户没有修改或删除权限,则显示没有选项的提示
+        if (!hasUpdateRolePermission && !hasDeleteRolePermission) {
+            const noOption = document.createElement('div');
+            noOption.textContent = '没有可用的操作';
+            noOption.style.textAlign = 'center';
+            noOption.style.color = '#999';
+            menu.appendChild(noOption);
+        }
+    }
+
+    document.body.appendChild(menu);
+
+    document.addEventListener('click', function closeMenu(event) {
+        if (!menu.contains(event.target)) {
+            menu.remove();
+            document.removeEventListener('click', closeMenu);
+        }
+    });
+}
+
+
+//修改角色信息
+function modifyRole(roleName) {
+    console.log(`modifyRole called with roleName: ${roleName}`);
+    
+    fetchRoleInfo(roleName, function(roleInfo) {
+        console.log(`fetchRoleInfo returned:`, roleInfo);
+
+        if (!roleInfo) {
+            console.error('Role info is undefined or null');
+            return;
+        }
+
+        const extraInfoContent = document.getElementById('extraInfoContent');
+        if (!extraInfoContent) {
+            console.error('Element with id "extraInfoContent" not found');
+            return;
+        }
+
+        extraInfoContent.innerHTML = `
+            <h3>修改角色: ${roleInfo.Name}</h3>
+            <label for="roleName">角色名称:</label>
+            <input type="text" id="roleName" value="${roleInfo.Name}" required><br><br>
+            <label for="permissions">权限:</label><br>
+            <div id="permissions">
+                  <div>
+            <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)">
+            <label for="license">许可证</label>
+            <div id="licenseSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="generate_license" name="permissions" value="generate_license">
+                <label for="generate_license">生成许可证</label><br>
+                <input type="checkbox" id="upload_license" name="permissions" value="upload_license">
+                <label for="upload_license">上传许可证</label><br>
+                <input type="checkbox" id="read_license" name="permissions" value="read_license">
+                <label for="read_license">读取许可证</label><br>
+                <input type="checkbox" id="update_license" name="permissions" value="update_license">
+                <label for="update_license">更新许可证</label><br>
+                <input type="checkbox" id="delete_license" name="permissions" value="delete_license">
+                <label for="delete_license">删除许可证</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)">
+            <label for="user">用户</label>
+            <div id="userSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_user" name="permissions" value="create_user">
+                <label for="create_user">创建用户</label><br>
+                <input type="checkbox" id="read_user" name="permissions" value="read_user">
+                <label for="read_user">读取用户</label><br>
+                <input type="checkbox" id="update_user" name="permissions" value="update_user">
+                <label for="update_user">更新用户</label><br>
+                <input type="checkbox" id="delete_user" name="permissions" value="delete_user">
+                <label for="delete_user">删除用户</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)">
+            <label for="role">角色</label>
+            <div id="roleSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_role" name="permissions" value="create_role">
+                <label for="create_role">创建角色</label><br>
+                <input type="checkbox" id="delete_role" name="permissions" value="delete_role">
+                <label for="delete_role">删除角色</label><br>
+                <input type="checkbox" id="update_role" name="permissions" value="update_role">
+                <label for="update_role">更新角色</label><br>
+                <input type="checkbox" id="get_role" name="permissions" value="get_role">
+                <label for="get_role">获取角色</label><br>
+            </div>
+        </div>
+            </div><br><br>
+            <button onclick="saveRoleChanges('${roleInfo.Id}')">保存</button>
+        `;
+
+        console.log('Form content added to extraInfoContent');
+
+        const checkboxes = document.querySelectorAll('#permissions input[type="checkbox"]');
+
+// 遍历所有复选框
+checkboxes.forEach(checkbox => {
+    if (roleInfo.Permissions.includes(checkbox.value)) {
+        checkbox.checked = true; // 如果当前权限在roleInfo.Permissions中,则勾选
+    }
+});
+
+        const extraInfoModal = document.getElementById('extraInfoModal');
+        if (!extraInfoModal) {
+            console.error('Element with id "extraInfoModal" not found');
+            return;
+        }
+
+        extraInfoModal.style.display = 'block';  // 强制显示模态框
+        console.log('Modal should be visible now');
+    });
+}
+
+function getCheckboxOptions(selectedPermissions) {
+    const permissionMap = {
+        'generate_license': '生成许可证',
+        'upload_license': '上传许可证',
+        'read_license': '读取许可证',
+        'update_license': '修改许可证',
+        'delete_license': '删除许可证',
+        'dispat_license': '分发许可证',
+        'read_license_record': '读取许可证分发记录',
+      //  'get_user_info': '获取用户信息',
+        'create_user': '创建用户',
+        'read_user': '读取用户',
+        'update_user': '更新用户',
+        'delete_user': '删除用户',
+        'create_role': '创建角色',
+        'delete_role': '删除角色',
+        'update_role': '更新角色',
+        'get_role': '获取角色'
+    };
+
+    return Object.keys(permissionMap).map(permission => `
+        <div>
+            <input type="checkbox" id="${permission}" name="permissions" value="${permission}" ${selectedPermissions.includes(permission) ? 'checked' : ''}>
+            <label for="${permission}">${permissionMap[permission]}</label>
+        </div>
+    `).join('');
+}
+
+
+
+
+
+function fetchRoleInfo(roleName, callback) {
+    console.log(`fetchRoleInfo called with roleName: ${roleName}`);
+    
+    fetch('http://127.0.0.1:8080/api/admin/GetRoles', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ Name: roleName })
+    })
+    .then(response => {
+        console.log('fetchRoleInfo response received', response);
+        return response.json();
+    })
+    .then(data => {
+        console.log('fetchRoleInfo data received', data);
+
+        // 直接从 data.data 获取角色信息
+        if (data && data.data) {
+            console.log('Role info found:', data.data);
+            callback(data.data);  // 直接返回 data.data 而不是 data.data[roleName]
+        } else {
+            console.error('Role not found or unexpected data structure', data);
+            callback(null);  // 如果角色信息未找到,返回 null
+        }
+    })
+    .catch(error => {
+        console.error('Error in fetchRoleInfo:', error);
+        callback(null);  // 捕获异常情况
+    });
+}
+
+function getPermissionsOptions(selectedPermissions) {
+    const permissionMap = {
+        'generate_license': '生成许可证',
+        'upload_license': '上传许可证',
+        'read_license': '读取许可证',
+        'update_license': '修改许可证',
+        'delete_license': '删除许可证',
+        'dispat_license': '分发许可证',
+        'read_license_record': '读取许可证分发记录',
+        //'get_user_info': '获取用户信息',
+        'create_user': '创建用户',
+        'read_user': '读取用户',
+        'update_user': '更新用户',
+        'delete_user': '删除用户',
+        'create_role': '创建角色',
+        'delete_role': '删除角色',
+        'update_role': '更新角色',
+        'get_role': '获取角色'
+    };
+    
+    return Object.keys(permissionMap).map(permission => `
+        <option value="${permission}" ${selectedPermissions.includes(permission) ? 'selected' : ''}>
+            ${permissionMap[permission]}
+        </option>
+    `).join('');
+}
+
+function saveRoleChanges(roleId) {
+    const updatedRoleName = document.getElementById('roleName').value.trim();
+    const selectedPermissions = Array.from(document.querySelectorAll('#permissions input[type="checkbox"]:checked'))
+                                    .map(checkbox => checkbox.value)
+                                    .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类
+
+    if (!updatedRoleName) {
+        alert('角色名称不能为空!');
+        return;
+    }
+
+    const updateRole = {
+        Id: parseInt(roleId, 10),  // 确保 roleId 被传递并转换为整数
+        Name: updatedRoleName,
+        Permissions: selectedPermissions
+    };
+
+    fetch('http://127.0.0.1:8080/api/admin/UpdateRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(updateRole)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色更新成功!');
+            fetchRoles(); // 刷新角色列表
+            closeModal('extraInfoModal'); // 关闭信息栏
+        } else {
+            alert('角色更新失败:' + data.error);
+        }
+    });
+}
+
+//删除角色
+function deleteRole(roleName) {
+    console.log(`deleteRole called for role: ${roleName}`);
+    
+    const confirmed = confirm(`确认删除角色: ${roleName} 吗?`);
+    if (!confirmed) {
+        return;
+    }
+
+    fetch('http://127.0.0.1:8080/api/admin/DeleteRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+            name: roleName  // 将角色名称传递给后端
+        })
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色删除成功!');
+            fetchRoles();  // 刷新角色列表
+        } else {
+            alert('角色删除失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        console.error('Error deleting role:', error);
+        alert('删除角色时发生错误,请稍后再试。');
+    });
+}
+
+document.getElementById('createRoleButton').addEventListener('click', function() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+    extraInfoContent.innerHTML = `
+        <h3>创建新角色</h3>
+        <label for="newRoleName">角色名称:</label>
+        <input type="text" id="newRoleName" required><br><br>
+          <label for="newPermissions">权限:</label><br>
+ <div id="newPermissions">
+        <div>
+            <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)">
+            <label for="license">许可证</label>
+            <div id="licenseSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="generate_license" name="permissions" value="generate_license">
+                <label for="generate_license">生成许可证</label><br>
+                <input type="checkbox" id="upload_license" name="permissions" value="upload_license">
+                <label for="upload_license">上传许可证</label><br>
+                <input type="checkbox" id="read_license" name="permissions" value="read_license">
+                <label for="read_license">读取许可证</label><br>
+                <input type="checkbox" id="update_license" name="permissions" value="update_license">
+                <label for="update_license">更新许可证</label><br>
+                <input type="checkbox" id="delete_license" name="permissions" value="delete_license">
+                <label for="delete_license">删除许可证</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)">
+            <label for="user">用户</label>
+            <div id="userSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_user" name="permissions" value="create_user">
+                <label for="create_user">创建用户</label><br>
+                <input type="checkbox" id="read_user" name="permissions" value="read_user">
+                <label for="read_user">读取用户</label><br>
+                <input type="checkbox" id="update_user" name="permissions" value="update_user">
+                <label for="update_user">更新用户</label><br>
+                <input type="checkbox" id="delete_user" name="permissions" value="delete_user">
+                <label for="delete_user">删除用户</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)">
+            <label for="role">角色</label>
+            <div id="roleSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_role" name="permissions" value="create_role">
+                <label for="create_role">创建角色</label><br>
+                <input type="checkbox" id="delete_role" name="permissions" value="delete_role">
+                <label for="delete_role">删除角色</label><br>
+                <input type="checkbox" id="update_role" name="permissions" value="update_role">
+                <label for="update_role">更新角色</label><br>
+                <input type="checkbox" id="get_role" name="permissions" value="get_role">
+                <label for="get_role">获取角色</label><br>
+            </div>
+        </div>
+    </div><br><br>
+    <button onclick="createNewRole()">创建</button>
+</div>
+
+     
+    `;
+    document.getElementById('extraInfoModal').style.display = 'block';
+});
+
+
+function toggleSubPermissions(category, checkbox) {
+    const subPermissions = document.querySelectorAll(`#${category}SubPermissions input[type="checkbox"]`);
+    subPermissions.forEach(subCheckbox => {
+        subCheckbox.checked = checkbox.checked;
+    });
+}
+
+function createNewRole() {
+    const newRoleName = document.getElementById('newRoleName').value.trim();
+    const selectedPermissions = Array.from(document.querySelectorAll('#newPermissions input[type="checkbox"]:checked'))
+                                    .map(checkbox => checkbox.value)
+                                    .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类
+
+    if (!newRoleName) {
+        alert('角色名称不能为空!');
+        return;
+    }
+
+    const newRole = {
+        Name: newRoleName,
+        Permissions: selectedPermissions
+    };
+
+    fetch('http://127.0.0.1:8080/api/admin/CreateRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(newRole)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色创建成功!');
+            fetchRoles(); // 刷新角色列表
+            closeModal('extraInfoModal'); // 关闭信息栏
+        } else {
+            alert('角色创建失败:' + data.error);
+        }
+    });
+}
+
+//显示用户信息
+function showEditUserForm() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+
+    // 清空之前的内容
+    extraInfoContent.innerHTML = '';
+
+    // 创建表单
+    const form = document.createElement('form');
+    form.id = 'editUserForm';
+    form.style.width = '400px'; // 增加表单宽度
+
+    form.innerHTML = `
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="username" style="flex: 0 0 80px;">用户名:</label>
+            <input type="text" id="username" name="username" value="${selectedRowData.Username}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="telephone" style="flex: 0 0 80px;">电话:</label>
+            <input type="text" id="telephone" name="telephone" value="${selectedRowData.Telephone}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="email" style="flex: 0 0 80px;">邮箱:</label>
+            <input type="email" id="email" name="email" value="${selectedRowData.Email}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="role" style="flex: 0 0 80px;">权限:</label>
+            <select id="role" name="role" style="flex: 1;" required></select>
+        </div>
+
+        <button type="button" onclick="saveUserChanges()" style="width: 100%; background-color: #007bff; color: white; border: none; padding: 10px; border-radius: 5px;">保存</button>
+    `;
+
+    // 将表单添加到弹出框内容中
+    extraInfoContent.appendChild(form);
+
+    // 获取角色列表并填充到选择框中
+    fetch('http://127.0.0.1:8080/api/admin/GetRoleNames', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const roleSelect = document.getElementById('role');
+        data.roles.forEach(role => {
+            const option = document.createElement('option');
+            option.value = role;
+            option.textContent = role;
+            if (selectedRowData.Role === role) {
+                option.selected = true;
+            }
+            roleSelect.appendChild(option);
+        });
+    })
+    .catch(error => console.error('Error fetching roles:', error));
+}
+
+
+function saveUserChanges() {
+            const form = document.getElementById('editUserForm');
+            const formData = new FormData(form);
+            const updatedUser = {
+                Username: formData.get('username'),
+                Telephone: formData.get('telephone'),
+                Email: formData.get('email'),
+                Role: formData.get('role')
+            };
+
+            fetch(`http://127.0.0.1:8080/api/admin/updateUser`, {
+                method: 'POST',
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({ ...updatedUser, Id: selectedRowData.Id })
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success) {
+                    alert('用户信息更新成功!');
+                    fetchUsers();
+                    closeModal('extraInfoModal');
+                } else {
+                    alert('用户信息更新失败:' + data.error);
+                }
+            });
+        }
+
+//用户个人信息
+function toggleUserInfo() {
+    const userModal = document.getElementById('userModal');
+    const userButton = document.getElementById('username');
+    const rect = userButton.getBoundingClientRect();
+    const modalWidth = 300; // 信息栏的宽度
+    const windowWidth = window.innerWidth; // 浏览器窗口的宽度
+
+    if (userModal.style.display === 'none' || userModal.style.display === '') {
+        fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            const userInfoContent = document.getElementById('userInfoContent');
+            let power;
+            switch (data.data.Role) {
+                case 'admin':
+                    power = '至高无上的主';
+                    break;
+                case 'supportRole':
+                    power = '运维';
+                    break;
+                case 'guest':
+                    power = '访客';
+                    break;
+                default:
+                    power = data.data.Role;
+            }
+
+            userInfoContent.innerHTML = `
+               <h2> 个人信息</h2>
+               <div class="apple-modal-content">
+                   <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p>
+                   <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p>
+                   <p class="apple-modal-text"><strong>邮箱:</strong> ${data.data.Email}</p>
+                   <p class="apple-modal-text"><strong>电话:</strong> ${data.data.Telephone}</p>
+                   <p class="apple-modal-text"><strong>权限:</strong> ${power}</p>
+               </div>
+            `;
+
+            // 设置模态框位置
+            userModal.style.top = `${rect.bottom + window.scrollY + 10}px`;
+            const leftPosition = rect.right + window.scrollX + 20; // 右侧位置
+            const rightEdge = leftPosition + modalWidth;
+
+            if (rightEdge > windowWidth) {
+                const leftEdge = rect.left + window.scrollX - modalWidth - 20;
+                userModal.style.left = `${Math.max(20, leftEdge)}px`;
+            } else {
+                userModal.style.left = `${leftPosition}px`;
+            }
+
+            userModal.style.display = 'block';
+            userModal.style.opacity = '0'; // 先设置透明度为0
+            setTimeout(() => {
+                userModal.style.opacity = '1'; // 然后慢慢显示
+            }, 0); // 延迟一帧显示
+
+            userModal.style.transition = 'opacity 0.3s ease, top 0.3s ease, left 0.3s ease';
+
+            // 添加全局点击监听器
+            document.addEventListener('click', handleClickOutsideModal);
+        });
+
+    } else {
+        closeUserInfo();
+    }
+}
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+function handleClickOutsideModal(event) {
+    const userModal = document.getElementById('userModal');
+    if (!userModal.contains(event.target) && event.target.id !== 'username') {
+        closeUserInfo();
+    }
+}
+
+
+//用户退出
+function logout() {
+            localStorage.removeItem('Authorization');
+            window.location.href = '/';
+        }
+
+// 添加到每个模态框的 JavaScript 部分
+document.addEventListener('DOMContentLoaded', function() {
+    const modals = document.querySelectorAll('.modal');
+
+    modals.forEach(modal => {
+        modal.addEventListener('click', function(event) {
+            // 判断是否点击的是 modal 的背景
+            if (event.target === modal) {
+                modal.style.display = 'none';
+            }
+        });
+    });
+});
+
+function showUserManagement() {
+    document.getElementById('table-container').style.display = 'none';
+    document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面
+    document.getElementById('user-management').style.display = 'block';
+    
+    // 检查用户是否有 create_user 权限
+    const hasCreateUserPermission = userPermissions.includes('create_user');
+
+    // 获取添加用户按钮元素
+    const addUserButton = document.getElementById('addUserButton');
+
+    // 根据权限显示或隐藏添加用户按钮
+    if (hasCreateUserPermission) {
+        addUserButton.style.display = 'block';
+    } else {
+        addUserButton.style.display = 'none';
+    }
+
+    // 加载用户列表
+    fetchUsers();
+        }
+
+function showTable() {
+    document.getElementById('user-management').style.display = 'none';
+    document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面
+    document.getElementById('table-container').style.display = 'block';
+        }
+
+function toggleSidebar() {
+    const sidebar = document.getElementById('sidebar');
+    const content = document.getElementById('content');
+    sidebar.classList.toggle('hidden');
+    content.classList.toggle('expanded');
+
+    const toggleButton = document.querySelector('.toggle-sidebar');
+    if (sidebar.classList.contains('hidden')) {
+        toggleButton.innerHTML = '>';  // 当侧边栏隐藏时,显示右箭头
+    } else {
+        toggleButton.innerHTML = '<';  // 当侧边栏显示时,显示左箭头
+    }
+}
+
+
+
+
+
+
+
+ function fetchUsername() {
+    fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        document.getElementById('username').textContent = data.data.Username;
+        currentUserRole = data.data.Role; // 存储当前用户的角色
+        currentUserName = data.data.Username
+        // 使用获取到的角色,调用获取权限的接口
+        fetchPermissionsByRole(currentUserRole)
+            .then(() => {
+                //fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+                // 检查用户是否有 upload_license 权限
+                const hasUploadLicensePermission = userPermissions.includes('upload_license');
+
+                // 获取上传按钮元素
+                const uploadButton = document.querySelector('.upload-button');
+
+                // 根据权限显示或隐藏上传按钮
+                if (hasUploadLicensePermission) {
+                    uploadButton.style.display = 'inline-block'; // 显示按钮
+                } else {
+                    uploadButton.style.display = 'none'; // 隐藏按钮
+                }
+            });
+    });
+}
+
+function fetchPermissionsByRole(role) {
+    return fetch(`http://127.0.0.1:8080/api/admin/GetSelfRoles`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ name: role })
+    })
+    .then(response => response.json())
+    .then(data => {
+        userPermissions = data.data.Permissions; // 获取用户的权限数组
+        console.log('userPermissions:', userPermissions);
+        
+        // 定义权限类别
+        const licensePermissions = ['upload_license', 'read_license'];
+        const userPermissionsCheck = [ 'create_user', 'read_user', 'update_user', 'delete_user'];
+        const rolePermissions = ['create_role', 'delete_role', 'update_role', 'get_role'];
+
+        const hasLicenseAccess = licensePermissions.some(permission => userPermissions.includes(permission));
+        const hasUserManagementAccess = userPermissionsCheck.some(permission => userPermissions.includes(permission));
+        const hasRoleManagementAccess = rolePermissions.some(permission => userPermissions.includes(permission));
+
+        // 根据权限渲染菜单并显示初始页面
+        renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess);
+    });
+}
+
+
+
+
+function renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess) {
+    const sidebar = document.querySelector('.sidebar');
+
+    // 清空现有菜单项
+    sidebar.innerHTML = '';
+
+    let initialPageShown = false;
+
+    // 动态添加菜单项并确定初始显示的页面
+    if (hasLicenseAccess) {
+        const licenseButton = document.createElement('button');
+        licenseButton.textContent = 'License 管理';
+        licenseButton.onclick = showTable;
+        sidebar.appendChild(licenseButton);
+
+        if (!initialPageShown) {
+            showTable(); // 如果有License权限,先显示License页面
+            initialPageShown = true;
+        }
+    }
+
+    if (hasUserManagementAccess) {
+        const userManagementButton = document.createElement('button');
+        userManagementButton.textContent = '用户管理';
+        userManagementButton.onclick = showUserManagement;
+        sidebar.appendChild(userManagementButton);
+
+        if (!initialPageShown) {
+            showUserManagement(); // 如果没有License权限,但有用户管理权限,显示用户管理页面
+            initialPageShown = true;
+        }
+    }
+
+    if (hasRoleManagementAccess) {
+        const roleManagementButton = document.createElement('button');
+        roleManagementButton.textContent = '角色管理';
+        roleManagementButton.onclick = showRoleManagement;
+        sidebar.appendChild(roleManagementButton);
+
+        if (!initialPageShown) {
+            showRoleManagement(); // 如果没有License和用户管理权限,但有角色管理权限,显示角色管理页面
+            initialPageShown = true;
+        }
+    }
+
+    if (!initialPageShown && sidebar.firstChild) {
+        sidebar.firstChild.click(); // 如果没有优先的权限页面,则显示菜单中的第一个页面
+    }
+}
+
+        // 页面初始化时调用 fetchUsername 函数
+        fetchUsername();
+        //fetchApplications(currentPage, pageSize);
+    </script>
+</body>
+</html>

+ 3767 - 0
static/license_info/license_info copy 4.html

@@ -0,0 +1,3767 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>License 分发管理</title>
+    <style>
+        /* 保持样式不变 */
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+            background-color: #f8f8f8;
+            margin: 0;
+            padding: 0;
+            display: flex;
+        }
+header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 20px;
+    background-color: #1169ff;
+    color: white;
+    width: 100%;
+    margin: 0; /* 移除上下左右的空隙 */
+    box-sizing: border-box; /* 确保padding不会影响元素的宽度 */
+    border: 4px solid #1169ff; /* 确保红框颜色填满 */
+    border-width: 4px 0 4px 0; /* 只显示上下的红框颜色 */
+    border-radius: 10px; /* 设置圆角 */
+  
+}
+
+h1 {
+            font-size: 24px;
+            font-weight: 600;
+            margin: 0;
+        }
+
+    .CaptureLicenseOnce-button {
+   background-color: white;
+    color: #007aff;
+    border: 2px solid #007aff;
+    padding: 10px 20px;
+    border-radius: 10px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: none;
+    transition: background-color 0.3s, color 0.3s;
+    float: right; /* 将按钮移动到左侧 */
+}
+
+.CaptureLicenseOnce-button:hover {
+    background-color: #0eb3ff;
+    color: white;
+}
+        
+      
+/* 扁平风格的选择框 */
+.flat-select {
+    background-color: transparent; /* 背景色透明 */
+    border: 1px solid #007aff; /* 边框颜色与按钮一致 */
+    border-radius: 15px; /* 圆角边框 */
+    padding: 5px 10px; /* 内边距 */
+    font-size: 16px; /* 字体大小 */
+    color: #007aff; /* 文字颜色 */
+    outline: none; /* 移除默认的焦点样式 */
+    appearance: none; /* 移除默认的下拉箭头样式 */
+    -webkit-appearance: none; /* 对部分浏览器的兼容性处理 */
+    -moz-appearance: none; /* 对部分浏览器的兼容性处理 */
+    cursor: pointer; /* 鼠标指针样式 */
+    margin-left: 10px; /* 添加左边距,使选择框与前面的元素有些距离 */
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */
+}
+
+/* 选择框在悬停时的效果 */
+.flat-select:hover {
+    background-color: #007aff; /* 背景色变为蓝色 */
+    color: white; /* 文字颜色变为白色 */
+}
+
+/* 选择框在聚焦时的效果 */
+.flat-select:focus {
+    background-color: #e0f7ff; /* 聚焦时的背景颜色 */
+    border-color: #0056b3; /* 聚焦时的边框颜色 */
+}
+
+/* 添加下拉箭头的样式 */
+.flat-select::after {
+    content: '▼'; /* 使用字符作为下拉箭头 */
+    position: absolute;
+    right: 10px;
+    pointer-events: none; /* 确保下拉箭头不会遮挡选择框 */
+}
+
+
+/* 扁平圆角风格的按钮样式 */
+.flat-rounded-button {
+    background-color: white;
+    color: #007aff;
+    border: 2px solid #007aff;
+    padding: 10px 20px;
+    border-radius: 15px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s;
+    margin: 5px; /* 添加按钮之间的间距 */
+}
+
+/* 悬停时的效果 */
+.flat-rounded-button:hover {
+    background-color: #0eb3ff;
+    color: white;
+}
+
+/*lic 展示页 主行展开后变化*/
+.expanded-row {
+    background-color: #0eb3ff; /* 展开时的背景颜色 */
+    border-color: #04aa9c; /* 展开时的边框颜色 */
+    border-width: 4px; /* 边框宽度 */
+    border-radius: 35px; /* 边框圆角 */
+    transition: all 0.2s ease; /* 添加过渡效果 */
+}
+
+/*苹果风格模态框*/
+.apple-modal-content {
+    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+    padding: 20px;
+    border-radius: 12px;
+    background-color: white;
+    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+    margin-bottom: 20px;
+    min-width: 300px; /* 添加最小宽度 */
+}
+
+.apple-modal-title {
+    font-size: 24px;
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 10px;
+}
+
+.apple-modal-subtitle {
+    font-size: 20px;
+    font-weight: 500;
+    color: #555;
+    margin-top: 20px;
+    margin-bottom: 10px;
+}
+/* 苹果风格的文字样式 */
+.apple-modal-text {
+    font-size: 16px;
+    color: #555;
+    line-height: 1.6;
+    margin-bottom: 10px;
+    
+}
+
+/* 强调部分 */
+.apple-modal-text strong {
+    color: #333;
+}
+
+/* 苹果风格的模态框关闭按钮 */
+
+.apple-close {
+    color: #aaa;
+    font-size: 24px; /* 调整字体大小 */
+    font-weight: bold;
+    cursor: pointer;
+    transition: color 0.3s;
+}
+
+.apple-close:hover {
+    color: black;
+}
+
+/* 苹果风格的退出按钮 */
+.apple-logout-button {
+    background-color: #007aff; /* 苹果风格的蓝色 */
+    color: white;
+    border: none;
+    padding: 8px 16px; /* 减小内边距,使按钮更小 */
+    border-radius: 10px; /* 圆角稍微减小 */
+    font-size: 14px; /* 调整字体大小 */
+    font-weight: 500;
+    cursor: pointer;
+    transition: background-color 0.3s, transform 0.3s;
+}
+
+.apple-logout-button:hover {
+    background-color: #005bb5; /* 悬停时按钮颜色变深 */
+    transform: scale(1.05); /* 悬停时按钮略微放大 */
+}
+
+.apple-logout-button:active {
+    background-color: #003e7e; /* 点击时按钮颜色更深 */
+    transform: scale(0.98); /* 点击时按钮略微缩小 */
+}
+
+
+.upload-button, .user-button {
+            background-color: white;
+            color: #007aff;
+            border: none;
+            padding: 10px 20px;
+            border-radius: 10px;
+            cursor: pointer;
+            font-size: 16px;
+            font-weight: 500;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            transition: background-color 0.3s;
+        }
+ .upload-button:hover, .user-button:hover {
+            background-color: #f0f0f0;
+        }
+        .sidebar {
+            width: 200px;
+            background-color: #f1f1f1;
+            padding: 20px;
+            box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
+            height: 100vh;
+            transition: transform 0.3s ease;
+        }
+        .sidebar.hidden {
+            transform: translateX(-100%);
+        }
+        .sidebar button {
+            width: 100%;
+            padding: 10px;
+            margin-bottom: 10px;
+            background-color: white;
+            color: #007aff;
+            border: none;
+            border-radius: 10px;
+            cursor: pointer;
+            font-size: 16px;
+            font-weight: 500;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            transition: background-color 0.3s;
+        }
+        .sidebar button:hover {
+            background-color: #e0e0e0;
+        }
+        .content {
+            flex-grow: 1;
+            padding: 20px;
+            transition: margin-left 0.3s ease;
+        }
+        .content.expanded {
+            margin-left: -200px;
+        }
+        .toggle-sidebar {
+    position: fixed;
+    top: 50%; /* 垂直居中 */
+    transform: translateY(-50%); /* 调整为居中对齐 */
+    left: 0; /* 靠左对齐 */
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 10px;
+    cursor: pointer;
+    border-radius: 0 10px 10px 0; /* 右侧圆角,左侧保持平直 */
+    width: 30px; /* 长条形箭头的宽度 */
+    height: 60px; /* 长条形箭头的高度 */
+    z-index: 1000;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: all 0.3s ease; /* 添加动效 */
+}
+
+.sidebar.hidden + .content .toggle-sidebar {
+            left: 0;
+            transform: translateX(0) translateY(-50%);
+        }
+
+
+ /* 通用按钮样式 */
+.license-status-btn {
+    display: inline-block;
+    padding: 5px 15px;
+    font-size: 14px;
+    font-weight: bold;
+    color: white;
+    text-align: center;
+    border-radius: 15px; /* 圆角样式 */
+    cursor: pointer;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+    transition: background-color 0.3s;
+    border: none; /* 移除按钮边框 */
+}
+
+/* 分发按钮样式 */
+.license-status-btn.distribute {
+    background-color: #007bff; /* 蓝色背景 */
+}
+
+.license-status-btn.distribute:hover {
+    background-color: #0056b3; /* 悬停时的颜色 */
+}
+
+/* 生成按钮样式 */
+.license-status-btn.generate {
+    background-color: #ffc107; /* 黄色背景 */
+}
+
+.license-status-btn.generate:hover {
+    background-color: #e0a800; /* 悬停时的颜色 */
+}
+
+/* 默认状态下的箭头图标 */
+.arrow-icon {
+    width: 10px;
+    height: 10px;
+    border: solid #007aff;
+    border-width: 0 3px 3px 0;
+    display: inline-block;
+    padding: 3px;
+    transform: rotate(45deg); /* 初始方向向下 */
+    transition: transform 0.3s ease; /* 添加旋转过渡效果 */
+    cursor: pointer;
+}
+
+/* 当行展开时旋转箭头图标 */
+.rotate-arrow {
+    transform: rotate(-135deg); /* 旋转方向向上 */
+}
+
+
+
+/*分发历史样式*/
+#distributionHistoryModal .centered-modal-content {
+    background-color: #ffffff;
+    border: none;
+    border-radius: 15px;
+    padding: 20px;
+    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+    text-align: center;
+    width: 30%;  /* 设置宽度为屏幕的80% */
+    max-width: 90%;  /* 最大宽度设置为90%屏幕宽度 */
+    height: auto;  /* 高度自适应内容 */
+    max-height: 80vh;  /* 设置最大高度为屏幕的80% */
+    overflow-y: auto;  /* 如果内容超出则添加垂直滚动条 */
+    overflow-x: hidden;  /* 水平不出现滚动条 */
+    margin: 0 auto;  /* 居中显示 */
+}
+
+/* lic查看详细按钮样式 */
+.license-status-btn.view-details {
+    background-color: #add8e6; /* 浅蓝色背景 */
+    color: white; /* 白色文字 */
+    border: none; /* 移除按钮边框 */
+    padding: 8px 16px; /* 调整内边距,与“生成”按钮保持一致 */
+    border-radius: 20px; /* 调整圆角,确保形状一致 */
+    cursor: pointer;
+    font-size: 14px; /* 调整字体大小,确保一致 */
+    font-weight: 500; /* 字体权重,确保一致 */
+    margin-left: 10px; /* 与其他按钮的间隔 */
+    transition: background-color 0.3s, color 0.3s; /* 添加过渡效果 */
+}
+
+.license-status-btn.view-details:hover {
+    background-color: #87ceeb; /* 悬停时颜色变深 */
+}
+
+
+
+
+/* 表格样式 */
+/* 表格容器 */
+/* 表格容器 */
+
+table {
+    width: 100%;
+    border-collapse: separate;
+    border-spacing: 0 4px; /* 设置行间距为4px */
+   /*  background-color: transparent; 使表格背景透明,突出行间距效果 */
+    margin: 20px 0;
+}
+
+th, td {
+    padding: 15px 20px; /* 设置单元格内边距 */
+    text-align: left;
+    font-size: 16px;
+  /*   background-color: white; 单元格背景色 */
+   
+}
+
+
+/* 鼠标悬停时改变边框颜色 */
+tr:hover {
+    background-color: #e6f7ff; /* 设置悬停时的背景颜色 */
+    border-color: #1169ff; /* 设置悬停时的边框颜色 */
+    border-width: 4px; /* 设置悬停时的边框大小 */
+    border-radius: 15px; /* 设置悬停时的圆角 */
+}
+th {
+    background-color: #f8f8f8; /* 表头背景色 */
+    font-weight: bold;
+    color: #333;
+}
+
+td {
+    color: #555;
+}
+
+/* 表格行样式 */
+tr {
+    background-color: white; /* 每行背景色 */
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 设置阴影效果 */
+    border-radius: 10px; /* 设置每行的圆角 */
+    overflow: hidden; /* 确保圆角效果生效 */
+    border: 2px solid transparent; /* 默认边框为透明 */
+    transition: all 0.3s ease; /* 添加过渡效果 */
+    
+}
+/* 确保单元格也适应行的圆角 */
+tr:first-child td:first-child {
+    border-top-left-radius: 10px;
+}
+tr:first-child td:last-child {
+    border-top-right-radius: 10px;
+}
+tr:last-child td:first-child {
+    border-bottom-left-radius: 10px;
+}
+tr:last-child td:last-child {
+    border-bottom-right-radius: 10px;
+}
+
+
+
+
+
+/*添加用户样式*/
+.flat-rounded-input {
+    width: calc(100% - 40px); /* 与其他输入框一致的宽度 */
+    padding: 15px 20px;  /* 更大的内边距 */
+    font-size: 18px;  /* 更大的字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆角边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+.flat-rounded-input:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+.flat-rounded-button {
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 15px 20px;
+    border-radius: 25px;
+    cursor: pointer;
+    font-size: 18px;
+    font-weight: bold;
+    box-shadow: none; /* 移除阴影效果 */
+    transition: background-color 0.3s, color 0.3s;
+}
+
+.flat-rounded-button:hover {
+    background-color: #005bb5;
+}
+.form-group {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+}
+
+.form-group label {
+    flex: 0 0 80px; /* 固定标签宽度 */
+    text-align: right;
+    margin-right: 10px; /* 标签与输入框之间的间距 */
+}
+
+.form-group input {
+    flex: 1; /* 输入框占据剩余空间 */
+}
+
+
+
+/* 分页按钮样式 */
+.pagination button {
+    padding: 10px 20px;
+    margin: 0 5px;
+    cursor: pointer;
+    border: none;
+    border-radius: 15px;
+    background-color: #007aff;
+    color: white;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: background-color 0.3s;
+}
+
+.pagination button:disabled {
+    background-color: #b0c4de;
+    cursor: not-allowed;
+}
+
+.pagination button:not(:disabled):hover {
+    background-color: #005bb5;
+}
+
+
+
+
+        .modal {
+            display: none;
+            position: fixed;
+            z-index: 1;
+            left: 0;
+            top: 0;
+            width: 100%;
+            height: 100%;
+            overflow: auto;
+            background-color: rgba(0, 0, 0, 0.4);
+        }
+.modal-content {
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background-color: #fefefe;
+            padding: 20px;
+            border: 1px solid #888;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            max-width: 100%;
+            max-height: 90%;
+
+            overflow-y: auto;
+        }
+
+
+/*修改license信息的样式*/
+.modify-license-modal-content {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background-color: #fefefe;
+    padding: 50px;
+    border: 1px solid #888;
+    border-radius: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    width: 400px;
+    height: 80%; /* 设置为你希望的高度 */
+    overflow-y: auto;
+    text-align: center;
+}
+
+.modify-license-modal-content input[type="number"],
+.modify-license-modal-content input[type="date"],
+.modify-license-modal-content input[type="text"],
+.modify-license-modal-content input[type="email"],
+.modify-license-modal-content input[type="password"],
+.modify-license-modal-content textarea,
+.modify-license-modal-content select {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 更大内边距 */
+    font-size: 18px;  /* 更大字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆形边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色更浅 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+.modify-license-modal-content input[type="number"]:focus,
+.modify-license-modal-content input[type="date"]:focus,
+.modify-license-modal-content input[type="text"]:focus,
+.modify-license-modal-content input[type="email"]:focus,
+.modify-license-modal-content input[type="password"]:focus,
+.modify-license-modal-content textarea:focus,
+.modify-license-modal-content select:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+.modify-license-modal-content button {
+    width: 100%;
+    padding: 15px 20px;
+    font-size: 18px;
+    font-weight: bold;
+    color: white;
+    background-color: #007aff;
+    border: none;
+    border-radius: 25px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.modify-license-modal-content button:hover {
+    background-color: #005bb5;  /* 鼠标悬停时的颜色变化 */
+}
+
+.modify-license-modal-content .close {
+    color: #aaa;
+    float: right;
+    font-size: 30px;
+    font-weight: bold;
+}
+
+.modify-license-modal-content .close:hover,
+.modify-license-modal-content .close:focus {
+    color: black;
+    text-decoration: none;
+    cursor: pointer;
+}
+
+.modify-license-modal-content .extra-info {
+    padding: 20px;
+    background-color: white;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    margin-top: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    line-height: 1.5; /* 增加行高,保证字段间距 */
+}
+
+
+
+.modal-content input[type="number"] {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 与其他输入框的内边距一致 */
+    font-size: 18px;  /* 与其他输入框的字体大小一致 */
+    border: 2px solid #e0e0e0;  /* 与其他输入框的边框颜色一致 */
+    border-radius: 25px;  /* 与其他输入框的圆角一致 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 与其他输入框的背景色一致 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 与其他输入框的过渡效果一致 */
+}
+
+.modal-content input[type="number"]:focus {
+    border-color: #007aff;  /* 与其他输入框获得焦点时的边框颜色一致 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 与其他输入框获得焦点时的阴影效果一致 */
+    outline: none;  /* 移除默认的焦点轮廓 */
+}
+
+
+.modal-content input[type="date"] {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 与其他输入框的内边距一致 */
+    font-size: 18px;  /* 与其他输入框的字体大小一致 */
+    border: 2px solid #e0e0e0;  /* 与其他输入框的边框颜色一致 */
+    border-radius: 25px;  /* 与其他输入框的圆角一致 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 与其他输入框的背景色一致 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 与其他输入框的过渡效果一致 */
+}
+
+.modal-content input[type="date"]:focus {
+    border-color: #007aff;  /* 与其他输入框获得焦点时的边框颜色一致 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 与其他输入框获得焦点时的阴影效果一致 */
+    outline: none;  /* 移除默认的焦点轮廓 */
+}
+
+
+        /* 输入框样式 */
+.modal-content input[type="text"],
+.modal-content input[type="email"],
+.modal-content input[type="password"],
+.modal-content textarea,
+.modal-content select {
+    width: calc(100% - 40px);
+    padding: 15px 20px;  /* 更大内边距 */
+    font-size: 18px;  /* 更大字体 */
+    border: 2px solid #e0e0e0;  /* 边框颜色 */
+    border-radius: 25px;  /* 圆形边框 */
+    box-sizing: border-box;
+    margin-bottom: 20px;
+    background-color: #f8f8f8;  /* 背景色更浅 */
+    transition: border-color 0.3s, box-shadow 0.3s;  /* 添加动画效果 */
+}
+
+/* 输入框聚焦时的样式 */
+.modal-content input[type="text"]:focus,
+.modal-content input[type="email"]:focus,
+.modal-content input[type="password"]:focus,
+.modal-content textarea:focus,
+.modal-content select:focus {
+    border-color: #007aff;  /* 聚焦时的边框颜色 */
+    box-shadow: 0 0 8px rgba(0, 122, 255, 0.2);  /* 聚焦时的阴影效果 */
+    outline: none;  /* 去掉默认的聚焦样式 */
+}
+
+
+
+/* 按钮样式 */
+.modal-content button {
+    width: 100%;
+    padding: 15px 20px;
+    font-size: 18px;
+    font-weight: bold;
+    color: white;
+    background-color: #007aff;
+    border: none;
+    border-radius: 25px;
+    cursor: pointer;
+    transition: background-color 0.3s;
+}
+
+.modal-content button:hover {
+    background-color: #005bb5;  /* 鼠标悬停时的颜色变化 */
+}
+
+        .close {
+            color: #aaa;
+            float: right;
+            font-size: 30px;
+            font-weight: bold;
+            text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
+        }
+        .close:hover {
+    color: #000; /* 悬停时颜色变为黑色 */
+    transform: scale(1.1); /* 悬停时稍微放大 */
+}
+
+        .close:focus {
+            color: black;
+            text-decoration: none;
+            cursor: pointer;
+        }
+        .extra-info {
+    padding: 20px;
+    background-color: white;
+    border: 1px solid #ddd;
+    border-radius: 10px;
+    margin-top: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    line-height: 1.5; /* 增加行高,保证字段间距 */
+}
+.extra-info p {
+    margin: 10px 0; /* 每个字段的间距 */
+    word-wrap: break-word; /* 允许在单词内断行 */
+    word-break: break-all; /* 允许在任何字符处断行 */
+    white-space: pre-wrap; /* 保持空格和换行符 */
+    border-bottom: 1px solid #f0f0f0; /* 每个字段下方加上细线 */
+    padding-bottom: 8px; /* 加大下方内边距 */
+}
+
+/* 修改运维邮箱和销售邮箱的勾选框样式 */
+#emailInputs {
+    display: flex;
+    flex-direction: column; /* 确保每一行都垂直排列 */
+    gap: 10px; /* 增加每行之间的间距 */
+}
+
+#emailInputs div {
+    display: flex;
+    align-items: center; /* 垂直居中 */
+}
+
+#emailInputs input[type="checkbox"] {
+    appearance: none;
+    background-color: #fff;
+    margin: 0;
+    font: inherit;
+    color: #007aff;
+    width: 1.15em;
+    height: 1.15em;
+    border: 0.15em solid #007aff;
+    border-radius: 0.15em;
+    transform: translateY(-0.075em);
+    display: grid;
+    place-content: center;
+}
+
+#emailInputs input[type="checkbox"]::before {
+    content: "";
+    width: 0.65em;
+    height: 0.65em;
+    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 22%, 80% 0%, 43% 62%);
+    transform: scale(0);
+    transform-origin: bottom left;
+    transition: transform 0.15s ease-in-out;
+    box-shadow: inset 1em 1em #007aff;
+    /* 使用淡蓝色与主题颜色匹配 */
+    background-color: CanvasText;
+}
+
+#emailInputs input[type="checkbox"]:checked::before {
+    transform: scale(1);
+}
+
+
+        .user-info {
+            position: absolute;
+            width: 300px;
+            background-color: white;
+            padding: 20px;
+            border: 1px solid #ddd;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            display: none;
+        }
+        .user-info .close {
+            position: absolute;
+            top: 10px;
+            right: 10px;
+            color: #aaa;
+            font-size: 24px;
+            font-weight: bold;
+            cursor: pointer;
+        }
+        .user-info .close:hover,
+        .user-info .close:focus {
+            color: black;
+            text-decoration: none;
+        }
+        .centered-modal-content {
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background-color: #fefefe;
+            padding: 50px;
+            border: 1px solid #888;
+            border-radius: 10px;
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            width: 400px;
+            height: 400px;
+            overflow-y: auto;
+            text-align: center;
+        }
+        .ios-button {
+            width: 100%;
+            padding: 10px;
+            margin: 0;
+            border: none;
+            border-radius: 0;
+            font-size: 16px;
+            font-weight: 600;
+            color: #007aff;
+            background-color: transparent;
+            text-align: center;
+            cursor: pointer;
+            transition: background-color 0.3s;
+        }
+        .ios-button:active {
+            background-color: rgba(0, 122, 255, 0.1);
+        }
+        .email-modal-label {
+            font-size: 18px;
+            margin-bottom: 10px;
+            display: block;
+        }
+        .email-modal-input {
+            width: calc(100% - 20px);
+            padding: 10px;
+            font-size: 16px;
+            border: 1px solid #ccc;
+            border-radius: 5px;
+            margin-bottom: 10px;
+        }
+        .email-modal .modal-content {
+    width: 90%; /* 修改宽度 */
+    max-width: 600px; /* 最大宽度 */
+    height: auto; /* 自适应高度 */
+    max-height: 80%; /* 最大高度,防止内容溢出屏幕 */
+    overflow-y: auto; /* 添加垂直滚动条,如果内容超出 */
+}
+
+
+        .add-email-button {
+            display: block;
+            width: 100%;
+            padding: 10px 20px;
+            margin-bottom: 10px;
+            background-color: #007aff;
+            color: white;
+            border: none;
+            text-align: center;
+            font-size: 16px;
+            cursor: pointer;
+            border-radius: 5px;
+            transition: background-color 0.3s;
+        }
+        .add-email-button:hover {
+            background-color: #005bb5;
+        }
+        .action-modal-content {
+            display: flex;
+            flex-direction: column;
+            align-items: flex-start;
+        }
+        .action-modal-content button {
+            width: auto;
+            padding: 10px 20px;
+            margin: 5px 0;
+            background-color: white;
+            color: black;
+            border: none;
+            text-align: left;
+            font-size: 16px;
+            cursor: pointer;
+            border-radius: 5px;
+            transition: background-color 0.3s;
+        }
+        .action-modal-content button:hover {
+            background-color: #f0f0f0;
+        }
+        .sort-button {
+            background-color: transparent;
+            border: none;
+            color: #007aff;
+            font-size: 16px;
+            cursor: pointer;
+            padding: 5px 10px;
+            border-radius: 15px;
+            transition: background-color 0.3s;
+        }
+        .sort-button:hover {
+            background-color: rgba(0, 122, 255, 0.1);
+        }
+        #confirmGenerateModal .centered-modal-content {
+            background-color: #ffffff;
+            border: none;
+            border-radius: 15px;
+            padding: 20px;
+            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+            text-align: center;
+        }
+        #confirmGenerateModal .centered-modal-content button {
+            background-color: #007aff;
+            color: white;
+            border: none;
+            border-radius: 10px;
+            padding: 10px 20px;
+            cursor: pointer;
+            font-size: 16px;
+            margin: 10px;
+            transition: all 0.3s;
+        }
+        #confirmGenerateModal .centered-modal-content button:hover {
+            background-color: #005bb5;
+            border: 1px solid #007aff;
+        }
+
+        #role-management {
+    padding: 20px;
+    background-color: white;
+    border-radius: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 角色项的默认样式 */
+.role-item {
+    background-color: white; /* 默认背景色 */
+    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+    border-radius: 10px; /* 圆角效果 */
+    overflow: hidden; /* 确保圆角效果生效 */
+    border: 2px solid transparent; /* 默认边框为透明 */
+    transition: all 0.3s ease; /* 过渡效果 */
+    margin-bottom: 20px; /* 每个角色之间的间距 */
+    padding: 10px; /* 内边距 */
+}
+
+/* 置顶角色的样式 */
+.role-item.top-role {
+    background-color: #d3d3d3; /* 灰色背景 */
+}
+
+/* 鼠标悬停时的样式 */
+.role-item:hover {
+    background-color: #e6f7ff; /* 悬停时背景色 */
+    border-color: #1169ff; /* 悬停时边框颜色 */
+    border-width: 4px; /* 悬停时边框大小 */
+    border-radius: 15px; /* 悬停时的圆角 */
+}
+
+/* 置顶角色在悬停时的样式 */
+.role-item.top-role:hover {
+    background-color: #d3d3d3; /* 保持灰色背景不变 */
+    border-color: #1169ff; /* 悬停时边框颜色 */
+    border-width: 4px; /* 悬停时边框大小 */
+    border-radius: 15px; /* 悬停时的圆角 */
+}
+
+
+.role-item h3 {
+    margin-top: 0;
+}
+
+.role-item ul {
+    padding-left: 20px;
+}
+
+.create-role-button {
+    background-color: #007aff;
+    color: white;
+    border: none;
+    padding: 10px 20px;
+    border-radius: 10px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: background-color 0.3s;
+    margin-left: 20px; /* 与标题之间的间距 */
+}
+.create-role-button:hover {
+    background-color: #005bb5;
+}
+
+    </style>
+</head>
+<body>
+    <div class="sidebar" id="sidebar">
+        <button onclick="showTable()">License 管理</button>
+        <button onclick="showUserManagement()">用户管理</button>
+        <button onclick="showRoleManagement()">角色管理</button>
+    </div>
+    <div class="content" id="content">
+        <button class="toggle-sidebar" onclick="toggleSidebar()">←</button>
+        <header>
+            <h1>XUGU License 管理平台</h1>
+            <div>
+             <!--   <button class="upload-button" onclick="window.location.href='/static/upload_xlsx/index.html'" style="display: none;">Upload File</button> --> <!-- 默认隐藏 -->
+                <button class="user-button" onclick="toggleUserInfo()" id="username">User</button>
+             
+            </div>
+            
+        </header>
+        
+        <div id="table-container">
+            <table id="applications-table">
+                <thead>
+                    <tr>
+                        <th>创建人</th>
+                        <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>
+                        <th>关联项目</th>
+                        <th>销售人员</th>
+                        <th>技服人员</th>
+                        <th>总节点数</th>
+                        <th>使用单位</th>
+                        <th>产品名称</th>
+                        <th>版本</th>
+                        <th>节点数</th>
+                        <th>License状态</th>
+                    </tr>
+                </thead>
+                <tbody>
+                </tbody>
+            </table>
+            <div class="pagination">
+                <button id="prev-page">上一页</button>
+                <button id="next-page">下一页</button>
+                <select id="page-selector" class="flat-select"></select>
+                <span id="pagination-info">第 1 页,共 0 页</span> <!-- 新增信息显示区域 -->
+                <div id="capture-license-button-container">
+                    <!-- 按钮将在这里插入 -->
+                </div>
+             <!--   <button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button>   动态插入按钮的容器 -->
+            </div>
+        </div>
+<!-- License 详细信息的模态框 -->
+<div id="detailsModal" class="modal">
+    <div class="modal-content">
+        <span class="close" onclick="closeModal('detailsModal')">&times;</span>
+        <h3>License 详细信息</h3>
+        <div id="detailsContent"></div>
+        <button class="close-button" onclick="closeModal('detailsModal')">关闭</button>
+    </div>
+</div>
+
+
+ <!-- 用户管理的添加用户 -->
+<div id="user-management" style="display: none;">
+    <div style="display: flex; align-items: center; justify-content: space-between;">
+        <h2>用户管理</h2>
+        <button id="addUserButton" class="create-role-button" style="display: none;">添加用户</button> <!-- 默认隐藏 -->
+    </div>
+    <table id="users-table">
+        <thead>
+        
+            <tr>
+                <th>用户名</th>
+                <th>电话</th>
+                <th>邮箱</th>
+                <th>权限</th>
+                <th>账号</th>
+            </tr>
+        </thead>
+        <tbody>
+        </tbody>
+    </table>
+</div>
+
+        
+            <!-- 新增的角色管理容器 -->
+    <div id="role-management" style="display: none;">
+        <div style="display: flex; align-items: center; justify-content: space-between;">
+            <h2>角色管理</h2>
+            <button id="createRoleButton" class="create-role-button">创建角色</button>
+        </div>
+        <div id="roles-container"></div>
+    </div>
+    </div>
+
+    <!-- License 管理的弹出菜单 -->
+    <div id="licenseActionModal" class="modal">
+        <div class="modal-content action-modal-content" id="licenseActionModalContent">
+            <span class="close" onclick="closeModal('licenseActionModal')">&times;</span>
+            <!-- <button onclick="showExtraInfo()">查看额外信息</button>
+            <button onclick="modifyLicenseInfo()">修改信息</button> 新增的修改信息按钮 -->
+            <!-- <button onclick="showDistributionHistory()">分发历史</button>
+            <button onclick="confirmDelete()">删除</button> -->
+        </div>
+    </div>
+
+<!-- 修改信息的表单框 -->
+<div id="modifyLicenseModal" class="modal">
+    <div class="modify-license-modal-content">
+        <span class="close" onclick="closeModal('modifyLicenseModal')">&times;</span>
+        <h3>修改License信息</h3>
+        <form id="modifyLicenseForm">
+            <label for="creator">创建人:</label>
+            <input type="text" id="creator" name="creator" required><br><br>
+
+            <label for="applicationDate">申请日期:</label>
+            <input type="date" id="applicationDate" name="applicationDate" class="form-control" required><br><br>
+            
+
+            <label for="associatedProject">关联项目:</label>
+            <input type="text" id="associatedProject" name="associatedProject" required><br><br>
+
+            <label for="salesPerson">销售人员:</label>
+            <input type="text" id="salesPerson" name="salesPerson" required><br><br>
+
+            <label for="salesEmail">销售邮箱:</label>
+            <input type="email" id="salesEmail" name="salesEmail" required><br><br>
+
+            <label for="supportPerson">技服人员:</label>
+            <input type="text" id="supportPerson" name="supportPerson" required><br><br>
+
+            <label for="supportEmail">技服邮箱:</label>
+            <input type="email" id="supportEmail" name="supportEmail" required><br><br>
+
+            <label for="totalNodes">总节点数:</label>
+            <input type="number" id="totalNodes" name="totalNodes" class="form-control" required><br><br>
+
+            <label for="company">使用单位:</label>
+            <input type="text" id="company" name="company" required><br><br>
+
+            <label for="productName">产品名称:</label>
+            <input type="text" id="productName" name="productName" required><br><br>
+
+            <label for="version"> 数据库版本: </label>
+            <input type="text" id="version" name="version" required><br><br>
+
+            <label for="nodeCount">节点数:</label>
+            <input type="number" id="nodeCount" name="nodeCount" class="form-control" required><br><br>
+
+            <button type="button" onclick="saveLicenseChanges()">保存</button>
+        </form>
+    </div>
+</div>
+
+
+
+    <!-- 用户管理的弹出菜单 -->
+    <div id="userActionModal" class="modal">
+        <div class="modal-content action-modal-content" id="userActionModalContent">
+            <span class="close" onclick="closeModal('userActionModal')">&times;</span>
+            <button onclick="showMoreUserInfo()">更多用户信息</button>
+            <button onclick="showUserLicenseHistory()">查看license分发记录</button>
+            <button onclick="modifyUser()">修改用户</button>
+        </div>
+    </div>
+
+<!-- 用户管理的添加用户 -->
+<div id="addUserModal" class="modal">
+    <div class="centered-modal-content" style="height: 50vh; overflow-y: auto;">
+        <span class="close" onclick="closeModal('addUserModal')">&times;</span>
+        <h3>添加用户</h3>
+        <form id="addUserForm">
+            <div class="form-group">
+                <label for="addUsername">用户名:</label>
+                <input type="text" id="addUsername" name="username" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addPassword">密码:</label>
+                <input type="password" id="addPassword" name="password" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addAccount">账号:</label>
+                <input type="text" id="addAccount" name="account" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addTelephone">电话:</label>
+                <input type="text" id="addTelephone" name="telephone" class="flat-rounded-input" required>
+            </div>
+
+            <div class="form-group">
+                <label for="addEmail">邮箱:</label>
+                <input type="email" id="addEmail" name="email" class="flat-rounded-input" required>
+            </div>
+
+            <button type="button" onclick="saveNewUser()" class="flat-rounded-button">保存</button>
+        </form>
+    </div>
+</div>
+
+
+    
+
+    <!-- 邮箱和用户选择弹出框 -->
+    <div id="emailModal" class="modal">
+        <div class="modal-content centered-modal-content" style="height: 45vh; overflow-y: auto;">
+            <span class="close" onclick="closeModal('emailModal')">&times;</span>
+    
+            <!-- 邮箱输入部分 -->
+            <label for="emailInput1" class="email-modal-label">选中要发送的邮箱:</label>
+            <div id="emailInputs">
+                <input type="text" id="emailInput1" class="email-modal-input">
+            </div>
+            <br>
+            <button onclick="addEmailInput()" class="add-email-button">添加邮箱</button>
+    
+            <!-- 用户选择部分 -->
+            <label for="userSelect1" class="email-modal-label">选择要分发的用户:</label>
+            <div id="userInputs"></div>
+            <button onclick="addUserInput()" class="add-email-button">添加用户</button>
+    
+            <!-- 发送按钮 -->
+            <button onclick="sendEmail()" class="ios-button">发送</button>
+        </div>
+    </div>
+    
+    
+    <!-- 其他模态框不变 -->
+    <div id="extraInfoModal" class="modal">
+        <div class="modal-content">
+            <span class="close" onclick="closeModal('extraInfoModal')">&times;</span>
+            <div id="extraInfoContent" class="extra-info"></div>
+        </div>
+    </div>
+
+    <div id="userModal" class="user-info">
+        <span class="close apple-close" onclick="closeUserInfo()">&times;</span> <!-- 关闭按钮 -->
+        <div id="userInfoContent"></div>
+        <br>
+        <button class="apple-logout-button" onclick="logout()">退出</button>
+    </div>
+    
+
+        <!-- license删除模态框-->
+    <div id="confirmDeleteModal" class="modal">
+        <div class="centered-modal-content">
+            <span class="close" onclick="closeModal('confirmDeleteModal')">&times;</span>
+            
+        </div>
+    </div>
+    
+    
+
+    <div id="confirmGenerateModal" class="modal">
+        <div class="centered-modal-content" style="height: 15vh; overflow-y: auto;">
+            <span class="close" onclick="closeModal('confirmGenerateModal')">&times;</span>
+            <p>确认生成License吗?</p>
+            <button id="confirm-generate-button">确认</button>
+            <button onclick="closeModal('confirmGenerateModal')">取消</button>
+        </div>
+    </div>
+
+    <div id="distributionHistoryModal" class="modal">
+        <div class="centered-modal-content">
+            <span class="close" onclick="closeModal('distributionHistoryModal')">&times;</span>
+            <h3>分发历史</h3>
+            <div id="distributionHistoryContent" class="extra-info"></div>
+        </div>
+    </div>
+
+<script>
+    //翻页有关,还需优化
+        let currentPage = 1;
+        let pageSize = 10;
+        let LisOffset = 1;
+        let totalPages = 0; // 存储总页数
+        let selectedPage =1;
+        let nextPage =1;
+        let prevPage = 10;
+//用户token
+        const token = localStorage.getItem('Authorization');
+//选中行的数据
+        let selectedRowData = null;//选中行的数据
+        let isAscending = true;
+        let userMap = {}; // 用于存储用户名和用户ID的映射
+        let currentUserRole = ''; // 新增变量存储当前用户的权限
+        let currentUserName = ''; // 新增变量存储当前用户的名字
+        let userPermissions = [];// 全局变量,用于存储用户权限
+        let LicApplicationData = []; // 全局变量存储数据
+        let currentRolePermissions = []; // 这是您获取的当前角色的权限列表
+
+        
+function checkPermission(permission) {
+            console.log(`检查权限: ${permission} - ${hasPermission ? '有权限' : '无权限'}`);
+    return userPermissions.includes(permission);
+}
+
+async function initialize() {
+    await fetchUsername(); // 确保 fetchUsername 完成
+    fetchApplications(1, 10); // 然后再调用 fetchApplications
+
+
+}
+  
+//获取license展示信息
+function fetchApplications(page, size) {
+    
+    fetch(`http://127.0.0.1:8080/api/admin/GetAllLicenseInfo?page=${page}&pageSize=${size}`, {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        LicApplicationData = data.data; // 将接收到的数据存储到全局变量
+        console.log(data); // 输出获取的数据结构
+        console.log("z该死的权限数组",userPermissions); 
+        const hasGeneratePermission = userPermissions.includes("generate_license");
+        const hasDistributePermission = userPermissions.includes("dispat_license");
+
+    
+ // 更新总页数
+ //totalPages = Math.ceil(data.total / 10);
+        // 在控制台打印权限结果
+        console.log(`hasGeneratePermission: ${hasGeneratePermission}, hasDistributePermission: ${hasDistributePermission}`);
+        totalPages = Math.ceil(data.total / 10);
+        const tableBody = document.querySelector('#applications-table tbody');
+        const tableHead = document.querySelector('#applications-table thead tr');
+
+        tableBody.innerHTML = '';
+        tableHead.innerHTML = `
+            <th></th> <!-- 添加一个空的表头用于放置下拉按钮 -->
+            <th>创建人</th>
+            <th>申请日期 </th> 
+               <!--   <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>-->
+            <th>关联项目</th>
+            <th>销售人员</th>
+            <th>技服人员</th>
+            <th>总节点数</th>
+            <th>使用单位</th>
+            <th>操作</th> <!-- 新增的表头用于显示操作按钮 -->
+        `;
+
+        data.data.forEach(applicationArray => {
+            const firstApplication = applicationArray[0];
+            let showGenerateButton = false;
+
+            // Check if any child row has LicenseFlage as "未生成"
+            applicationArray.forEach(detail => {
+                if (detail.LicenseFlage === "未生成") {
+                    showGenerateButton = true;
+                }
+            });
+
+            // 创建主行
+            const row = document.createElement('tr');
+            const dropdownButton = document.createElement('button');
+        // 使用CSS创建一个箭头图标
+            dropdownButton.innerHTML = '';
+            dropdownButton.classList.add('arrow-icon');
+            dropdownButton.style.cursor = 'pointer';
+
+            row.innerHTML = `
+                <td></td> <!-- 空的单元格用于放置下拉按钮 -->
+                <td>${createEllipsisText(firstApplication.Creator)}</td>
+                <td>${createEllipsisText(firstApplication.ApplicationDate)}</td>
+                <td>${createEllipsisText(firstApplication.GlxmName)}</td>
+                <td>${createEllipsisText(firstApplication.SalesPerson)}</td>
+                <td>${createEllipsisText(firstApplication.SupportPerson)}</td>
+                <td>${firstApplication.TotalNodes}</td>
+                <td>${createEllipsisText(firstApplication.Company)}</td>
+            `;
+            row.querySelector('td').appendChild(dropdownButton);
+
+    // 添加 License 状态按钮 (父级行)
+    if (hasGeneratePermission || hasDistributePermission) {
+        const licenseStatusCell = document.createElement('td');
+
+        if (hasGeneratePermission && showGenerateButton) {
+            licenseStatusCell.innerHTML += `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${firstApplication.oa_request_id}', true)">生成</button>`;
+        } else if (hasDistributePermission && firstApplication.LicenseFlage === "已生成") {
+            licenseStatusCell.innerHTML += `<button class="license-status-btn distribute" onclick="showEmailModal('${firstApplication.SupportEmail}', '${firstApplication.SalesEmail}', '${firstApplication.UniqueID}')">分发</button>`;
+        }
+
+        // 添加一个分隔符
+        licenseStatusCell.innerHTML += `<span style="margin: 0 10px; display: inline-block; width: 1px; height: 20px; background-color: #ccc;"></span>`;
+
+        // 在这里添加“查看详情”按钮
+        licenseStatusCell.innerHTML += `<button class="license-status-btn view-details" onclick="showDetailsModal('${firstApplication.UniqueID}', false)">查看详情</button>`;
+
+        row.appendChild(licenseStatusCell);
+}
+
+
+            tableBody.appendChild(row);
+
+            // 多行内容及表头 (子行)
+            const detailRow = document.createElement('tr');
+            const detailCell = document.createElement('td');
+            detailCell.colSpan = 11; // 占满所有列
+            detailCell.style.display = 'none';
+            const detailTable = document.createElement('table');
+
+            // 添加表头
+            const detailTableHeader = document.createElement('tr');
+            detailTableHeader.innerHTML = `
+                <th>产品名称</th>
+                <th>版本</th>
+                <th>节点数</th>
+                <th>处理器</th>
+                <th>操作系统</th>
+                <th>主MAC地址</th>
+                <th>副MAC地址</th>
+                <th>   查看</th>
+            `;
+            detailTable.appendChild(detailTableHeader);
+
+            // 添加详细信息行 (子行)
+            applicationArray.forEach(detail => {
+                const detailInnerRow = document.createElement('tr');
+                detailInnerRow.innerHTML = `
+                    <td>${createEllipsisText(detail.ProductName)}</td>
+                    <td>${createEllipsisText(detail.ProductVersion)}</td>
+                    <td>${detail.NodeCount}</td>
+                    <td>${createEllipsisText(detail.oa_cpu)}</td>
+                    <td>${createEllipsisText(detail.oa_operating_system)}</td>
+                    <td>${createEllipsisText(detail.oa_main_mac)}</td>
+                    <td>${createEllipsisText(detail.oa_second_mac)}</td>
+                `;
+//保留这里的代码,涉及到子行的单独申请
+                // 添加 License 状态按钮 (子行) 
+                // if (hasGeneratePermission || hasDistributePermission) {
+                //     const licenseStatusDetailCell = document.createElement('td');
+
+                //     if (hasGeneratePermission && detail.LicenseFlage === "未生成") {
+                //         // 子行点击生成按钮时,传递 UniqueID 和 false 表示这是子行
+                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${detail.UniqueID}', false)">生成</button>`;
+                //     } else if (hasDistributePermission && detail.LicenseFlage === "已生成") {
+                //         // 子行点击分发按钮时,传递 UniqueID 用于分发操作
+                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn distribute" onclick="showEmailModal('${detail.SupportEmail}', '${detail.SalesEmail}', '${detail.UniqueID}')">分发</button>`;
+                //     }
+
+                //     detailInnerRow.appendChild(licenseStatusDetailCell);
+                // }
+
+                detailTable.appendChild(detailInnerRow);
+        // 添加“查看详情”按钮 (子行)
+        const viewDetailsCell = document.createElement('td');
+        viewDetailsCell.innerHTML = `<button class="license-status-btn view-details" onclick="showDetailsModal('${detail.UniqueID}', true)">查看详情</button>`;
+        detailInnerRow.appendChild(viewDetailsCell);
+
+    detailTable.appendChild(detailInnerRow);
+
+
+                // 为每个详细信息行添加点击事件 (子行)
+                detailInnerRow.addEventListener('click', (event) => {
+                    if (!event.target.closest('button')) {
+                        openActionModal(event, detail, 'licenseActionModal');
+                    }
+                });
+
+                detailInnerRow.addEventListener('contextmenu', (event) => {
+                    event.preventDefault();
+                    if (!event.target.closest('button')) {
+                        openActionModal(event, detail, 'licenseActionModal');
+                    }
+                });
+            });
+
+            detailCell.appendChild(detailTable);
+            detailRow.appendChild(detailCell);
+            tableBody.appendChild(detailRow);
+
+            // 主行的点击事件,用于切换下拉菜单的显示隐藏
+            // row.addEventListener('click', (event) => {
+            //     if (!event.target.closest('button')) { // 如果点击的不是按钮
+            //         detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none';
+            //     }
+            // });
+
+            // // 点击下拉按钮切换显示隐藏
+            // dropdownButton.addEventListener('click', (event) => {
+            //     event.stopPropagation(); // 阻止事件冒泡到行点击事件
+            //     detailCell.style.display = detailCell.style.display === 'none' ? 'table-cell' : 'none';
+            // });
+            row.addEventListener('click', (event) => {
+    if (!event.target.closest('button')) { // 如果点击的不是按钮
+        // const isExpanded = detailCell.style.display === 'table-cell';
+        // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+        // row.classList.toggle('expanded-row', !isExpanded);
+        // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
+        if (!event.target.closest('button')) {
+        const isExpanded = detailCell.style.display === 'table-cell';
+        
+        // 收回其他行
+        closeAllExpandedRows();
+
+        // 展开/收起当前行
+        detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+        row.classList.toggle('expanded-row', !isExpanded);
+        dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
+    }
+    }
+
+    
+});
+
+
+
+
+
+
+dropdownButton.addEventListener('click', (event) => {
+    // event.stopPropagation(); // 阻止事件冒泡到行点击事件
+    // const isExpanded = detailCell.style.display === 'table-cell';
+    // detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+    // row.classList.toggle('expanded-row', !isExpanded);
+    // dropdownButton.classList.toggle('rotate-arrow', !isExpanded); // 旋转箭头图标
+
+    event.stopPropagation(); // 阻止事件冒泡到行点击事件
+    const isExpanded = detailCell.style.display === 'table-cell';
+    
+    // 收回其他行
+    closeAllExpandedRows();
+
+    // 展开/收起当前行
+    detailCell.style.display = isExpanded ? 'none' : 'table-cell';
+    row.classList.toggle('expanded-row', !isExpanded);
+    dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
+});
+
+        });
+
+        // 分页和其他控制逻辑
+  // 更新分页信息
+      //  totalPages = Math.ceil(data.total / pageSize);
+        document.getElementById('pagination-info').textContent = `第 ${currentPage} 页,共 ${totalPages} 页`;
+        document.getElementById('prev-page').disabled = currentPage <= 1;
+        document.getElementById('next-page').disabled = currentPage >= totalPages;
+        const pageSelector = document.getElementById('page-selector');
+        pageSelector.innerHTML = '';
+        for (let i = 1; i <= totalPages; i++) {
+            const option = document.createElement('option');
+            option.value = i;
+            option.text = i;
+            if (i === selectedPage) {
+                option.selected = true;
+                document.getElementById('pagination-info').textContent = `第 ${selectedPage} 页,共 ${totalPages} 页`;
+                // LisOffset = selectedPage
+                // pageSize = LisOffset + 10;
+                // document.getElementById('prev-page').disabled = currentPage <= 1;
+                // document.getElementById('next-page').disabled = currentPage >= totalPages;
+            }
+            pageSelector.appendChild(option);
+        }
+        
+        
+    });
+}
+
+function checkCaptureLicensePermission() {
+  
+
+    // 获取插入按钮的容器元素
+    const container = document.getElementById('capture-license-button-container');
+
+    if (container) {  // 确保容器元素存在
+        if (userPermissions.includes('capture_license_once_to_db')) {
+            // 如果有权限,插入按钮
+            const CaptureLicensebuttonHtml = `<button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button>`;
+            container.innerHTML = CaptureLicensebuttonHtml;
+        } else {
+            // 如果没有权限,确保不显示按钮
+            container.innerHTML = ''; // 清空容器
+        }
+    } else {
+        console.error('找不到 capture-license-button-container 元素');
+    }
+}
+
+
+
+let currentOffset = 1;
+const itemsPerPage = 10;
+
+// 添加页数选择框的事件监听器
+document.getElementById('page-selector').addEventListener('change', (event) => {
+     selectedPage = parseInt(event.target.value, 10);
+     
+    const startRecord = (selectedPage - 1) * 10 + 1;
+    const endRecord = startRecord + 10;
+    LisOffset = selectedPage
+    pageSize = LisOffset* 10; 
+    currentPage = selectedPage 
+    currentOffset = startRecord
+    endOffset = endRecord
+    fetchApplications(startRecord, endRecord);
+
+});
+
+// 分页按钮事件监听器
+document.getElementById('prev-page').addEventListener('click', () => {
+    if (currentPage > 1) {
+        currentPage--;
+        selectedPage--
+    
+        currentOffset -= itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
+    }
+});
+
+
+document.getElementById('next-page').addEventListener('click', () => {
+    if (currentPage < totalPages) {
+        currentPage++
+        selectedPage++
+        LisOffset += pageSize-LisOffset;
+        pageSize += 10; // 增加页数时,增加 pageSize,规则可自定义
+
+  
+        currentOffset += itemsPerPage;
+        const startOffset = currentOffset;
+        const endOffset = currentOffset + itemsPerPage - 1;
+        fetchApplications(startOffset, endOffset);
+    }
+});
+
+// 页面加载时默认调用第一页的数据
+//fetchApplications(1);
+// 页面初始化时调用 fetchUsername 函数
+
+//fetchApplications(LisOffset,pageSize);
+
+//排序
+// function sortTableByDate() {
+//     applicationData.sort((a, b) => {
+//         const dateTimeA = `${a[0].ApplicationDate} ${a[0].ApplicationTime}`;
+//         const dateTimeB = `${b[0].ApplicationDate} ${b[0].ApplicationTime}`;
+//         return isAscending ? dateTimeA.localeCompare(dateTimeB) : dateTimeB.localeCompare(dateTimeA);
+//     });
+
+//     renderTable(applicationData); // 排序后重新渲染表格
+//     isAscending = !isAscending; // 切换排序顺序
+// }
+
+
+// 关闭所有已经展开的行
+function closeAllExpandedRows() {
+    const allExpandedRows = document.querySelectorAll('.expanded-row');
+    allExpandedRows.forEach(expandedRow => {
+        const detailCell = expandedRow.nextElementSibling.querySelector('td');
+        if (detailCell && detailCell.style.display === 'table-cell') {
+            detailCell.style.display = 'none';
+            expandedRow.classList.remove('expanded-row');
+            const dropdownButton = expandedRow.querySelector('.arrow-icon');
+            if (dropdownButton) {
+                dropdownButton.classList.remove('rotate-arrow');
+            }
+        }
+    });
+}
+
+
+
+// 创建带省略号的文本,并在鼠标悬停时显示完整内容
+function createEllipsisText(text) {
+    const maxLength = 20; // 最大显示字符数
+    if (text == null || typeof text !== 'string') {
+        return ''; // 如果 text 是 null、undefined 或不是字符串,返回空字符串
+    }
+    if (text.length > maxLength) {
+        const span = document.createElement('span');
+        span.textContent = text.substring(0, maxLength) + '...';
+        span.title = text; // 鼠标悬停时显示完整内容
+        return span.outerHTML;
+    }
+    return text;
+}
+
+//生成licensestr
+function confirmGenerateLicense(id, isParentRow) {
+    const confirmGenerateModal = document.getElementById('confirmGenerateModal');
+    confirmGenerateModal.style.display = 'block';
+    document.getElementById('confirm-generate-button').onclick = function() {
+        generateLicense(id, isParentRow);
+    };
+}
+
+function generateLicense(id, isParentRow) {
+    const payload = isParentRow ? { oa_request_id: id } : { uniqueID: id };
+    
+    fetch('http://127.0.0.1:8080/api/admin/GenerateLicense', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(payload)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('License生成成功!');
+            const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+        //    fetchApplications(LisOffset, pageSize);
+        } else {
+            alert('License生成失败:' + data.error);
+        }
+        closeModal('confirmGenerateModal');
+    });
+}
+
+
+//主动抓取一次Licen数据
+function CaptureLicenseOncefunc() {
+    // 显示加载模态框
+    const loadingModal = document.createElement('div');
+    loadingModal.classList.add('modal-content', 'apple-modal-content');
+    loadingModal.innerHTML = `
+        <h3>正在获取 License 信息...</h3>
+        <div class="progress-bar" style="width: 100%; height: 20px; background-color: #e0e0e0;">
+            <div class="progress" style="width: 50%; height: 100%; background-color: #007aff;"></div>
+        </div>
+    `;
+    document.body.appendChild(loadingModal);
+
+    // 定义超时函数
+    const timeoutPromise = new Promise((_, reject) => {
+        setTimeout(() => {
+            reject(new Error('获取超时'));
+        }, 10000); // 10秒超时
+    });
+
+    // 发起 GET 请求的 Promise
+    const fetchPromise = fetch('http://127.0.0.1:8080/api/admin/GetCaptureLicenseOnce', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    }).then(response => response.json());
+
+    // 使用 Promise.race 来竞争两个 Promise,哪个先返回就使用哪个
+    Promise.race([fetchPromise, timeoutPromise])
+    .then(data => {
+        // 先关闭进度条
+        document.body.removeChild(loadingModal);
+
+        // 显示成功或失败提示
+        if (data.success) {
+            alert('License 获取成功!');
+        } else {
+            alert('获取失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        // 先关闭进度条
+        document.body.removeChild(loadingModal);
+        
+        // 显示错误提示
+        alert(error.message); // 如果超时或请求失败
+    });
+}
+
+
+//查看lic所有信息
+function showDetailsModal(uniqueID, isChildRow = false, page = 1) {
+    console.log("当前 uniqueID:", uniqueID);
+    console.log("当前 isChildRow:", isChildRow);
+    console.log("当前页码:", page);
+
+    let selectedData = null;
+    const itemsPerPage = 1; // 每页只显示一个子行数据
+    let currentPage = page; // 当前页码
+
+    // 查找主行和子行数据
+    console.log("查找主行和子行数据");
+    let selectedApplicationArray = null;
+    for (let applicationArray of LicApplicationData) {
+        if (applicationArray.some(data => data.UniqueID === uniqueID)) {
+            selectedApplicationArray = applicationArray;
+            break;
+        }
+    }
+
+    if (!selectedApplicationArray) {
+        console.error('未找到对应的记录,UniqueID:', uniqueID);
+        alert('未找到对应的记录,请检查数据');
+        return;
+    }
+
+    // 计算总页数
+    const totalItems = selectedApplicationArray.length;
+    const totalPages = totalItems + 1; // 主行为第一页,后续为子行
+    console.log("totalItems: ", totalItems);
+    console.log("totalPages: ", totalPages);
+
+    let detailsHtml = `<div class="apple-modal-content">`;
+
+    if (currentPage === 1) {
+        // 显示主行内容(第一页)
+        console.log("显示主行内容(第一页)");
+        detailsHtml += `<h3 class="apple-modal-title">项目信息</h3>`;
+        const firstData = selectedApplicationArray[0];
+        detailsHtml += `
+            <p class="apple-modal-text"><strong>创建人:</strong> ${firstData.Creator}</p>
+            <p class="apple-modal-text"><strong>申请日期:</strong> ${firstData.ApplicationDate}</p>
+            <p class="apple-modal-text"><strong>关联项目:</strong> ${firstData.GlxmName}</p>
+            <p class="apple-modal-text"><strong>销售人员:</strong> ${firstData.SalesPerson}</p>
+            <p class="apple-modal-text"><strong>技服人员:</strong> ${firstData.SupportPerson}</p>
+            <p class="apple-modal-text"><strong>总节点数:</strong> ${firstData.TotalNodes}</p>
+            <p class="apple-modal-text"><strong>使用单位:</strong> ${firstData.Company}</p>
+        `;
+    } else {
+        // 显示子行内容(从第二页开始)
+        console.log("显示子行内容(第" + currentPage + "页)");
+        const dataIndex = currentPage - 2; // 当前页对应的子行数据索引,主行占用第一页
+        const data = selectedApplicationArray[dataIndex];
+        detailsHtml += `
+            <h4 class="apple-modal-subtitle">集群 ${currentPage - 1}</h4>
+            <p class="apple-modal-text"><strong>产品名称:</strong> ${data.ProductName}</p>
+            <p class="apple-modal-text"><strong>版本:</strong> ${data.ProductVersion}</p>
+            <p class="apple-modal-text"><strong>节点数:</strong> ${data.NodeCount}</p>
+            <p class="apple-modal-text"><strong>处理器:</strong> ${data.oa_cpu}</p>
+            <p class="apple-modal-text"><strong>操作系统:</strong> ${data.oa_operating_system}</p>
+            <p class="apple-modal-text"><strong>主MAC地址:</strong> ${data.oa_main_mac}</p>
+            <p class="apple-modal-text"><strong>副MAC地址:</strong> ${data.oa_second_mac}</p>
+        `;
+    }
+
+    // 添加分页按钮
+    detailsHtml += `<div class="pagination-controls" style="text-align: center;">`;
+    if (currentPage > 1) {
+        detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage - 1})">上一页</button>`;
+    }
+    detailsHtml += `<hr style="margin: 10px 0; border-top: 1px solid #ccc;">`; // 分隔符
+    if (currentPage < totalPages) {
+        detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage + 1})">下一页</button>`;
+    }
+    detailsHtml += `</div>`;
+
+    detailsHtml += `</div>`;
+
+    console.log("detailsHtml: ", detailsHtml);
+
+    document.getElementById('detailsContent').innerHTML = detailsHtml;
+    document.getElementById('detailsModal').style.display = 'block';
+}
+
+
+// 用户管理菜单栏
+function openUserActionModal(event, data, modalId) {
+    selectedRowData = data;
+    let modal = document.getElementById(modalId);
+    const modalContent = modal.querySelector('.modal-content');
+
+    // 清空之前的内容
+    modalContent.innerHTML = `
+        <span class="close" onclick="closeModal('${modalId}')">&times;</span>
+    `;
+
+    // 动态生成更多用户信息按钮
+    if (userPermissions.includes('read_user')) {
+        modalContent.innerHTML += `<button onclick="showMoreUserInfo(); closeModal('${modalId}');">更多用户信息</button>`;
+    }
+
+    // 检查是否有 `update_user` 权限,决定是否显示修改用户按钮
+    if (userPermissions.includes('update_user')) {
+        modalContent.innerHTML += `<button onclick="modifyUser(); closeModal('${modalId}');">修改用户</button>`;
+    }
+
+    // 检查是否有 `delete_user` 权限,决定是否显示删除按钮
+    if (userPermissions.includes('delete_user')) {
+        modalContent.innerHTML += `<button onclick="confirmDeleteUser('${data.UniqueID}'); closeModal('${modalId}');">删除用户</button>`;
+    }
+
+    // 显示菜单位置
+    modalContent.style.top = `${event.clientY}px`;
+    modalContent.style.left = `${event.clientX}px`;
+    modal.style.display = 'block';
+}
+
+
+
+// 为用户管理界面的每一行添加点击和右键事件监听器
+function fetchUsers() {
+    fetch('http://127.0.0.1:8080/api/admin/userInfoAll', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const tableBody = document.querySelector('#users-table tbody');
+        tableBody.innerHTML = '';
+        data.data.forEach(user => {
+            // 如果 ACCOUNT 字段为 'admin',则跳过这一行
+            if (user.Account === 'admin') {
+                return;
+            }
+
+            const row = document.createElement('tr');
+            row.innerHTML = `
+                <td>${user.Username}</td>
+                <td>${user.Telephone}</td>
+                <td>${user.Email}</td>
+                <td>${user.Role}</td>
+                <td>${user.Account}</td>
+            `;
+
+            row.addEventListener('click', (event) => {
+                if (!event.target.classList.contains('ios-button')) {
+                    openUserActionModal(event, user, 'userActionModal');
+                }
+            });
+            row.addEventListener('contextmenu', (event) => {
+                event.preventDefault();
+                if (!event.target.classList.contains('ios-button')) {
+                    openUserActionModal(event, user, 'userActionModal');
+                }
+            });
+
+            tableBody.appendChild(row);
+        });
+    });
+}
+
+//查看用户lic历史
+function showUserLicenseHistory() {
+    fetch(`http://127.0.0.1:8080/api/admin/GetlicenseRecordInfoByUser`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+            Id: selectedRowData.Id,
+            UserName: selectedRowData.Username,
+            Page: 1,
+            PageSize: 10
+        })
+    })
+    .then(response => response.json())
+    .then(data => {
+        const extraInfoContent = document.getElementById('extraInfoContent');
+        extraInfoContent.innerHTML = `<h3>License 分发记录</h3>`;
+        
+        if (data.data && data.data.length > 0) {
+            const table = document.createElement('table');
+            table.style.width = '100%';
+            table.style.borderCollapse = 'collapse';
+            table.style.marginTop = '10px';
+
+            const thead = document.createElement('thead');
+            const headerRow = document.createElement('tr');
+            const headers = ['分发日期', '关联项目', '产品名称', '版本', '节点数', 'Company'];
+
+            headers.forEach(headerText => {
+                const th = document.createElement('th');
+                th.textContent = headerText;
+                th.style.border = '1px solid #ddd';
+                th.style.padding = '8px';
+                th.style.backgroundColor = '#f1f1f1';
+                headerRow.appendChild(th);
+            });
+
+            thead.appendChild(headerRow);
+            table.appendChild(thead);
+
+            const tbody = document.createElement('tbody');
+            data.data.forEach(record => {
+                const row = document.createElement('tr');
+
+                const cells = [
+                    record.up_time.Time,
+                    record.AssociatedProject,
+                    record.ProductName,
+                    record.Version,
+                    record.NodeCount,
+                    record.Company
+                ];
+
+                cells.forEach(cellText => {
+                    const td = document.createElement('td');
+                    td.textContent = cellText;
+                    td.style.border = '1px solid #ddd';
+                    td.style.padding = '8px';
+                    row.appendChild(td);
+                });
+
+                tbody.appendChild(row);
+            });
+
+            table.appendChild(tbody);
+            extraInfoContent.appendChild(table);
+        } else {
+            extraInfoContent.innerHTML += `<p>没有找到分发记录。</p>`;
+        }
+
+        document.getElementById('extraInfoModal').style.display = 'block';
+    });
+}
+
+
+//用户菜单栏
+function openActionModal(event, data, modalId) {
+    selectedRowData = data;
+    let modal = document.getElementById(modalId);
+    const modalContent = modal.querySelector('.modal-content');
+
+    // 清空之前的内容
+    modalContent.innerHTML = `
+        <span class="close" onclick="closeModal('${modalId}')">&times;</span>
+    `;
+
+
+
+    // 动态生成查看分发记录
+    if (userPermissions.includes('read_license_record')) {
+        modalContent.innerHTML += `
+            <button onclick="showDistributionHistory(); closeModal('${modalId}');">查看分发记录</button>
+        `;
+    }
+     // 动态生成查看额外信息
+     if (userPermissions.includes('read_license')) {
+        modalContent.innerHTML += `
+            <button onclick="showExtraInfo(); closeModal('${modalId}');">查看额外信息</button>
+        `;
+    }
+
+    // 检查是否有 `update_license` 权限,决定是否显示修改信息按钮
+    if (userPermissions.includes('update_license')) {
+        modalContent.innerHTML += `<button onclick="modifyLicenseInfo(); closeModal('${modalId}');">修改信息</button>`;
+    }
+
+    // 检查是否有 `delete_license` 权限,决定是否显示删除按钮
+    if (userPermissions.includes('delete_license')) {
+        modalContent.innerHTML += `<button onclick="confirmDelete(); closeModal('${modalId}');">删除</button>`;
+    }
+
+    // 显示菜单位置
+    modalContent.style.top = `${event.clientY}px`;
+    modalContent.style.left = `${event.clientX}px`;
+    modal.style.display = 'block';
+}
+
+
+
+
+
+function closeModal(modalId) {
+            document.getElementById(modalId).style.display = 'none';
+        }
+
+
+// function closeUserInfo() {
+//             document.getElementById('userModal').style.display = 'none';
+//         }
+
+function confirmDelete() {
+    const confirmDeleteModal = document.getElementById('confirmDeleteModal');
+    confirmDeleteModal.innerHTML = `
+ <div class="centered-modal-content">
+    <span class="close" onclick="closeModal('confirmDeleteModal')" style="font-size: 24px; font-weight: bold; color: #555; cursor: pointer;">&times;</span>
+    <div style="margin-bottom: 15px; border: 1px solid #ddd; padding: 10px; border-radius: 10px;">
+        <p><strong>申请日期:</strong> ${selectedRowData.ApplicationDate}</p>
+        <p><strong>关联项目:</strong> ${selectedRowData.AssociatedProject}</p>
+        <p><strong>使用单位:</strong> ${selectedRowData.Company}</p>
+    </div>
+    <p>确认删除此行数据吗?</p>
+    <button class="flat-rounded-button" onclick="deleteRow()">确认</button>
+    <button class="flat-rounded-button" onclick="closeModal('confirmDeleteModal')">取消</button>
+</div>
+
+    `;
+    confirmDeleteModal.style.display = 'block';
+}
+
+//添加用户
+document.getElementById('addUserButton').addEventListener('click', function() {
+    document.getElementById('addUserModal').style.display = 'block';
+});
+//添加用户
+function saveNewUser() {
+    const username = document.getElementById('addUsername').value.trim();
+    const password = document.getElementById('addPassword').value.trim();
+    const account = document.getElementById('addAccount').value.trim();
+    const telephone = document.getElementById('addTelephone').value.trim();
+    const email = document.getElementById('addEmail').value.trim();
+
+    // 验证每个字段都不能为空
+    if (!username || !password || !account || !telephone || !email) {
+        alert('有空选项未填写');
+        return;
+    }
+
+    // 验证电话是否为11位数字
+    const phonePattern = /^\d{11}$/;
+    if (!phonePattern.test(telephone)) {
+        alert('电话必须是11位数字');
+        return;
+    }
+
+    // 验证密码长度是否至少为6位
+    if (password.length < 6) {
+        alert('密码长度必须至少为6位');
+        return;
+    }
+
+    // 验证邮箱是否包含@符号
+    if (!email.includes('@')) {
+        alert('邮箱必须包含@符号');
+        return;
+    }
+
+    // 验证账号长度是否至少为3位
+    if (account.length < 3) {
+        alert('账号长度必须至少为3位');
+        return;
+    }
+
+    const newUser = {
+        Username: username,
+        Password: password,
+        Account: account,
+        Telephone: telephone,
+        Email: email
+    };
+
+    fetch('http://127.0.0.1:8080/api/register', {  // 修改为实际的API路径
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(newUser)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('用户创建成功!');
+            fetchUsers(); // 重新加载用户列表
+            closeModal('addUserModal'); // 关闭模态框
+        } else {
+            alert('用户创建失败:' + data.error);
+        }
+    });
+}
+
+
+
+
+
+
+function deleteUser(uniqueID) {
+    fetch('http://127.0.0.1:8080/api/admin/deleteUser', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ UniqueID: uniqueID })
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('用户删除成功!');
+            fetchUsers(); // 重新加载用户列表
+        } else {
+            alert('用户删除失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        console.error('Error deleting user:', error);
+        alert('删除用户时发生错误,请稍后再试。');
+    });
+}
+function confirmDeleteUser(uniqueID) {
+    const confirmed = confirm("确认删除此用户吗?");
+    if (confirmed) {
+        deleteUser(uniqueID);
+    }
+}
+
+ function deleteRow() {
+            fetch(`http://127.0.0.1:8080/api/admin/deleteLicRow`, {
+                method: 'POST',
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
+            }).then(response => {
+                if (response.ok) {
+                    alert('删除成功');
+                    closeModal('confirmDeleteModal');
+                  //  fetchApplications(LisOffset, pageSize);
+                  const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+                } else {
+                    alert('删除失败');
+                }
+            });
+        }
+
+
+
+function showEmailModal(supportEmail, salesEmail, uniqueID) {
+    // 清空并设置默认值
+    document.getElementById('emailInputs').innerHTML = `
+        <div>
+            <input type="checkbox" id="supportEmailCheckbox" value="${supportEmail}" checked>
+            <label for="supportEmailCheckbox">  运维邮箱: ${supportEmail}</label>
+        </div>
+        <div>
+            <input type="checkbox" id="salesEmailCheckbox" value="${salesEmail}" checked>
+            <label for="salesEmailCheckbox">  销售邮箱: ${salesEmail}</label>
+        </div>
+ 
+    `;
+    document.getElementById('userInputs').innerHTML = ''; // 清空用户输入
+
+    // 获取用户信息并填充第一个用户输入框
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const userSelect = document.createElement('select');
+        userSelect.id = 'userSelect1';
+        userSelect.className = 'email-modal-input';
+        
+        data.data.forEach(user => {
+            userMap[user.Username] = {// 存储用户名和用户ID的映射
+            Account: user.Account,
+            UniqueID: user.UniqueID,
+            Username: user.Username,
+            Email: user.Email,
+            Role: user.Role,
+            Telephone:user.Telephone
+        };
+            const option = document.createElement('option');
+            option.value = user.Username;
+            option.textContent = user.Username;
+            userSelect.appendChild(option);
+        });
+
+        //document.getElementById('userInputs').appendChild(userSelect);
+    });
+
+    document.getElementById('emailModal').style.display = 'block';
+    selectedRowData = { ...selectedRowData, UniqueID: uniqueID };
+}
+
+function addEmailInput() {
+    const emailInputs = document.getElementById('emailInputs');
+    const newInputDiv = document.createElement('div');
+    newInputDiv.style.display = 'flex';
+    newInputDiv.style.alignItems = 'center';
+    newInputDiv.style.marginBottom = '10px';
+
+    const newInput = document.createElement('input');
+    newInput.type = 'text';
+    newInput.className = 'email-modal-input';
+    newInput.style.flexGrow = '1';
+    newInputDiv.appendChild(newInput);
+
+    const deleteButton = document.createElement('button');
+    deleteButton.textContent = '✕';
+    deleteButton.style.background = 'none';
+    deleteButton.style.border = 'none';
+    deleteButton.style.color = '#007aff';
+    deleteButton.style.cursor = 'pointer';
+    deleteButton.style.fontSize = '12px'; /* 再次缩小字体大小 */
+    deleteButton.style.padding = '0'; /* 移除内边距 */
+    deleteButton.style.marginLeft = '3px'; /* 减少与输入框的间距 */
+    deleteButton.style.width = '20px'; /* 限制按钮宽度 */
+    deleteButton.style.height = '20px'; /* 限制按钮高度 */
+    deleteButton.onclick = () => {
+        newInputDiv.remove();
+    };
+
+    newInputDiv.appendChild(deleteButton);
+    emailInputs.appendChild(newInputDiv);
+}
+
+function addUserInput() {
+    const userInputs = document.getElementById('userInputs');
+    const newUserDiv = document.createElement('div');
+    newUserDiv.className = 'user-select-container';
+    newUserDiv.style.display = 'flex';
+    newUserDiv.style.alignItems = 'center';
+    newUserDiv.style.marginBottom = '10px';
+
+    const newUserSelect = document.createElement('select');
+    newUserSelect.className = 'email-modal-input';
+    newUserSelect.style.flexGrow = '1';
+    newUserSelect.style.marginRight = '5px';
+
+    // 添加一个默认的空白选项
+    const defaultOption = document.createElement('option');
+    defaultOption.value = '';
+    defaultOption.textContent = '请选择用户';
+    newUserSelect.appendChild(defaultOption);
+
+    // 获取当前已选择的用户
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    // 获取用户列表并填充到选择框中
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        data.data.forEach(user => {
+            // 仅显示未被选中的用户,并且过滤掉admin用户
+            if (!selectedValues.includes(user.Username) && user.Username !== 'admin') {
+                const option = document.createElement('option');
+                option.value = user.Username;
+                option.textContent = user.Username;
+                newUserSelect.appendChild(option);
+            }
+        });
+    });
+
+    const deleteButton = document.createElement('button');
+    deleteButton.textContent = '✕';
+    deleteButton.style.background = 'none';
+    deleteButton.style.border = 'none';
+    deleteButton.style.color = '#007aff';
+    deleteButton.style.cursor = 'pointer';
+    deleteButton.style.fontSize = '12px';
+    deleteButton.style.padding = '0';
+    deleteButton.style.marginLeft = '3px';
+    deleteButton.style.width = '20px';
+    deleteButton.style.height = '20px';
+    deleteButton.onclick = () => {
+        newUserDiv.remove();
+        updateUserOptions(); // 更新其他下拉框中的选项
+    };
+
+    newUserSelect.addEventListener('change', updateUserOptions);
+
+    newUserDiv.appendChild(newUserSelect);
+    newUserDiv.appendChild(deleteButton);
+    userInputs.appendChild(newUserDiv);
+        // 设置空白选项为默认选项
+    newUserSelect.selectedIndex = 0;
+}
+
+function updateUserOptions() {
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    document.querySelectorAll('.user-select-container select').forEach(select => {
+        const currentValue = select.value;
+        select.innerHTML = ''; // 清空现有选项
+
+        // 添加一个默认的空白选项
+        const defaultOption = document.createElement('option');
+        defaultOption.value = '';
+        defaultOption.textContent = '请选择用户';
+        select.appendChild(defaultOption);
+
+        fetch('http://127.0.0.1:8080/api/admin/userInfoAll', {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            data.data.forEach(user => {
+                if (!selectedValues.includes(user.Username) || user.Username === currentValue) {
+                    if (user.Username !== 'admin') { // 过滤掉admin用户
+                        const option = document.createElement('option');
+                        option.value = user.Username;
+                        option.textContent = user.Username;
+                        select.appendChild(option);
+                    }
+                }
+            });
+
+            select.value = currentValue;
+        });
+    });
+}
+
+
+
+// 打开修改信息表单框
+function modifyLicenseInfo() {
+    const form = document.getElementById('modifyLicenseForm');
+    
+    // 将选中的行数据填充到表单中
+    form.creator.value = selectedRowData.Creator;
+    form.applicationDate.value = selectedRowData.ApplicationDate;
+    form.associatedProject.value = selectedRowData.GlxmName;
+    form.salesPerson.value = selectedRowData.SalesPerson;
+    form.salesEmail.value = selectedRowData.SalesEmail;
+    form.supportPerson.value = selectedRowData.SupportPerson;
+    form.supportEmail.value = selectedRowData.SupportEmail;
+    form.totalNodes.value = selectedRowData.TotalNodes;
+    form.company.value = selectedRowData.Company;
+    form.productName.value = selectedRowData.ProductName;
+    form.version.value = selectedRowData.ProductVersion;
+    form.nodeCount.value = selectedRowData.NodeCount;
+    
+    document.getElementById('modifyLicenseModal').style.display = 'block';
+}
+
+// 保存修改后的数据
+function saveLicenseChanges() {
+    const form = document.getElementById('modifyLicenseForm');
+    const updatedData = {
+        UniqueID: selectedRowData.UniqueID,
+        Creator: form.creator.value,
+        ApplicationDate: form.applicationDate.value,
+        AssociatedProject: form.associatedProject.value,
+        SalesPerson: form.salesPerson.value,
+        SalesEmail: form.salesEmail.value,
+        SupportPerson: form.supportPerson.value,
+        SupportEmail: form.supportEmail.value,
+        TotalNodes: parseInt(form.totalNodes.value, 10), // 将 TotalNodes 转换为整数
+        Company: form.company.value,
+        ProductName: form.productName.value,
+        Version: form.version.value,
+        NodeCount: parseInt(form.nodeCount.value, 10), // 将 NodeCount 转换为整数
+    };
+    
+    fetch(`http://127.0.0.1:8080/api/admin/UpdateLicense`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(updatedData)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('License信息更新成功!');
+          //  fetchApplications(LisOffset, pageSize);
+          const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+            closeModal('modifyLicenseModal');
+        } else {
+            alert('License信息更新失败:' + data.error);
+        }
+    });
+}
+
+
+
+
+function updateUserOptions() {
+    const selectedValues = Array.from(document.querySelectorAll('.user-select-container select'))
+        .map(select => select.value);
+
+    document.querySelectorAll('.user-select-container select').forEach(select => {
+        const currentValue = select.value;  // 保留当前选择值
+        select.innerHTML = ''; // 清空现有选项
+        
+        fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            data.data.forEach(user => {
+                // 保留当前值,并排除已经在其他下拉框中选中的值
+                if (!selectedValues.includes(user.Username) || user.Username === currentValue) {
+                    const option = document.createElement('option');
+                    option.value = user.Username;
+                    option.textContent = user.Username;
+                    if (user.Username === currentValue) {
+                        option.selected = true;  // 保持当前选择
+                    }
+                    select.appendChild(option);
+                }
+            });
+        });
+    });
+}
+
+//lic分发给用户 与邮件
+function sendEmail() {
+    console.log('Send button clicked');
+
+    const emailInputs = document.querySelectorAll('.email-modal-input[type="text"]');
+    let emails = Array.from(emailInputs)
+        .map(input => input.value.trim())
+        .filter(email => email && email.includes('@'))
+        .join(',');
+
+    const supportEmailChecked = document.getElementById('supportEmailCheckbox').checked;
+    const salesEmailChecked = document.getElementById('salesEmailCheckbox').checked;
+
+    const emailArray = emails ? [emails] : [];
+
+    if (supportEmailChecked) {
+        emailArray.push(document.getElementById('supportEmailCheckbox').value);
+    }
+    if (salesEmailChecked) {
+        emailArray.push(document.getElementById('salesEmailCheckbox').value);
+    }
+
+    emails = emailArray.join(',');
+
+    // if (!emails) {
+    //     alert('请至少选择一个邮箱地址。');
+    //     return;
+    // }
+
+    console.log('Emails to send:', emails);
+
+    const userInputs = document.querySelectorAll('select.email-modal-input');
+    console.log('userMap:', userMap);
+    
+    const users = Array.from(userInputs)
+        .map(select => userMap[select.value].Account)
+        .join(',');
+
+    const userIds = Array.from(userInputs)
+        .map(select => userMap[select.value].UniqueID)
+        .join(',');
+
+    const userNames = Array.from(userInputs)
+        .map(select => userMap[select.value].Username);
+
+
+
+    const operatorUniqueID = userMap[currentUserName].UniqueID;
+    console.log('User IDs:', userIds);
+    console.log('Users:', users);
+    console.log(' selectedRowData.UniqueID:',  selectedRowData.UniqueID);
+
+    if (!userIds) {
+        alert('请至少选择一个用户。');
+        return;
+    }
+
+    const requestData = {
+        LicenseUniqueID: selectedRowData.UniqueID,
+        UserUniqueIDs: userIds.split(','), 
+        UserAccounts: users.split(','), 
+        Emails: emails,
+        UserNames: userNames,
+        OperatorUniqueID: operatorUniqueID
+    };
+    console.log('requestData:', requestData);
+
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicense', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(requestData)
+    })
+    .then(response => {
+        console.log('Response received');
+        return response.json();
+    })
+    .then(data => {
+        if (data.success) {
+            alert('分发成功!');
+            closeModal('emailModal');
+        } else {
+            // 检查是否有 error 字段,并提示用户详细的错误信息
+            const errorMessage = data.error || '分发失败。';
+            alert(`分发失败: ${errorMessage}`);
+        }
+   
+    })
+    .catch(error => {
+        console.error('Error occurred during email distribution:', error);
+        alert('分发失败,请检查网络或后端服务。');
+    });
+}
+
+
+
+
+
+
+function showDistributionHistory() {
+    fetch('http://127.0.0.1:8080/api/admin/GetlicenseRecord', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
+    })
+    .then(response => response.json())
+    .then(data => {
+        const distributionHistoryContent = document.getElementById('distributionHistoryContent');
+        const { license_record_to_user, license_record_to_emails } = data.data;
+
+        // 确保 license_record_to_user 和 license_record_to_emails 存在并且是数组
+        const userRecords = Array.isArray(license_record_to_user) ? license_record_to_user : [];
+        const emailRecords = Array.isArray(license_record_to_emails) ? license_record_to_emails : [];
+
+        if (userRecords.length > 0 || emailRecords.length > 0) {
+            const userHistoryHtml = userRecords.map(record => `
+                <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">
+                    <p><strong>已转发给用户:</strong> ${record.user_account}</p>
+                    <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p>
+                </div>
+            `).join('');
+
+            const emailHistoryHtml = emailRecords.map(record => `
+                <div style="margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 10px; background-color: #f9f9f9;">
+                    <p><strong>已发给邮箱:</strong> ${record.emails}</p>
+                    <p><strong>分发时间:</strong> ${new Date(record.up_time).toLocaleString()}</p>
+                </div>
+            `).join('');
+
+            distributionHistoryContent.innerHTML = userHistoryHtml + emailHistoryHtml;
+        } else {
+            distributionHistoryContent.innerHTML = `<p>没有分发历史记录。</p>`;
+        }
+
+        // 显示模态框
+        const distributionHistoryModal = document.getElementById('distributionHistoryModal');
+        distributionHistoryModal.style.display = 'block';
+    });
+}
+
+
+
+
+
+ function showMoreUserInfo() {
+            const extraInfoContent = document.getElementById('extraInfoContent');
+            extraInfoContent.innerHTML = `
+                <p><strong>用户名:</strong> ${selectedRowData.Username}</p>
+                <p><strong>电话:</strong> ${selectedRowData.Telephone}</p>
+                <p><strong>邮箱:</strong> ${selectedRowData.Email}</p>
+                <p><strong>权限:</strong> ${selectedRowData.Role}</p>
+            `;
+            document.getElementById('extraInfoModal').style.display = 'block';
+        }
+
+function modifyUser() {
+            const userInfoContent = document.getElementById('extraInfoContent');
+            userInfoContent.innerHTML = `
+                <p><strong>用户名:</strong> ${selectedRowData.Username}</p>
+                <p><strong>电话:</strong> ${selectedRowData.Telephone}</p>
+                <p><strong>邮箱:</strong> ${selectedRowData.Email}</p>
+                <p><strong>权限:</strong> ${selectedRowData.Role}</p>
+                <button onclick="showEditUserForm()">编辑用户信息</button>
+            `;
+            document.getElementById('extraInfoModal').style.display = 'block';
+        }
+
+//查看额外信息
+function showExtraInfo() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+    
+    // 清空之前的内容
+    extraInfoContent.innerHTML = '';
+
+    // 使用预定义的字段名和中文翻译
+    const fieldTranslations = {
+        id: "ID",
+        user_id: "用户ID",
+        up_user: "上传用户",
+        up_time: "上传时间",
+        del_time: "删除时间",
+        License1: "License 1",
+        License2: "License 2",
+        LicenseFlage: "License 状态",
+        UniqueID: "唯一标识符",
+        Creator: "创建人",
+        ApplicationDate: "申请日期",
+        AssociatedProject: "关联项目",
+        SalesPerson: "销售人员",
+        SalesEmail: "销售邮箱",
+        SupportPerson: "支持人员",
+        SupportEmail: "支持邮箱",
+        TotalNodes: "总节点数",
+        Company: "公司",
+        ProductName: "产品名称",
+        Version: "版本",
+        NodeCount: "节点数",
+        Processor: "处理器",
+        OperatingSystem: "操作系统",
+        MasterMacAddress: "主MAC地址",
+        SecondaryMasterMacAddress: "备用主MAC地址"
+    };
+
+    // 使用指定的字段进行展示
+    const fieldsToShow = [
+        "id", "user_id", "up_user", "up_time", "del_time", "License1", "License2", 
+        "LicenseFlage", "UniqueID", "Creator", "ApplicationDate", "AssociatedProject", 
+        "SalesPerson", "SalesEmail", "SupportPerson", "SupportEmail", "TotalNodes", 
+        "Company", "ProductName", "Version", "NodeCount", "Processor", "OperatingSystem", 
+        "MasterMacAddress", "SecondaryMasterMacAddress"
+    ];
+
+    fieldsToShow.forEach(key => {
+        if (selectedRowData.hasOwnProperty(key)) {
+            let value = selectedRowData[key];
+            
+            // 特殊处理 up_time 和 del_time
+            if (key === 'up_time' || key === 'del_time') {
+                if (value.Valid) {
+                    value = new Date(value.Time).toLocaleString(); // 格式化日期时间
+                } else {
+                    value = '无';
+                }
+            }
+
+            // 处理 License1 和 License2,提取字符串字段
+            if (key === 'License1' || key === 'License2') {
+                // 假设 License 对象包含一个名为 'Details' 的字符串字段
+                value = value.String || '[无数据]';
+            }
+
+            // 处理 MasterMacAddress 和 SecondaryMasterMacAddress,提取字符串字段
+            // if (key === 'MasterMacAddress' || key === 'SecondaryMasterMacAddress') {
+            //     // 假设 License 对象包含一个名为 'Details' 的字符串字段
+            //     value = value.String || '[无数据]';
+            // }
+
+            const infoElement = document.createElement('p');
+            infoElement.innerHTML = `<strong>${fieldTranslations[key]}:</strong> ${value}`;
+            extraInfoContent.appendChild(infoElement);
+        }
+    });
+
+    // 显示 modal
+    document.getElementById('extraInfoModal').style.display = 'block';
+}
+
+
+function showRoleManagement() {
+    document.getElementById('table-container').style.display = 'none';
+    document.getElementById('user-management').style.display = 'none'; // 隐藏用户管理页面
+    document.getElementById('role-management').style.display = 'block';;
+
+    fetchRoles();
+}
+
+function fetchRoles() {
+    fetch('http://127.0.0.1:8080/api/admin/GetRoles', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ Name: " " })  // 发送空的 Name 参数
+    })
+    .then(response => response.json())
+    .then(data => {
+        const roleContainer = document.getElementById('roles-container');
+        roleContainer.innerHTML = ''; // 清空之前的内容
+
+        const permissionMap = {
+            'generate_license': '生成许可证',
+            'upload_license': '上传许可证',
+            'read_license': '读取许可证',
+            'read_license_record': '读取许可证分发记录',
+            'update_license': '修改许可证',
+            'delete_license': '删除许可证',
+            'dispat_license': '分发许可证',
+            'create_user': '创建用户',
+            'read_user': '读取用户',
+            'update_user': '更新用户',
+            'delete_user': '删除用户',
+            'create_role': '创建角色',
+            'delete_role': '删除角色',
+            'update_role': '更新角色',
+            'get_role': '获取角色'
+        };
+
+        // 检查用户是否有 create_role 权限
+        const hasCreateRolePermission = userPermissions.includes('create_role');
+
+        // 如果有权限则显示“创建角色”按钮
+        if (hasCreateRolePermission) {
+            document.getElementById('createRoleButton').style.display = 'block';
+        } else {
+            document.getElementById('createRoleButton').style.display = 'none';
+        }
+
+        // 处理置顶角色和其他角色的渲染(代码不变)
+        const topRoles = ['admin', 'guest', 'supportRole'];
+
+        topRoles.forEach(role => {
+            if (data.data[role]) {
+                renderRole(roleContainer, data.data[role], permissionMap, true);
+            }
+        });
+
+        Object.keys(data.data).forEach(role => {
+            if (!topRoles.includes(role)) {
+                renderRole(roleContainer, data.data[role], permissionMap, false);
+            }
+        });
+    });
+}
+
+
+function renderRole(container, roleInfo, permissionMap, isTopRole) {
+    const roleDiv = document.createElement('div');
+    roleDiv.className = 'role-item';
+    roleDiv.style.position = 'relative';  // 确保弹出菜单能够正确定位
+
+    if (isTopRole) {
+        roleDiv.classList.add('top-role'); // 应用置顶角色的样式
+    }
+
+    let permissions = roleInfo.Permissions.map(permission => permissionMap[permission]);
+    let permissionsHtml = permissions.join(',');  // 使用逗号分隔并合并为一行
+
+    roleDiv.innerHTML = `
+        <h3>${roleInfo.Name}</h3>
+        <p>${permissionsHtml}</p>
+    `;
+    container.appendChild(roleDiv);
+
+    // 添加事件监听器,处理点击和右键点击弹出菜单
+    roleDiv.addEventListener('click', function(event) {
+        event.stopPropagation();  // 阻止事件冒泡
+        event.preventDefault();   // 阻止默认行为
+        showRoleActionMenu(event, roleInfo.Name);
+    });
+
+    roleDiv.addEventListener('contextmenu', function(event) {
+        event.preventDefault();
+        showRoleActionMenu(event, roleInfo.Name);
+    });
+}
+
+function showRoleActionMenu(event, roleName) {
+    const existingMenu = document.getElementById('role-action-menu');
+    if (existingMenu) {
+        existingMenu.remove();
+    }
+
+    const menu = document.createElement('div');
+    menu.id = 'role-action-menu';
+    menu.style.position = 'absolute';
+    menu.style.top = `${event.clientY}px`;
+    menu.style.left = `${event.clientX}px`;
+    menu.style.backgroundColor = '#fff';
+    menu.style.border = '1px solid #ccc';
+    menu.style.borderRadius = '5px';
+    menu.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)';
+    menu.style.padding = '10px';
+    menu.style.zIndex = '1000';
+
+    const topRoles = ['admin', 'guest', 'support'];
+
+    if (topRoles.includes(roleName)) {
+        // 为 admin, guest, supportRole 设置灰色和不可点击样式
+        const disabledButton = document.createElement('button');
+        disabledButton.textContent = '不可操作';
+        disabledButton.style.display = 'block';
+        disabledButton.style.width = '100%';
+        disabledButton.style.padding = '10px 20px';
+        disabledButton.style.border = 'none';
+        disabledButton.style.borderRadius = '15px';
+        disabledButton.style.cursor = 'not-allowed';
+        disabledButton.style.backgroundColor = '#d3d3d3';  // 灰色背景
+        disabledButton.style.color = '#999';  // 灰色文字
+
+        menu.appendChild(disabledButton);
+    } else {
+        // 检查用户是否有 update_role 和 delete_role 权限
+        const hasUpdateRolePermission = userPermissions.includes('update_role');
+        const hasDeleteRolePermission = userPermissions.includes('delete_role');
+
+        // 创建和添加修改角色按钮
+        if (hasUpdateRolePermission) {
+            const modifyButton = document.createElement('button');
+            modifyButton.textContent = '修改角色';
+            modifyButton.style.display = 'block';
+            modifyButton.style.marginBottom = '10px';
+            modifyButton.style.width = '100%';
+            modifyButton.style.padding = '10px 20px';
+            modifyButton.style.border = 'none';
+            modifyButton.style.borderRadius = '15px';
+            modifyButton.style.cursor = 'pointer';
+            modifyButton.style.transition = 'background-color 0.3s, color 0.3s';
+            modifyButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
+            modifyButton.style.backgroundColor = '#007aff';
+            modifyButton.style.color = '#fff';
+
+            modifyButton.addEventListener('mouseenter', function () {
+                modifyButton.style.backgroundColor = '#005bb5';
+            });
+
+            modifyButton.addEventListener('mouseleave', function () {
+                modifyButton.style.backgroundColor = '#007aff';
+            });
+
+            modifyButton.addEventListener('click', function () {
+                modifyRole(roleName);
+                menu.remove(); // 点击按钮后,关闭菜单栏
+            });
+
+            menu.appendChild(modifyButton);
+        }
+
+        // 创建和添加删除角色按钮
+        if (hasDeleteRolePermission) {
+            const deleteButton = document.createElement('button');
+            deleteButton.textContent = '删除角色';
+            deleteButton.style.display = 'block';
+            deleteButton.style.width = '100%';
+            deleteButton.style.padding = '10px 20px';
+            deleteButton.style.border = 'none';
+            deleteButton.style.borderRadius = '15px';
+            deleteButton.style.cursor = 'pointer';
+            deleteButton.style.transition = 'background-color 0.3s, color 0.3s';
+            deleteButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
+            deleteButton.style.backgroundColor = '#ff3b30';
+            deleteButton.style.color = '#fff';
+
+            deleteButton.addEventListener('mouseenter', function () {
+                deleteButton.style.backgroundColor = '#c23321';
+            });
+
+            deleteButton.addEventListener('mouseleave', function () {
+                deleteButton.style.backgroundColor = '#ff3b30';
+            });
+
+            deleteButton.addEventListener('click', function () {
+                deleteRole(roleName);
+                menu.remove(); // 点击按钮后,关闭菜单栏
+            });
+
+            menu.appendChild(deleteButton);
+        }
+
+        // 如果用户没有修改或删除权限,则显示没有选项的提示
+        if (!hasUpdateRolePermission && !hasDeleteRolePermission) {
+            const noOption = document.createElement('div');
+            noOption.textContent = '没有可用的操作';
+            noOption.style.textAlign = 'center';
+            noOption.style.color = '#999';
+            menu.appendChild(noOption);
+        }
+    }
+
+    document.body.appendChild(menu);
+
+    document.addEventListener('click', function closeMenu(event) {
+        if (!menu.contains(event.target)) {
+            menu.remove();
+            document.removeEventListener('click', closeMenu);
+        }
+    });
+}
+
+
+//修改角色信息
+function modifyRole(roleName) {
+    console.log(`modifyRole called with roleName: ${roleName}`);
+    
+    fetchRoleInfo(roleName, function(roleInfo) {
+        console.log(`fetchRoleInfo returned:`, roleInfo);
+
+        if (!roleInfo) {
+            console.error('Role info is undefined or null');
+            return;
+        }
+
+        const extraInfoContent = document.getElementById('extraInfoContent');
+        if (!extraInfoContent) {
+            console.error('Element with id "extraInfoContent" not found');
+            return;
+        }
+
+        extraInfoContent.innerHTML = `
+            <h3>修改角色: ${roleInfo.Name}</h3>
+            <label for="roleName">角色名称:</label>
+            <input type="text" id="roleName" value="${roleInfo.Name}" required><br><br>
+            <label for="permissions">权限:</label><br>
+            <div id="permissions">
+                  <div>
+            <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)">
+            <label for="license">许可证</label>
+            <div id="licenseSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="generate_license" name="permissions" value="generate_license">
+                <label for="generate_license">生成许可证</label><br>
+                <input type="checkbox" id="upload_license" name="permissions" value="upload_license">
+                <label for="upload_license">上传许可证</label><br>
+                <input type="checkbox" id="read_license" name="permissions" value="read_license">
+                <label for="read_license">读取许可证</label><br>
+                <input type="checkbox" id="update_license" name="permissions" value="update_license">
+                <label for="update_license">更新许可证</label><br>
+                <input type="checkbox" id="delete_license" name="permissions" value="delete_license">
+                <label for="delete_license">删除许可证</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)">
+            <label for="user">用户</label>
+            <div id="userSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_user" name="permissions" value="create_user">
+                <label for="create_user">创建用户</label><br>
+                <input type="checkbox" id="read_user" name="permissions" value="read_user">
+                <label for="read_user">读取用户</label><br>
+                <input type="checkbox" id="update_user" name="permissions" value="update_user">
+                <label for="update_user">更新用户</label><br>
+                <input type="checkbox" id="delete_user" name="permissions" value="delete_user">
+                <label for="delete_user">删除用户</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)">
+            <label for="role">角色</label>
+            <div id="roleSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_role" name="permissions" value="create_role">
+                <label for="create_role">创建角色</label><br>
+                <input type="checkbox" id="delete_role" name="permissions" value="delete_role">
+                <label for="delete_role">删除角色</label><br>
+                <input type="checkbox" id="update_role" name="permissions" value="update_role">
+                <label for="update_role">更新角色</label><br>
+                <input type="checkbox" id="get_role" name="permissions" value="get_role">
+                <label for="get_role">获取角色</label><br>
+            </div>
+        </div>
+            </div><br><br>
+            <button onclick="saveRoleChanges('${roleInfo.Id}')">保存</button>
+        `;
+
+        console.log('Form content added to extraInfoContent');
+
+        const checkboxes = document.querySelectorAll('#permissions input[type="checkbox"]');
+
+// 遍历所有复选框
+checkboxes.forEach(checkbox => {
+    if (roleInfo.Permissions.includes(checkbox.value)) {
+        checkbox.checked = true; // 如果当前权限在roleInfo.Permissions中,则勾选
+    }
+});
+
+        const extraInfoModal = document.getElementById('extraInfoModal');
+        if (!extraInfoModal) {
+            console.error('Element with id "extraInfoModal" not found');
+            return;
+        }
+
+        extraInfoModal.style.display = 'block';  // 强制显示模态框
+        console.log('Modal should be visible now');
+    });
+}
+
+function getCheckboxOptions(selectedPermissions) {
+    const permissionMap = {
+        'generate_license': '生成许可证',
+        'upload_license': '上传许可证',
+        'read_license': '读取许可证',
+        'update_license': '修改许可证',
+        'delete_license': '删除许可证',
+        'dispat_license': '分发许可证',
+        'read_license_record': '读取许可证分发记录',
+      //  'get_user_info': '获取用户信息',
+        'create_user': '创建用户',
+        'read_user': '读取用户',
+        'update_user': '更新用户',
+        'delete_user': '删除用户',
+        'create_role': '创建角色',
+        'delete_role': '删除角色',
+        'update_role': '更新角色',
+        'get_role': '获取角色'
+    };
+
+    return Object.keys(permissionMap).map(permission => `
+        <div>
+            <input type="checkbox" id="${permission}" name="permissions" value="${permission}" ${selectedPermissions.includes(permission) ? 'checked' : ''}>
+            <label for="${permission}">${permissionMap[permission]}</label>
+        </div>
+    `).join('');
+}
+
+
+
+
+
+function fetchRoleInfo(roleName, callback) {
+    console.log(`fetchRoleInfo called with roleName: ${roleName}`);
+    
+    fetch('http://127.0.0.1:8080/api/admin/GetRoles', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ Name: roleName })
+    })
+    .then(response => {
+        console.log('fetchRoleInfo response received', response);
+        return response.json();
+    })
+    .then(data => {
+        console.log('fetchRoleInfo data received', data);
+
+        // 直接从 data.data 获取角色信息
+        if (data && data.data) {
+            console.log('Role info found:', data.data);
+            callback(data.data);  // 直接返回 data.data 而不是 data.data[roleName]
+        } else {
+            console.error('Role not found or unexpected data structure', data);
+            callback(null);  // 如果角色信息未找到,返回 null
+        }
+    })
+    .catch(error => {
+        console.error('Error in fetchRoleInfo:', error);
+        callback(null);  // 捕获异常情况
+    });
+}
+
+function getPermissionsOptions(selectedPermissions) {
+    const permissionMap = {
+        'generate_license': '生成许可证',
+        'upload_license': '上传许可证',
+        'read_license': '读取许可证',
+        'update_license': '修改许可证',
+        'delete_license': '删除许可证',
+        'dispat_license': '分发许可证',
+        'read_license_record': '读取许可证分发记录',
+        //'get_user_info': '获取用户信息',
+        'create_user': '创建用户',
+        'read_user': '读取用户',
+        'update_user': '更新用户',
+        'delete_user': '删除用户',
+        'create_role': '创建角色',
+        'delete_role': '删除角色',
+        'update_role': '更新角色',
+        'get_role': '获取角色'
+    };
+    
+    return Object.keys(permissionMap).map(permission => `
+        <option value="${permission}" ${selectedPermissions.includes(permission) ? 'selected' : ''}>
+            ${permissionMap[permission]}
+        </option>
+    `).join('');
+}
+
+function saveRoleChanges(roleId) {
+    const updatedRoleName = document.getElementById('roleName').value.trim();
+    const selectedPermissions = Array.from(document.querySelectorAll('#permissions input[type="checkbox"]:checked'))
+                                    .map(checkbox => checkbox.value)
+                                    .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类
+
+    if (!updatedRoleName) {
+        alert('角色名称不能为空!');
+        return;
+    }
+
+    const updateRole = {
+        Id: parseInt(roleId, 10),  // 确保 roleId 被传递并转换为整数
+        Name: updatedRoleName,
+        Permissions: selectedPermissions
+    };
+
+    fetch('http://127.0.0.1:8080/api/admin/UpdateRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(updateRole)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色更新成功!');
+            fetchRoles(); // 刷新角色列表
+            closeModal('extraInfoModal'); // 关闭信息栏
+        } else {
+            alert('角色更新失败:' + data.error);
+        }
+    });
+}
+
+//删除角色
+function deleteRole(roleName) {
+    console.log(`deleteRole called for role: ${roleName}`);
+    
+    const confirmed = confirm(`确认删除角色: ${roleName} 吗?`);
+    if (!confirmed) {
+        return;
+    }
+
+    fetch('http://127.0.0.1:8080/api/admin/DeleteRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+            name: roleName  // 将角色名称传递给后端
+        })
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色删除成功!');
+            fetchRoles();  // 刷新角色列表
+        } else {
+            alert('角色删除失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        console.error('Error deleting role:', error);
+        alert('删除角色时发生错误,请稍后再试。');
+    });
+}
+
+document.getElementById('createRoleButton').addEventListener('click', function() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+    extraInfoContent.innerHTML = `
+        <h3>创建新角色</h3>
+        <label for="newRoleName">角色名称:</label>
+        <input type="text" id="newRoleName" required><br><br>
+          <label for="newPermissions">权限:</label><br>
+ <div id="newPermissions">
+        <div>
+            <input type="checkbox" id="license" name="permissions" value="license" onchange="toggleSubPermissions('license', this)">
+            <label for="license">许可证</label>
+            <div id="licenseSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="generate_license" name="permissions" value="generate_license">
+                <label for="generate_license">生成许可证</label><br>
+                <input type="checkbox" id="upload_license" name="permissions" value="upload_license">
+                <label for="upload_license">上传许可证</label><br>
+                <input type="checkbox" id="read_license" name="permissions" value="read_license">
+                <label for="read_license">读取许可证</label><br>
+                <input type="checkbox" id="update_license" name="permissions" value="update_license">
+                <label for="update_license">更新许可证</label><br>
+                <input type="checkbox" id="delete_license" name="permissions" value="delete_license">
+                <label for="delete_license">删除许可证</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="user" name="permissions" value="user" onchange="toggleSubPermissions('user', this)">
+            <label for="user">用户</label>
+            <div id="userSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_user" name="permissions" value="create_user">
+                <label for="create_user">创建用户</label><br>
+                <input type="checkbox" id="read_user" name="permissions" value="read_user">
+                <label for="read_user">读取用户</label><br>
+                <input type="checkbox" id="update_user" name="permissions" value="update_user">
+                <label for="update_user">更新用户</label><br>
+                <input type="checkbox" id="delete_user" name="permissions" value="delete_user">
+                <label for="delete_user">删除用户</label><br>
+            </div>
+        </div>
+        <div>
+            <input type="checkbox" id="role" name="permissions" value="role" onchange="toggleSubPermissions('role', this)">
+            <label for="role">角色</label>
+            <div id="roleSubPermissions" style="margin-left: 20px;">
+                <input type="checkbox" id="create_role" name="permissions" value="create_role">
+                <label for="create_role">创建角色</label><br>
+                <input type="checkbox" id="delete_role" name="permissions" value="delete_role">
+                <label for="delete_role">删除角色</label><br>
+                <input type="checkbox" id="update_role" name="permissions" value="update_role">
+                <label for="update_role">更新角色</label><br>
+                <input type="checkbox" id="get_role" name="permissions" value="get_role">
+                <label for="get_role">获取角色</label><br>
+            </div>
+        </div>
+    </div><br><br>
+    <button onclick="createNewRole()">创建</button>
+</div>
+
+     
+    `;
+    document.getElementById('extraInfoModal').style.display = 'block';
+});
+
+
+function toggleSubPermissions(category, checkbox) {
+    const subPermissions = document.querySelectorAll(`#${category}SubPermissions input[type="checkbox"]`);
+    subPermissions.forEach(subCheckbox => {
+        subCheckbox.checked = checkbox.checked;
+    });
+}
+
+function createNewRole() {
+    const newRoleName = document.getElementById('newRoleName').value.trim();
+    const selectedPermissions = Array.from(document.querySelectorAll('#newPermissions input[type="checkbox"]:checked'))
+                                    .map(checkbox => checkbox.value)
+                                    .filter(value => !['license', 'user', 'role'].includes(value)); // 过滤掉一级分类
+
+    if (!newRoleName) {
+        alert('角色名称不能为空!');
+        return;
+    }
+
+    const newRole = {
+        Name: newRoleName,
+        Permissions: selectedPermissions
+    };
+
+    fetch('http://127.0.0.1:8080/api/admin/CreateRole', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(newRole)
+    })
+    .then(response => response.json())
+    .then(data => {
+        if (data.success) {
+            alert('角色创建成功!');
+            fetchRoles(); // 刷新角色列表
+            closeModal('extraInfoModal'); // 关闭信息栏
+        } else {
+            alert('角色创建失败:' + data.error);
+        }
+    });
+}
+
+//显示用户信息
+function showEditUserForm() {
+    const extraInfoContent = document.getElementById('extraInfoContent');
+
+    // 清空之前的内容
+    extraInfoContent.innerHTML = '';
+
+    // 创建表单
+    const form = document.createElement('form');
+    form.id = 'editUserForm';
+    form.style.width = '400px'; // 增加表单宽度
+
+    form.innerHTML = `
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="username" style="flex: 0 0 80px;">用户名:</label>
+            <input type="text" id="username" name="username" value="${selectedRowData.Username}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="telephone" style="flex: 0 0 80px;">电话:</label>
+            <input type="text" id="telephone" name="telephone" value="${selectedRowData.Telephone}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="email" style="flex: 0 0 80px;">邮箱:</label>
+            <input type="email" id="email" name="email" value="${selectedRowData.Email}" style="flex: 1;" required>
+        </div>
+        
+        <div style="display: flex; align-items: center; margin-bottom: 15px;">
+            <label for="role" style="flex: 0 0 80px;">权限:</label>
+            <select id="role" name="role" style="flex: 1;" required></select>
+        </div>
+
+        <button type="button" onclick="saveUserChanges()" style="width: 100%; background-color: #007bff; color: white; border: none; padding: 10px; border-radius: 5px;">保存</button>
+    `;
+
+    // 将表单添加到弹出框内容中
+    extraInfoContent.appendChild(form);
+
+    // 获取角色列表并填充到选择框中
+    fetch('http://127.0.0.1:8080/api/admin/GetRoleNames', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        const roleSelect = document.getElementById('role');
+        data.roles.forEach(role => {
+            const option = document.createElement('option');
+            option.value = role;
+            option.textContent = role;
+            if (selectedRowData.Role === role) {
+                option.selected = true;
+            }
+            roleSelect.appendChild(option);
+        });
+    })
+    .catch(error => console.error('Error fetching roles:', error));
+}
+
+
+function saveUserChanges() {
+            const form = document.getElementById('editUserForm');
+            const formData = new FormData(form);
+            const updatedUser = {
+                Username: formData.get('username'),
+                Telephone: formData.get('telephone'),
+                Email: formData.get('email'),
+                Role: formData.get('role')
+            };
+
+            fetch(`http://127.0.0.1:8080/api/admin/updateUser`, {
+                method: 'POST',
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({ ...updatedUser, Id: selectedRowData.Id })
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success) {
+                    alert('用户信息更新成功!');
+                    fetchUsers();
+                    closeModal('extraInfoModal');
+                } else {
+                    alert('用户信息更新失败:' + data.error);
+                }
+            });
+        }
+
+//用户个人信息
+function toggleUserInfo() {
+    const userModal = document.getElementById('userModal');
+    const userButton = document.getElementById('username');
+    const rect = userButton.getBoundingClientRect();
+    const modalWidth = 300; // 信息栏的宽度
+    const windowWidth = window.innerWidth; // 浏览器窗口的宽度
+
+    if (userModal.style.display === 'none' || userModal.style.display === '') {
+        fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
+            method: 'GET',
+            headers: {
+                'Authorization': `Bearer ${token}`,
+                'Content-Type': 'application/json'
+            }
+        })
+        .then(response => response.json())
+        .then(data => {
+            const userInfoContent = document.getElementById('userInfoContent');
+            let power;
+            switch (data.data.Role) {
+                case 'admin':
+                    power = '至高无上的主';
+                    break;
+                case 'supportRole':
+                    power = '运维';
+                    break;
+                case 'guest':
+                    power = '访客';
+                    break;
+                default:
+                    power = data.data.Role;
+            }
+
+            userInfoContent.innerHTML = `
+               <h2> 个人信息</h2>
+               <div class="apple-modal-content">
+                   <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p>
+                   <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p>
+                   <p class="apple-modal-text"><strong>邮箱:</strong> ${data.data.Email}</p>
+                   <p class="apple-modal-text"><strong>电话:</strong> ${data.data.Telephone}</p>
+                   <p class="apple-modal-text"><strong>权限:</strong> ${power}</p>
+               </div>
+            `;
+
+            // 设置模态框位置
+            userModal.style.top = `${rect.bottom + window.scrollY + 10}px`;
+            const leftPosition = rect.right + window.scrollX + 20; // 右侧位置
+            const rightEdge = leftPosition + modalWidth;
+
+            if (rightEdge > windowWidth) {
+                const leftEdge = rect.left + window.scrollX - modalWidth - 20;
+                userModal.style.left = `${Math.max(20, leftEdge)}px`;
+            } else {
+                userModal.style.left = `${leftPosition}px`;
+            }
+
+            userModal.style.display = 'block';
+            userModal.style.opacity = '0'; // 先设置透明度为0
+            setTimeout(() => {
+                userModal.style.opacity = '1'; // 然后慢慢显示
+            }, 0); // 延迟一帧显示
+
+            userModal.style.transition = 'opacity 0.3s ease, top 0.3s ease, left 0.3s ease';
+
+            // 添加全局点击监听器
+            document.addEventListener('click', handleClickOutsideModal);
+        });
+
+    } else {
+        closeUserInfo();
+    }
+}
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+function handleClickOutsideModal(event) {
+    const userModal = document.getElementById('userModal');
+    if (!userModal.contains(event.target) && event.target.id !== 'username') {
+        closeUserInfo();
+    }
+}
+
+
+//用户退出
+function logout() {
+            localStorage.removeItem('Authorization');
+            window.location.href = '/';
+        }
+
+
+function showUserManagement() {
+    document.getElementById('table-container').style.display = 'none';
+    document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面
+    document.getElementById('user-management').style.display = 'block';
+    
+    // 检查用户是否有 create_user 权限
+    const hasCreateUserPermission = userPermissions.includes('create_user');
+
+    // 获取添加用户按钮元素
+    const addUserButton = document.getElementById('addUserButton');
+
+    // 根据权限显示或隐藏添加用户按钮
+    if (hasCreateUserPermission) {
+        addUserButton.style.display = 'block';
+    } else {
+        addUserButton.style.display = 'none';
+    }
+
+    // 加载用户列表
+    fetchUsers();
+        }
+
+function showTable() {
+    document.getElementById('user-management').style.display = 'none';
+    document.getElementById('role-management').style.display = 'none'; // 隐藏角色管理页面
+    document.getElementById('table-container').style.display = 'block';
+        }
+
+function toggleSidebar() {
+    const sidebar = document.getElementById('sidebar');
+    const content = document.getElementById('content');
+    sidebar.classList.toggle('hidden');
+    content.classList.toggle('expanded');
+
+    const toggleButton = document.querySelector('.toggle-sidebar');
+    if (sidebar.classList.contains('hidden')) {
+        toggleButton.innerHTML = '>';  // 当侧边栏隐藏时,显示右箭头
+    } else {
+        toggleButton.innerHTML = '<';  // 当侧边栏显示时,显示左箭头
+    }
+}
+
+
+
+
+
+
+
+ function fetchUsername() {
+    fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        document.getElementById('username').textContent = data.data.Username;
+        currentUserRole = data.data.Role; // 存储当前用户的角色
+        currentUserName = data.data.Username
+        // 使用获取到的角色,调用获取权限的接口
+        fetchPermissionsByRole(currentUserRole)
+            .then(() => {
+                //fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+                // 检查用户是否有 upload_license 权限
+                const hasUploadLicensePermission = userPermissions.includes('upload_license');
+
+                // 获取上传按钮元素
+                const uploadButton = document.querySelector('.upload-button');
+
+                // 根据权限显示或隐藏上传按钮
+                // if (hasUploadLicensePermission) {
+                //     uploadButton.style.display = 'inline-block'; // 显示按钮
+                // } else {
+                //     uploadButton.style.display = 'none'; // 隐藏按钮
+                // }
+// 是否生成主动抓取lic按钮
+    checkCaptureLicensePermission();
+ // 检查是否有 capture_license_once_to_db 权限
+
+            });
+    });
+}
+
+function fetchPermissionsByRole(role) {
+    return fetch(`http://127.0.0.1:8080/api/admin/GetSelfRoles`, {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ name: role })
+    })
+    .then(response => response.json())
+    .then(data => {
+        userPermissions = data.data.Permissions; // 获取用户的权限数组
+        console.log('userPermissions:', userPermissions);
+        
+        // 定义权限类别
+        const licensePermissions = ['upload_license', 'read_license'];
+        const userPermissionsCheck = [ 'create_user', 'read_user', 'update_user', 'delete_user'];
+        const rolePermissions = ['create_role', 'delete_role', 'update_role', 'get_role'];
+
+        const hasLicenseAccess = licensePermissions.some(permission => userPermissions.includes(permission));
+        const hasUserManagementAccess = userPermissionsCheck.some(permission => userPermissions.includes(permission));
+        const hasRoleManagementAccess = rolePermissions.some(permission => userPermissions.includes(permission));
+
+        // 根据权限渲染菜单并显示初始页面
+        renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess);
+    });
+}
+
+
+
+
+function renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, hasRoleManagementAccess) {
+    const sidebar = document.querySelector('.sidebar');
+
+    // 清空现有菜单项
+    sidebar.innerHTML = '';
+
+    let initialPageShown = false;
+
+    // 动态添加菜单项并确定初始显示的页面
+    if (hasLicenseAccess) {
+        const licenseButton = document.createElement('button');
+        licenseButton.textContent = 'License 管理';
+        licenseButton.onclick = showTable;
+        sidebar.appendChild(licenseButton);
+
+        if (!initialPageShown) {
+            showTable(); // 如果有License权限,先显示License页面
+            initialPageShown = true;
+        }
+    }
+
+    if (hasUserManagementAccess) {
+        const userManagementButton = document.createElement('button');
+        userManagementButton.textContent = '用户管理';
+        userManagementButton.onclick = showUserManagement;
+        sidebar.appendChild(userManagementButton);
+
+        if (!initialPageShown) {
+            showUserManagement(); // 如果没有License权限,但有用户管理权限,显示用户管理页面
+            initialPageShown = true;
+        }
+    }
+
+    if (hasRoleManagementAccess) {
+        const roleManagementButton = document.createElement('button');
+        roleManagementButton.textContent = '角色管理';
+        roleManagementButton.onclick = showRoleManagement;
+        sidebar.appendChild(roleManagementButton);
+
+        if (!initialPageShown) {
+            showRoleManagement(); // 如果没有License和用户管理权限,但有角色管理权限,显示角色管理页面
+            initialPageShown = true;
+        }
+    }
+
+    if (!initialPageShown && sidebar.firstChild) {
+        sidebar.firstChild.click(); // 如果没有优先的权限页面,则显示菜单中的第一个页面
+    }
+}
+
+// 添加到每个模态框的 JavaScript 部分
+document.addEventListener('DOMContentLoaded', function() {
+  
+    // 获取所有模态框
+    const modals = document.querySelectorAll('.modal');
+    
+    // 为每个模态框添加点击事件监听器
+    modals.forEach(modal => {
+        modal.addEventListener('click', function(event) {
+            // 如果点击的是模态框背景而不是模态框内容,关闭模态框
+            if (event.target === modal) {
+                modal.style.display = 'none';
+            }
+        });
+    });
+});
+
+        // 页面初始化时调用 fetchUsername 函数
+        fetchUsername();
+        //fetchApplications(currentPage, pageSize);
+    </script>
+</body>
+</html>

+ 24 - 15
static/license_info/license_info copy.html

@@ -1316,7 +1316,8 @@ function fetchApplications(page, size) {
         tableHead.innerHTML = `
             <th></th> <!-- 添加一个空的表头用于放置下拉按钮 -->
             <th>创建人</th>
-            <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>
+            <th>申请日期 </th> 
+               <!--   <th>申请日期 <button class="sort-button" onclick="sortTableByDate()">排序</button></th>-->
             <th>关联项目</th>
             <th>销售人员</th>
             <th>技服人员</th>
@@ -1538,6 +1539,9 @@ dropdownButton.addEventListener('click', (event) => {
     });
 }
 
+let currentOffset = 1;
+const itemsPerPage = 10;
+
 // 添加页数选择框的事件监听器
 document.getElementById('page-selector').addEventListener('change', (event) => {
      selectedPage = parseInt(event.target.value, 10);
@@ -1547,6 +1551,8 @@ document.getElementById('page-selector').addEventListener('change', (event) => {
     LisOffset = selectedPage
     pageSize = LisOffset* 10; 
     currentPage = selectedPage 
+    currentOffset = startRecord
+    endOffset = endRecord
     fetchApplications(startRecord, endRecord);
 });
 
@@ -1562,8 +1568,7 @@ document.getElementById('prev-page').addEventListener('click', () => {
         fetchApplications(startOffset, endOffset);
     }
 });
-let currentOffset = 1;
-const itemsPerPage = 10;
+
 
 document.getElementById('next-page').addEventListener('click', () => {
     if (currentPage < totalPages) {
@@ -1657,7 +1662,10 @@ function generateLicense(id, isParentRow) {
     .then(data => {
         if (data.success) {
             alert('License生成成功!');
-            fetchApplications(LisOffset, pageSize);
+            const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+        //    fetchApplications(LisOffset, pageSize);
         } else {
             alert('License生成失败:' + data.error);
         }
@@ -2113,7 +2121,10 @@ function confirmDeleteUser(uniqueID) {
                 if (response.ok) {
                     alert('删除成功');
                     closeModal('confirmDeleteModal');
-                    fetchApplications(LisOffset, pageSize);
+                  //  fetchApplications(LisOffset, pageSize);
+                  const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
                 } else {
                     alert('删除失败');
                 }
@@ -2367,7 +2378,10 @@ function saveLicenseChanges() {
     .then(data => {
         if (data.success) {
             alert('License信息更新成功!');
-            fetchApplications(LisOffset, pageSize);
+          //  fetchApplications(LisOffset, pageSize);
+          const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
             closeModal('modifyLicenseModal');
         } else {
             alert('License信息更新失败:' + data.error);
@@ -3486,14 +3500,6 @@ function toggleSidebar() {
 
 
 
-// document.getElementById('prev-page').addEventListener('click', () => {
-//             if (currentPage > 1) {
-//                 fetchApplications(currentPage - 1, pageSize);
-//             }
-//         });
-//  document.getElementById('next-page').addEventListener('click', () => {
-//             fetchApplications(currentPage + 1, pageSize);
-//         });
 
  function fetchUsername() {
     fetch(`http://127.0.0.1:8080/api/admin/userInfo`, {
@@ -3511,7 +3517,10 @@ function toggleSidebar() {
         // 使用获取到的角色,调用获取权限的接口
         fetchPermissionsByRole(currentUserRole)
             .then(() => {
-                fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                //fetchApplications(LisOffset, pageSize); // 确保在权限获取之后才调用 fetchApplications
+                const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
                 // 检查用户是否有 upload_license 权限
                 const hasUploadLicensePermission = userPermissions.includes('upload_license');
 

+ 323 - 151
static/license_info/license_info.html

@@ -13,7 +13,7 @@
             padding: 0;
             display: flex;
         }
-        header {
+header {
     display: flex;
     justify-content: space-between;
     align-items: center;
@@ -34,6 +34,26 @@ h1 {
             font-weight: 600;
             margin: 0;
         }
+
+    .CaptureLicenseOnce-button {
+   background-color: white;
+    color: #007aff;
+    border: 2px solid #007aff;
+    padding: 10px 20px;
+    border-radius: 10px;
+    cursor: pointer;
+    font-size: 16px;
+    font-weight: 500;
+    box-shadow: none;
+    transition: background-color 0.3s, color 0.3s;
+    float: right; /* 将按钮移动到左侧 */
+}
+
+.CaptureLicenseOnce-button:hover {
+    background-color: #0eb3ff;
+    color: white;
+}
+        
       
 /* 扁平风格的选择框 */
 .flat-select {
@@ -112,6 +132,7 @@ h1 {
     background-color: white;
     box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
     margin-bottom: 20px;
+    min-width: 300px; /* 添加最小宽度 */
 }
 
 .apple-modal-title {
@@ -1008,13 +1029,15 @@ tr:last-child td:last-child {
     <div class="content" id="content">
         <button class="toggle-sidebar" onclick="toggleSidebar()">←</button>
         <header>
-            <h1>License 管理平台</h1>
+            <h1>XUGU License 管理平台</h1>
             <div>
              <!--   <button class="upload-button" onclick="window.location.href='/static/upload_xlsx/index.html'" style="display: none;">Upload File</button> --> <!-- 默认隐藏 -->
                 <button class="user-button" onclick="toggleUserInfo()" id="username">User</button>
+             
             </div>
             
         </header>
+        
         <div id="table-container">
             <table id="applications-table">
                 <thead>
@@ -1040,7 +1063,10 @@ tr:last-child td:last-child {
                 <button id="next-page">下一页</button>
                 <select id="page-selector" class="flat-select"></select>
                 <span id="pagination-info">第 1 页,共 0 页</span> <!-- 新增信息显示区域 -->
-             
+                <div id="capture-license-button-container">
+                    <!-- 按钮将在这里插入 -->
+                </div>
+             <!--   <button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button>   动态插入按钮的容器 -->
             </div>
         </div>
 <!-- License 详细信息的模态框 -->
@@ -1265,6 +1291,7 @@ tr:last-child td:last-child {
     </div>
 
 <script>
+    //翻页有关,还需优化
         let currentPage = 1;
         let pageSize = 10;
         let LisOffset = 1;
@@ -1272,8 +1299,10 @@ tr:last-child td:last-child {
         let selectedPage =1;
         let nextPage =1;
         let prevPage = 10;
+//用户token
         const token = localStorage.getItem('Authorization');
-        let selectedRowData = null;
+//选中行的数据
+        let selectedRowData = null;//选中行的数据
         let isAscending = true;
         let userMap = {}; // 用于存储用户名和用户ID的映射
         let currentUserRole = ''; // 新增变量存储当前用户的权限
@@ -1288,8 +1317,16 @@ function checkPermission(permission) {
     return userPermissions.includes(permission);
 }
 
+async function initialize() {
+    await fetchUsername(); // 确保 fetchUsername 完成
+    fetchApplications(1, 10); // 然后再调用 fetchApplications
+
+
+}
+  
 //获取license展示信息
 function fetchApplications(page, size) {
+    
     fetch(`http://127.0.0.1:8080/api/admin/GetAllLicenseInfo?page=${page}&pageSize=${size}`, {
         method: 'GET',
         headers: {
@@ -1299,11 +1336,14 @@ function fetchApplications(page, size) {
     })
     .then(response => response.json())
     .then(data => {
+      //selectedRowData = data.data;
         LicApplicationData = data.data; // 将接收到的数据存储到全局变量
-        console.log(data); // 输出获取的数据结构
-
+        console.log("lic数据",data); // 输出获取的数据结构
+        console.log("z该死的权限数组",userPermissions); 
         const hasGeneratePermission = userPermissions.includes("generate_license");
         const hasDistributePermission = userPermissions.includes("dispat_license");
+
+    
  // 更新总页数
  //totalPages = Math.ceil(data.total / 10);
         // 在控制台打印权限结果
@@ -1357,22 +1397,21 @@ function fetchApplications(page, size) {
             `;
             row.querySelector('td').appendChild(dropdownButton);
 
-            // 添加 License 状态按钮 (父级行)
-          
+    // 添加 License 状态按钮 (父级行)
     if (hasGeneratePermission || hasDistributePermission) {
         const licenseStatusCell = document.createElement('td');
 
         if (hasGeneratePermission && showGenerateButton) {
             licenseStatusCell.innerHTML += `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${firstApplication.oa_request_id}', true)">生成</button>`;
         } else if (hasDistributePermission && firstApplication.LicenseFlage === "已生成") {
-            licenseStatusCell.innerHTML += `<button class="license-status-btn distribute" onclick="showEmailModal('${firstApplication.SupportEmail}', '${firstApplication.SalesEmail}', '${firstApplication.UniqueID}')">分发</button>`;
+            licenseStatusCell.innerHTML += `<button class="license-status-btn distribute" onclick="showEmailModal('${firstApplication.SupportEmail}', '${firstApplication.SalesEmail}','','${firstApplication.oa_request_id}')">分发</button>`;
         }
 
         // 添加一个分隔符
         licenseStatusCell.innerHTML += `<span style="margin: 0 10px; display: inline-block; width: 1px; height: 20px; background-color: #ccc;"></span>`;
 
         // 在这里添加“查看详情”按钮
-        licenseStatusCell.innerHTML += `<button class="license-status-btn view-details" onclick="showDetailsModal('${firstApplication.UniqueID}')">查看详情</button>`;
+        licenseStatusCell.innerHTML += `<button class="license-status-btn view-details" onclick="showDetailsModal('${firstApplication.UniqueID}', false)">查看详情</button>`;
 
         row.appendChild(licenseStatusCell);
 }
@@ -1413,8 +1452,8 @@ function fetchApplications(page, size) {
                     <td>${createEllipsisText(detail.oa_main_mac)}</td>
                     <td>${createEllipsisText(detail.oa_second_mac)}</td>
                 `;
-
-                // 添加 License 状态按钮 (子行)
+//保留这里的代码,涉及到子行的单独申请
+                // 添加 License 状态按钮 (子行) 
                 // if (hasGeneratePermission || hasDistributePermission) {
                 //     const licenseStatusDetailCell = document.createElement('td');
 
@@ -1423,7 +1462,7 @@ function fetchApplications(page, size) {
                 //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn generate" onclick="confirmGenerateLicense('${detail.UniqueID}', false)">生成</button>`;
                 //     } else if (hasDistributePermission && detail.LicenseFlage === "已生成") {
                 //         // 子行点击分发按钮时,传递 UniqueID 用于分发操作
-                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn distribute" onclick="showEmailModal('${detail.SupportEmail}', '${detail.SalesEmail}', '${detail.UniqueID}')">分发</button>`;
+                //         licenseStatusDetailCell.innerHTML = `<button class="license-status-btn distribute" onclick="showEmailModal('${detail.SupportEmail}', '${detail.SalesEmail}', '${detail.UniqueID}','')">分发</button>`;
                 //     }
 
                 //     detailInnerRow.appendChild(licenseStatusDetailCell);
@@ -1488,8 +1527,15 @@ function fetchApplications(page, size) {
         dropdownButton.classList.toggle('rotate-arrow', !isExpanded);
     }
     }
+
+    
 });
 
+
+
+
+
+
 dropdownButton.addEventListener('click', (event) => {
     // event.stopPropagation(); // 阻止事件冒泡到行点击事件
     // const isExpanded = detailCell.style.display === 'table-cell';
@@ -1517,7 +1563,6 @@ dropdownButton.addEventListener('click', (event) => {
         document.getElementById('pagination-info').textContent = `第 ${currentPage} 页,共 ${totalPages} 页`;
         document.getElementById('prev-page').disabled = currentPage <= 1;
         document.getElementById('next-page').disabled = currentPage >= totalPages;
-
         const pageSelector = document.getElementById('page-selector');
         pageSelector.innerHTML = '';
         for (let i = 1; i <= totalPages; i++) {
@@ -1539,6 +1584,28 @@ dropdownButton.addEventListener('click', (event) => {
     });
 }
 
+function checkCaptureLicensePermission() {
+  
+
+    // 获取插入按钮的容器元素
+    const container = document.getElementById('capture-license-button-container');
+
+    if (container) {  // 确保容器元素存在
+        if (userPermissions.includes('capture_license_once_to_db')) {
+            // 如果有权限,插入按钮
+            const CaptureLicensebuttonHtml = `<button class="CaptureLicenseOnce-button" onclick="CaptureLicenseOncefunc()">获取最新license</button>`;
+            container.innerHTML = CaptureLicensebuttonHtml;
+        } else {
+            // 如果没有权限,确保不显示按钮
+            container.innerHTML = ''; // 清空容器
+        }
+    } else {
+        console.error('找不到 capture-license-button-container 元素');
+    }
+}
+
+
+
 let currentOffset = 1;
 const itemsPerPage = 10;
 
@@ -1554,6 +1621,7 @@ document.getElementById('page-selector').addEventListener('change', (event) => {
     currentOffset = startRecord
     endOffset = endRecord
     fetchApplications(startRecord, endRecord);
+
 });
 
 // 分页按钮事件监听器
@@ -1588,8 +1656,8 @@ document.getElementById('next-page').addEventListener('click', () => {
 // 页面加载时默认调用第一页的数据
 //fetchApplications(1);
 // 页面初始化时调用 fetchUsername 函数
-fetchUsername();
-fetchApplications(LisOffset,pageSize);
+
+//fetchApplications(LisOffset,pageSize);
 
 //排序
 // function sortTableByDate() {
@@ -1622,7 +1690,6 @@ function closeAllExpandedRows() {
 
 
 
-
 // 创建带省略号的文本,并在鼠标悬停时显示完整内容
 function createEllipsisText(text) {
     const maxLength = 20; // 最大显示字符数
@@ -1674,85 +1741,137 @@ function generateLicense(id, isParentRow) {
 }
 
 
+//主动抓取一次Licen数据
+function CaptureLicenseOncefunc() {
+    // 显示加载模态框
+    const loadingModal = document.createElement('div');
+    loadingModal.classList.add('modal-content', 'apple-modal-content');
+    loadingModal.innerHTML = `
+        <h3>正在获取 License 信息...</h3>
+        <div class="progress-bar" style="width: 100%; height: 20px; background-color: #e0e0e0;">
+            <div class="progress" style="width: 50%; height: 100%; background-color: #007aff;"></div>
+        </div>
+    `;
+    document.body.appendChild(loadingModal);
 
+    // 定义超时函数
+    const timeoutPromise = new Promise((_, reject) => {
+        setTimeout(() => {
+            reject(new Error('获取超时'));
+        }, 10000); // 10秒超时
+    });
+
+    // 发起 GET 请求的 Promise
+    const fetchPromise = fetch('http://127.0.0.1:8080/api/admin/GetCaptureLicenseOnce', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${token}`,
+            'Content-Type': 'application/json'
+        }
+    }).then(response => response.json());
 
+    // 使用 Promise.race 来竞争两个 Promise,哪个先返回就使用哪个
+    Promise.race([fetchPromise, timeoutPromise])
+    .then(data => {
+        // 先关闭进度条
+        document.body.removeChild(loadingModal);
+
+        // 显示成功或失败提示
+        if (data.success) {
+            alert('License 获取成功!');
+        } else {
+            alert('获取失败:' + data.error);
+        }
+    })
+    .catch(error => {
+        // 先关闭进度条
+        document.body.removeChild(loadingModal);
+        
+        // 显示错误提示
+        alert(error.message); // 如果超时或请求失败
+    });
+}
 
 
 //查看lic所有信息
-function showDetailsModal(uniqueID, isChildRow = false) {
-    let selectedData = null;
+// 查看lic所有信息
+function showDetailsModal(uniqueID, isChildRow = false, page = 1) {
+    console.log("当前 uniqueID:", uniqueID);
+    console.log("当前 isChildRow:", isChildRow);
+    console.log("当前页码:", page);
 
-    if (isChildRow) {
-        // 查找子行数据
-        for (let applicationArray of LicApplicationData) {
-            selectedData = applicationArray.find(data => data.UniqueID === uniqueID);
-            if (selectedData) {
-                break;
-            }
-        }
+    let selectedData = null;
+    const itemsPerPage = 1; // 每页只显示一个子行数据
+    let currentPage = page; // 当前页码
 
-        if (!selectedData) {
-            console.error('未找到对应的子行记录,UniqueID:', uniqueID);
-            alert('未找到对应的子行记录,请检查数据');
-            return;
+    // 查找主行和子行数据
+    console.log("查找主行和子行数据");
+    let selectedApplicationArray = null;
+    for (let applicationArray of LicApplicationData) {
+        if (applicationArray.some(data => data.UniqueID === uniqueID)) {
+            selectedApplicationArray = applicationArray;
+            break;
         }
+    }
 
-        // 准备在模态框中显示的子行内容
-        let detailsHtml = `<div class="apple-modal-content">`;
-        detailsHtml += `<h3 class="apple-modal-title">详细信息</h3>`;
-        detailsHtml += `
-            <p class="apple-modal-text"><strong>产品名称:</strong> ${selectedData.ProductName}</p>
-            <p class="apple-modal-text"><strong>版本:</strong> ${selectedData.ProductVersion}</p>
-            <p class="apple-modal-text"><strong>节点数:</strong> ${selectedData.NodeCount}</p>
-            <p class="apple-modal-text"><strong>处理器:</strong> ${selectedData.oa_cpu}</p>
-            <p class="apple-modal-text"><strong>操作系统:</strong> ${selectedData.oa_operating_system}</p>
-            <p class="apple-modal-text"><strong>主MAC地址:</strong> ${selectedData.oa_main_mac}</p>
-            <p class="apple-modal-text"><strong>副MAC地址:</strong> ${selectedData.oa_second_mac}</p>
-        `;
-        detailsHtml += `</div>`;
-
-        // 显示模态框
-        document.getElementById('detailsContent').innerHTML = detailsHtml;
-        document.getElementById('detailsModal').style.display = 'block';
+    if (!selectedApplicationArray) {
+        console.error('未找到对应的记录,UniqueID:', uniqueID);
+        alert('未找到对应的记录,请检查数据');
+        return;
+    }
 
-    } else {
-        // 查找主行数据
-        let selectedApplicationArray = null;
+    let detailsHtml = `<div class="apple-modal-content">`;
 
-        for (let applicationArray of LicApplicationData) {
-            if (applicationArray.some(data => data.UniqueID === uniqueID)) {
-                selectedApplicationArray = applicationArray;
-                break;
-            }
+    // 如果是子行,直接显示该子行的信息,不进行分页
+    if (isChildRow) {
+    
+        // 查找唯一的子行数据
+        const childData = selectedApplicationArray.find(data => data.UniqueID === uniqueID);
+        if (childData) {
+            detailsHtml += `
+                
+                <p class="apple-modal-text"><strong>产品名称:</strong> ${childData.ProductName}</p>
+                <p class="apple-modal-text"><strong>版本:</strong> ${childData.ProductVersion}</p>
+                <p class="apple-modal-text"><strong>节点数:</strong> ${childData.NodeCount}</p>
+                <p class="apple-modal-text"><strong>处理器:</strong> ${childData.oa_cpu}</p>
+                <p class="apple-modal-text"><strong>操作系统:</strong> ${childData.oa_operating_system}</p>
+                <p class="apple-modal-text"><strong>主MAC地址:</strong> ${childData.oa_main_mac}</p>
+                <p class="apple-modal-text"><strong>副MAC地址:</strong> ${childData.oa_second_mac}</p>
+            `;
+        } else {
+            detailsHtml += `<p>未找到对应的子行记录。</p>`;
         }
+    } else {
+        // 如果是主行,使用分页显示主行和子行信息
+    
 
-        if (!selectedApplicationArray) {
-            console.error('未找到对应的记录,UniqueID:', uniqueID);
-            alert('未找到对应的记录,请检查数据');
-            return;
-        }
+        // 计算总页数
+        const totalItems = selectedApplicationArray.length;
+        const totalPages = totalItems + 1; // 主行为第一页,后续为子行
+        console.log("totalItems: ", totalItems);
+        console.log("totalPages: ", totalPages);
 
-        // 准备在模态框中显示的主行和子行的全部内容
-        let detailsHtml = `<div class="apple-modal-content">`;
-        detailsHtml += `<h3 class="apple-modal-title">项目信息</h3>`;
-        
-        // 显示主行的第一条记录信息
-        const firstData = selectedApplicationArray[0];
-        detailsHtml += `
-            <p class="apple-modal-text"><strong>创建人:</strong> ${firstData.Creator}</p>
-            <p class="apple-modal-text"><strong>申请日期:</strong> ${firstData.ApplicationDate}</p>
-            <p class="apple-modal-text"><strong>关联项目:</strong> ${firstData.GlxmName}</p>
-            <p class="apple-modal-text"><strong>销售人员:</strong> ${firstData.SalesPerson}</p>
-            <p class="apple-modal-text"><strong>技服人员:</strong> ${firstData.SupportPerson}</p>
-            <p class="apple-modal-text"><strong>总节点数:</strong> ${firstData.TotalNodes}</p>
-            <p class="apple-modal-text"><strong>使用单位:</strong> ${firstData.Company}</p>
-        `;
+        if (currentPage === 1) {
+            // 显示主行内容(第一页)
+  
+            detailsHtml += `<h3 class="apple-modal-title">项目信息</h3>`;
+            const firstData = selectedApplicationArray[0];
+            detailsHtml += `
+                <p class="apple-modal-text"><strong>创建人:</strong> ${firstData.Creator}</p>
+                <p class="apple-modal-text"><strong>申请日期:</strong> ${firstData.ApplicationDate}</p>
+                <p class="apple-modal-text"><strong>关联项目:</strong> ${firstData.GlxmName}</p>
+                <p class="apple-modal-text"><strong>销售人员:</strong> ${firstData.SalesPerson}</p>
+                <p class="apple-modal-text"><strong>技服人员:</strong> ${firstData.SupportPerson}</p>
+                <p class="apple-modal-text"><strong>总节点数:</strong> ${firstData.TotalNodes}</p>
+                <p class="apple-modal-text"><strong>使用单位:</strong> ${firstData.Company}</p>
+            `;
+        } else {
+            // 显示子行内容(从第二页开始)
 
-        // 显示子行的每条记录信息
-        detailsHtml += `<h3 class="apple-modal-title">集群信息</h3>`;
-        selectedApplicationArray.forEach((data, index) => {
+            const dataIndex = currentPage - 2; // 当前页对应的子行数据索引,主行占用第一页
+            const data = selectedApplicationArray[dataIndex];
             detailsHtml += `
-                <h4 class="apple-modal-subtitle">集群 ${index + 1}</h4>
+                <h4 class="apple-modal-subtitle">集群 ${currentPage - 1}</h4>
                 <p class="apple-modal-text"><strong>产品名称:</strong> ${data.ProductName}</p>
                 <p class="apple-modal-text"><strong>版本:</strong> ${data.ProductVersion}</p>
                 <p class="apple-modal-text"><strong>节点数:</strong> ${data.NodeCount}</p>
@@ -1760,16 +1879,27 @@ function showDetailsModal(uniqueID, isChildRow = false) {
                 <p class="apple-modal-text"><strong>操作系统:</strong> ${data.oa_operating_system}</p>
                 <p class="apple-modal-text"><strong>主MAC地址:</strong> ${data.oa_main_mac}</p>
                 <p class="apple-modal-text"><strong>副MAC地址:</strong> ${data.oa_second_mac}</p>
-                <h4 class="apple-modal-subtitle"> -------------------------------</h4>
             `;
-        });
+        }
 
+        // 添加分页按钮
+        detailsHtml += `<div class="pagination-controls" style="text-align: center;">`;
+        if (currentPage > 1) {
+            detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage - 1})">上一页</button>`;
+        }
+        detailsHtml += `<hr style="margin: 10px 0; border-top: 1px solid #ccc;">`; // 分隔符
+        if (currentPage < totalPages) {
+            detailsHtml += `<button style="font-size: 12px; padding: 5px 10px; width: 80px;" onclick="showDetailsModal('${uniqueID}', ${isChildRow}, ${currentPage + 1})">下一页</button>`;
+        }
         detailsHtml += `</div>`;
-
-        // 显示模态框
-        document.getElementById('detailsContent').innerHTML = detailsHtml;
-        document.getElementById('detailsModal').style.display = 'block';
     }
+
+    detailsHtml += `</div>`;
+
+    console.log("detailsHtml: ", detailsHtml);
+
+    document.getElementById('detailsContent').innerHTML = detailsHtml;
+    document.getElementById('detailsModal').style.display = 'block';
 }
 
 
@@ -1980,10 +2110,11 @@ function closeModal(modalId) {
         }
 
 
-function closeUserInfo() {
-            document.getElementById('userModal').style.display = 'none';
-        }
+// function closeUserInfo() {
+//             document.getElementById('userModal').style.display = 'none';
+//         }
 
+//删除一行lic信息
 function confirmDelete() {
     const confirmDeleteModal = document.getElementById('confirmDeleteModal');
     confirmDeleteModal.innerHTML = `
@@ -2003,10 +2134,35 @@ function confirmDelete() {
     confirmDeleteModal.style.display = 'block';
 }
 
+function deleteRow() {
+            fetch(`http://127.0.0.1:8080/api/admin/deleteLicRow`, {
+                method: 'POST',
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
+            }).then(response => {
+                if (response.ok) {
+                    alert('删除成功');
+                    closeModal('confirmDeleteModal');
+                  //  fetchApplications(LisOffset, pageSize);
+                  const startOffset = currentOffset;  // 当前的起始位置
+    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
+    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
+                } else {
+                    alert('删除失败');
+                }
+            });
+        }
+
+
+
 //添加用户
 document.getElementById('addUserButton').addEventListener('click', function() {
     document.getElementById('addUserModal').style.display = 'block';
 });
+
 //添加用户
 function saveNewUser() {
     const username = document.getElementById('addUsername').value.trim();
@@ -2109,31 +2265,9 @@ function confirmDeleteUser(uniqueID) {
     }
 }
 
- function deleteRow() {
-            fetch(`http://127.0.0.1:8080/api/admin/deleteLicRow`, {
-                method: 'POST',
-                headers: {
-                    'Authorization': `Bearer ${token}`,
-                    'Content-Type': 'application/json'
-                },
-                body: JSON.stringify({ uniqueID: selectedRowData.UniqueID })
-            }).then(response => {
-                if (response.ok) {
-                    alert('删除成功');
-                    closeModal('confirmDeleteModal');
-                  //  fetchApplications(LisOffset, pageSize);
-                  const startOffset = currentOffset;  // 当前的起始位置
-    const endOffset = startOffset + itemsPerPage - 1;  // 计算结束位置
-    fetchApplications(startOffset, endOffset);  // 传入计算好的起始和结束位置
-                } else {
-                    alert('删除失败');
-                }
-            });
-        }
-
-
 
-function showEmailModal(supportEmail, salesEmail, uniqueID) {
+// 分发模态框
+function showEmailModal(supportEmail, salesEmail, uniqueID,oa_request_id) {
     // 清空并设置默认值
     document.getElementById('emailInputs').innerHTML = `
         <div>
@@ -2181,7 +2315,7 @@ function showEmailModal(supportEmail, salesEmail, uniqueID) {
     });
 
     document.getElementById('emailModal').style.display = 'block';
-    selectedRowData = { ...selectedRowData, UniqueID: uniqueID };
+    selectedRowData = { ...selectedRowData, UniqueID: uniqueID ,Oa_request_id: oa_request_id};
 }
 
 function addEmailInput() {
@@ -2484,6 +2618,7 @@ function sendEmail() {
 
     const requestData = {
         LicenseUniqueID: selectedRowData.UniqueID,
+        Oa_request_id: selectedRowData.Oa_request_id,
         UserUniqueIDs: userIds.split(','), 
         UserAccounts: users.split(','), 
         Emails: emails,
@@ -3356,7 +3491,7 @@ function saveUserChanges() {
             });
         }
 
-
+//用户个人信息
 function toggleUserInfo() {
     const userModal = document.getElementById('userModal');
     const userButton = document.getElementById('username');
@@ -3392,27 +3527,24 @@ function toggleUserInfo() {
 
             userInfoContent.innerHTML = `
                <h2> 个人信息</h2>
-    <div class="apple-modal-content">
-        <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p>
-        <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p>
-        <p class="apple-modal-text"><strong>邮箱:</strong> ${data.data.Email}</p>
-        <p class="apple-modal-text"><strong>电话:</strong> ${data.data.Telephone}</p>
-        <p class="apple-modal-text"><strong>权限:</strong> ${power}</p>
-    </div>
-`;
+               <div class="apple-modal-content">
+                   <p class="apple-modal-text"><strong>用户名:</strong> ${data.data.Username}</p>
+                   <p class="apple-modal-text"><strong>账号:</strong> ${data.data.Account}</p>
+                   <p class="apple-modal-text"><strong>邮箱:</strong> ${data.data.Email}</p>
+                   <p class="apple-modal-text"><strong>电话:</strong> ${data.data.Telephone}</p>
+                   <p class="apple-modal-text"><strong>权限:</strong> ${power}</p>
+               </div>
+            `;
 
-            // 设置弹出框位置
+            // 设置模态框位置
             userModal.style.top = `${rect.bottom + window.scrollY + 10}px`;
-
             const leftPosition = rect.right + window.scrollX + 20; // 右侧位置
             const rightEdge = leftPosition + modalWidth;
 
             if (rightEdge > windowWidth) {
-                // 如果右侧超出窗口宽度,则将信息栏移动到按钮的左侧
                 const leftEdge = rect.left + window.scrollX - modalWidth - 20;
                 userModal.style.left = `${Math.max(20, leftEdge)}px`;
             } else {
-                // 否则显示在按钮右侧
                 userModal.style.left = `${leftPosition}px`;
             }
 
@@ -3422,36 +3554,55 @@ function toggleUserInfo() {
                 userModal.style.opacity = '1'; // 然后慢慢显示
             }, 0); // 延迟一帧显示
 
-            // 增加过渡效果
             userModal.style.transition = 'opacity 0.3s ease, top 0.3s ease, left 0.3s ease';
+
+            // 添加全局点击监听器
+            document.addEventListener('click', handleClickOutsideModal);
         });
+
     } else {
-        userModal.style.opacity = '0'; // 先设置透明度为0
-        setTimeout(() => {
-            userModal.style.display = 'none'; // 然后隐藏
-        }, 300); // 延迟0.3秒,等待过渡结束
+        closeUserInfo();
+    }
+}
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+
+
+function closeUserInfo() {
+    const userModal = document.getElementById('userModal');
+    userModal.style.opacity = '0'; // 先设置透明度为0
+    setTimeout(() => {
+        userModal.style.display = 'none'; // 然后隐藏
+    }, 300); // 延迟0.3秒,等待过渡结束
+
+    // 移除全局点击监听器
+    document.removeEventListener('click', handleClickOutsideModal);
+}
+
+function handleClickOutsideModal(event) {
+    const userModal = document.getElementById('userModal');
+    if (!userModal.contains(event.target) && event.target.id !== 'username') {
+        closeUserInfo();
     }
 }
 
 
-        function logout() {
+//用户退出
+function logout() {
             localStorage.removeItem('Authorization');
             window.location.href = '/';
         }
 
-// 添加到每个模态框的 JavaScript 部分
-document.addEventListener('DOMContentLoaded', function() {
-    const modals = document.querySelectorAll('.modal');
-
-    modals.forEach(modal => {
-        modal.addEventListener('click', function(event) {
-            // 判断是否点击的是 modal 的背景
-            if (event.target === modal) {
-                modal.style.display = 'none';
-            }
-        });
-    });
-});
 
 function showUserManagement() {
     document.getElementById('table-container').style.display = 'none';
@@ -3528,11 +3679,15 @@ function toggleSidebar() {
                 const uploadButton = document.querySelector('.upload-button');
 
                 // 根据权限显示或隐藏上传按钮
-                if (hasUploadLicensePermission) {
-                    uploadButton.style.display = 'inline-block'; // 显示按钮
-                } else {
-                    uploadButton.style.display = 'none'; // 隐藏按钮
-                }
+                // if (hasUploadLicensePermission) {
+                //     uploadButton.style.display = 'inline-block'; // 显示按钮
+                // } else {
+                //     uploadButton.style.display = 'none'; // 隐藏按钮
+                // }
+// 是否生成主动抓取lic按钮
+    checkCaptureLicensePermission();
+ // 检查是否有 capture_license_once_to_db 权限
+
             });
     });
 }
@@ -3618,6 +3773,23 @@ function renderMenuAndInitialPage(hasLicenseAccess, hasUserManagementAccess, has
     }
 }
 
+// 添加到每个模态框的 JavaScript 部分
+document.addEventListener('DOMContentLoaded', function() {
+  
+    // 获取所有模态框
+    const modals = document.querySelectorAll('.modal');
+    
+    // 为每个模态框添加点击事件监听器
+    modals.forEach(modal => {
+        modal.addEventListener('click', function(event) {
+            // 如果点击的是模态框背景而不是模态框内容,关闭模态框
+            if (event.target === modal) {
+                modal.style.display = 'none';
+            }
+        });
+    });
+});
+
         // 页面初始化时调用 fetchUsername 函数
         fetchUsername();
         //fetchApplications(currentPage, pageSize);

+ 3 - 1
支持库建表语句.sql

@@ -44,7 +44,7 @@ CREATE TABLE target_OA_license (
     id INTEGER IDENTITY(1,1) PRIMARY KEY COMMENT '自增主键,从1开始,每次递增1',
     Unique_ID VARCHAR(36) UNIQUE  NOT NULL   COMMENT '每行数据的唯一值ID,理论上有oa的REQUESTID就可以了',
     OA_ID INTEGER COMMENT 'oa 一行的ID',
-    OA_REQUESTID INTEGER COMMENT 'oa里的申请单请求ID,假设唯一标识',
+    OA_REQUESTID INTEGER COMMENT 'oa里的申请单请求ID',
     OA_REQUESTNAME VARCHAR(255) COMMENT '请求名称',
     OA_REQUESTNAMENEW VARCHAR(255) COMMENT '新请求名称',
     OA_REQUESTNAMEHTMLNEW VARCHAR(255) COMMENT '新请求名称(HTML格式)',
@@ -91,6 +91,7 @@ CREATE TABLE License_generate_Info (
 CREATE TABLE licenseRecordToUser (
     ID INT IDENTITY(1,1) PRIMARY KEY,
     License_UniqueID VARCHAR(36),
+    OA_REQUESTID INTEGER COMMENT 'oa里的申请单请求ID',
     user_UNIQUEID VARCHAR(255),
     User_Account VARCHAR(255),
     operator_UniqueID VARCHAR(255),
@@ -104,6 +105,7 @@ CREATE TABLE licenseRecordToUser (
 CREATE TABLE licenseRecordToEmails (
     ID INT IDENTITY(1,1) PRIMARY KEY,
     License_UniqueID VARCHAR(36),
+    OA_REQUESTID INTEGER COMMENT 'oa里的申请单请求ID',
     emails VARCHAR(255),
     operator_UniqueID VARCHAR(255),
     up_Time DATETIME,

+ 9 - 0
模拟oa库环境.sql

@@ -182,6 +182,15 @@ END;
             '虚谷v12 ' ,  -- SELECTNAME
              14627  -- FIELDID
         );
+        INSERT INTO XUGU.WORKFLOW_SELECTITEM (
+            "SELECTVALUE", 
+            "SELECTNAME", 
+            "FIELDID"
+        ) VALUES (
+            1,  -- SELECTVALUE
+            '分布式 ' ,  -- SELECTNAME
+             14628  -- FIELDID
+        );
         -- 插入到 HRMRESOURCE 表
         INSERT INTO XUGU.HRMRESOURCE (
             "ID",