Browse Source

新增分发

GTong 8 tháng trước cách đây
mục cha
commit
08b2c3b865

+ 2 - 2
config.toml

@@ -3,13 +3,13 @@ ip = "127.0.0.1"
 port = "8080"
 
 [database]
-oadb_ip = "127.0.0.1"
+oadb_ip = "10.28.20.233"
 oadb_port = "5138"
 oadb_db = "OAdb"
 oadb_user = "SYSDBA"
 oadb_password = "SYSDBA"
 
-licdb_ip = "127.0.0.1"
+licdb_ip = "10.28.20.233"
 licdb_port = "5138"
 licdb_db = "license"
 licdb_user = "SYSDBA"

+ 6 - 6
internal/api/license_api.go

@@ -43,14 +43,14 @@ type AllLicenseInfoResponse struct {
 
 // 生成license串请求
 type GenerateLicenseStrRequest struct {
-	OARequestId string `json:"oa_request_id"`
+	OARequestId int64  `json:"oa_request_id"`
 	UniqueID    string `json:"UniqueID"`
 }
 
 // 分发license给用户
 type DistributeLicenseRequest struct {
 	LicenseUniqueID  string   `json:"LicenseUniqueID"`
-	OaRequestId      string   `json:"Oa_request_id"`
+	OaRequestId      int64    `json:"Oa_request_id"`
 	OperatorUniqueID string   `json:"OperatorUniqueID"`
 	UserUniqueIDs    []string `json:"UserUniqueIDs"`
 	UserAccounts     []string `json:"UserAccounts"`
@@ -80,8 +80,8 @@ type UpdateLicenseInfoRequest struct {
 }
 
 type ConditionalSearchRequest struct {
-	LicenseFlag string `json:"license_flag,omitempty"`
-	StartingDate  string `json:"starting_date,omitempty"`
-	EndDate       string `json:"end_date,omitempty"`
-	AnySearch     string `json:"any_search,omitempty"`
+	LicenseFlag  string `json:"license_flag,omitempty"`
+	StartingDate string `json:"starting_date,omitempty"`
+	EndDate      string `json:"end_date,omitempty"`
+	AnySearch    string `json:"any_search,omitempty"`
 }

+ 159 - 132
internal/controllers/OALicenseInfo_controllers.go

@@ -47,7 +47,7 @@ func GetSingleLicenseInfoController(c *gin.Context) {
 	LicUniqueID := c.DefaultQuery("LicUniqueID", "10")
 
 	//获取指定的license信息
-	applications, total, err := models.GetOALicenseInfo(page, pageSize, "", LicUniqueID, "", "")
+	applications, total, err := models.GetOALicenseInfo(page, pageSize, "", LicUniqueID, "", 0)
 	if err != nil {
 		global.Logger.Errorln("指定UniqueID查询错误:", err.Error())
 		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("指定UniqueID查询错误: ", err.Error())})
@@ -63,78 +63,6 @@ func GetSingleLicenseInfoController(c *gin.Context) {
 
 }
 
-// func GetAllLicenseInfoControllerToDb(c *gin.Context) {
-
-// 	// userInfo, err := getLoginInfo(c)
-// 	// if err != nil {
-// 	// 	c.JSON(http.StatusUnauthorized, gin.H{"error": "用户信息不存在"})
-// 	// 	c.Abort()
-// 	// }
-
-// 	//获取请求参数
-// 	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
-// 	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
-// 	//获取指定的license信息
-// 	applications, total, err := models.GetOALicenseInfo(page, pageSize, "read_all_license", "", "", "")
-// 	if err != nil {
-// 		global.Logger.Errorln("read_all_license查询错误:", err.Error())
-// 		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("read_all_license查询错误: ", err.Error())})
-// 		return
-// 	}
-
-// 	var datas []api.AllLicenseInfoResponse
-// 	for _, v := range *applications {
-
-// 		data := api.AllLicenseInfoResponse{
-
-// 			UniqueID:               utils.ToString(v.LicInfo.UniqueID),
-// 			OARequestID:            utils.ToInt64(v.LicInfo.OARequestID),
-// 			OARequestName:          utils.ToString(v.LicInfo.OARequestName),
-// 			OARequestNameNew:       utils.ToString(v.LicInfo.OARequestNameNew),
-// 			OARequestNameHTMLNew:   utils.ToString(v.LicInfo.OARequestNameHTMLNew),
-// 			OAGLXMId:               utils.ToInt64(v.LicInfo.OAGLXMID),
-// 			OAGLXMName:             utils.ToString(v.LicInfo.OAGLXMName),
-// 			OASQSJ:                 utils.ToTimeString(v.LicInfo.OASQSJ),
-// 			OASalespersonName:      utils.ToString(v.LicInfo.OASalespersonName),
-// 			OAXSJSYX:               utils.ToString(v.LicInfo.OAXSJSYX),
-// 			OAOperationsPersonName: utils.ToString(v.LicInfo.OAOperationsPersonName),
-// 			OAJFJSYX:               utils.ToString(v.LicInfo.OAJFJSYX),
-// 			OASYDW:                 utils.ToString(v.LicInfo.OASYDW),
-// 			OAXMXXMS:               utils.ToString(v.LicInfo.OAXMXXMS),
-// 			OAJDS:                  utils.ToInt64(v.LicInfo.OAJDS),
-// 			OANodeCount:            utils.ToInt64(v.LicInfo.OANodeCount),
-// 			OAProductCode:          utils.ToString(v.LicInfo.OAProductCode),
-// 			OAProductName:          utils.ToString(v.LicInfo.OAProductName),
-// 			OAProductVersion:       utils.ToString(v.LicInfo.OAProductVersion),
-// 			OACPU:                  utils.ToString(v.LicInfo.OACPU),
-// 			OAOperatingSystem:      utils.ToString(v.LicInfo.OAOperatingSystem),
-// 			OAMainMAC:              utils.ToString(v.LicInfo.OAMainMAC),
-// 			OASecondMAC:            utils.ToString(v.LicInfo.OASecondMAC),
-// 			OACreationDate:         utils.ToString(v.LicInfo.OACreationDate),
-// 			OACreationTime:         utils.ToString(v.LicInfo.OACreationTime),
-// 			OALastOperateDate:      utils.ToString(v.LicInfo.OALastOperateDate),
-// 			OALastOperateTime:      utils.ToString(v.LicInfo.OALastOperateTime),
-// 			CaptureTime:            utils.ToTimeString(v.LicInfo.CaptureTime),
-// 			DelTime:                utils.ToTimeString(v.LicInfo.DelTime),
-// 			LastOperateTime:        utils.ToTimeString(v.LicInfo.LastOperateTime),
-
-// 			LicenseUniqueID: utils.ToString(v.GenrateInfo.LicenseUniqueID),
-// 			LicenseFlage:    utils.ToString(v.GenrateInfo.LicenseFlage),
-// 			Lic1:            utils.ToString(v.GenrateInfo.Lic1),
-// 			Lic2:            utils.ToString(v.GenrateInfo.Lic2),
-// 			CreatorGenerate: utils.ToTimeString(v.GenrateInfo.CreatorGenerate),
-// 		}
-// 		datas = append(datas, data)
-// 	}
-
-// 	c.JSON(http.StatusOK, gin.H{
-// 		"data":     datas,
-// 		"page":     page,
-// 		"pageSize": pageSize,
-// 		"total":    total,
-// 	})
-// }
-
 func GetAllLicenseInfoController(c *gin.Context) {
 	//获取请求参数
 	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
@@ -153,7 +81,7 @@ func GetAllLicenseInfoController(c *gin.Context) {
 	// 初始化存储 `OARequestID` 相同的 `ApiLicenseInfoTemp` 列表的 map
 	oaRequestIDMap := make(map[int64][]api.AllLicenseInfoResponse)
 	if userInfo.Permission[middlewares.ReadAllLicense] == middlewares.ReadAllLicense {
-		datas1, total, err := models.GetOALicenseInfo(pageSize, page, "read_all_license", "", "", "")
+		datas1, total, err := models.GetOALicenseInfo(pageSize, page, "read_all_license", "", "", 0)
 		if err != nil {
 			global.Logger.Errorln("error", err.Error())
 			c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
@@ -208,7 +136,7 @@ func GetAllLicenseInfoController(c *gin.Context) {
 		}
 
 	} else if userInfo.Permission[middlewares.ReadLicense] == middlewares.ReadLicense {
-		datas1, total, err := models.GetOALicenseInfo(pageSize, page, "", "", userInfo.UniqueID, "")
+		datas1, total, err := models.GetOALicenseInfo(pageSize, page, "", "", userInfo.UniqueID, 0)
 		if err != nil {
 			global.Logger.Errorln("error", err.Error())
 			c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
@@ -261,56 +189,6 @@ func GetAllLicenseInfoController(c *gin.Context) {
 		}
 	}
 
-	//获取指定的license缓存信息
-	//data, err := global.LicCache.GetPaginatedData(page, pageSize)
-
-	//返回[][]data 的方式
-	// var datas [][]api.AllLicenseInfoResponse
-	// for _, lic := range data {
-	// 	var dataTemp []api.AllLicenseInfoResponse
-	// 	for _, v := range lic {
-	// 		data := api.AllLicenseInfoResponse{
-	// 			UniqueID:               v.UniqueID.String,
-	// 			OARequestID:            v.OARequestID.Int64,
-	// 			OARequestName:          utils.ToString(v.OARequestName),
-	// 			OARequestNameNew:       utils.ToString(v.OARequestNameNew),
-	// 			OARequestNameHTMLNew:   utils.ToString(v.OARequestNameHTMLNew),
-	// 			OAGLXMId:               utils.ToInt64(v.OAGLXMId),
-	// 			OAGLXMName:             utils.ToString(v.OAGLXMName),
-	// 			OASQSJ:                 utils.ToTimeString(v.OASQSJ),
-	// 			OASalespersonName:      utils.ToString(v.OASalespersonName),
-	// 			OAXSJSYX:               utils.ToString(v.OAXSJSYX),
-	// 			OAOperationsPersonName: utils.ToString(v.OAOperationsPersonName),
-	// 			OAJFJSYX:               utils.ToString(v.OAJFJSYX),
-	// 			OASYDW:                 utils.ToString(v.OASYDW),
-	// 			OAXMXXMS:               utils.ToString(v.OAXMXXMS),
-	// 			OAJDS:                  utils.ToInt64(v.OAJDS),
-	// 			OANodeCount:            utils.ToInt64(v.OANodeCount),
-	// 			OAProductCode:          utils.ToString(v.OAProductCode),
-	// 			OAProductName:          utils.ToString(v.OAProductName),
-	// 			OAProductVersion:       utils.ToString(v.OAProductVersion),
-	// 			OACPU:                  utils.ToString(v.OACPU),
-	// 			OAOperatingSystem:      utils.ToString(v.OAOperatingSystem),
-	// 			OAMainMAC:              utils.ToString(v.OAMainMAC),
-	// 			OASecondMAC:            utils.ToString(v.OASecondMAC),
-	// 			OACreationDate:         utils.ToString(v.OACreationDate),
-	// 			OACreationTime:         utils.ToString(v.OACreationTime),
-	// 			OALastOperateDate:      utils.ToString(v.OALastOperateDate),
-	// 			OALastOperateTime:      utils.ToString(v.OALastOperateTime),
-	// 			CaptureTime:            utils.ToTimeString(v.CaptureTime),
-	// 			DelTime:                utils.ToTimeString(v.DelTime),
-	// 			LastOperateTime:        utils.ToTimeString(v.LastOperateTime),
-	// 			LicenseUniqueID:        utils.ToString(v.LicenseUniqueID),
-	// 			LicenseFlage:           utils.ToString(v.LicenseFlage),
-	// 			Lic1:                   utils.ToString(v.Lic1),
-	// 			Lic2:                   utils.ToString(v.Lic2),
-	// 			CreatorGenerate:        utils.ToString(v.CreatorGenerate),
-	// 		}
-	// 		dataTemp = append(dataTemp, data)
-	// 	}
-	// 	datas = append(datas, dataTemp)
-	// }
-
 	// 将 `oaRequestIDMap` 中的所有 `ApiLicenseInfoTemp` 列表添加到 `datas` 中
 	for _, apiLicenseInfoTemp := range oaRequestIDMap {
 		datas = append(datas, apiLicenseInfoTemp)
@@ -484,6 +362,73 @@ func GenerateOALicenseStrController(c *gin.Context) {
 */
 func DistributeOALicenseController(c *gin.Context) {
 
+	// //判断是否发邮件
+	// //数据库查询license信息
+	// var request api.DistributeLicenseRequest
+	// if err := c.ShouldBindJSON(&request); err != nil {
+	// 	global.Logger.Errorln("license分发请求解析失败  %s", err.Error())
+	// 	c.JSON(400, gin.H{
+	// 		"error": fmt.Sprintf("license分发请求解析失败  %s", err.Error()),
+	// 	})
+	// 	return
+	// }
+
+	// EmailArray := strings.Split(request.Emails, ",")
+	// err, existUsers := services.DistributeOALicenseServices(request.OperatorUniqueID, request.OaRequestId, request.UserUniqueIDs, request.UserAccounts, request.UserNames, EmailArray)
+	// if err != nil {
+	// 	global.Logger.Errorln("license分发失败  %s", err.Error())
+	// 	c.JSON(400, gin.H{
+	// 		"error": fmt.Sprintf("license分发失败  %s", err.Error()),
+	// 	})
+	// 	return
+	// }
+	// if existUsers != nil {
+	// 	global.Logger.Errorf("license分发失败,以下用户已经分发过  %s")
+	// 	c.JSON(400, gin.H{
+	// 		"error": fmt.Sprintf("以下用户已经分发过  %s", existUsers),
+	// 	})
+	// 	return
+	// }
+
+	// c.JSON(http.StatusOK, gin.H{
+	// 	"success": true,
+	// 	"data":    "分发成功!",
+	// })
+}
+
+func DistributeLicenseToUsersController(c *gin.Context) {
+	var request api.DistributeLicenseRequest
+	if err := c.ShouldBindJSON(&request); err != nil {
+		global.Logger.Errorln("license分发请求解析失败  %s", err.Error())
+		c.JSON(400, gin.H{
+			"error": fmt.Sprintf("license分发请求解析失败  %s", err.Error()),
+		})
+		return
+	}
+
+	err, existUsers := services.DistributeLicenseToUserServices(request.OperatorUniqueID, request.OaRequestId, request.UserUniqueIDs, request.UserAccounts, 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 existUsers != nil {
+		global.Logger.Errorf("license分发失败,以下用户已经分发过  %s")
+		c.JSON(400, gin.H{
+			"error": fmt.Sprintf("以下用户已经分发过  %s", existUsers),
+		})
+		return
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"success": true,
+		"data":    "分发成功!",
+	})
+}
+
+func DistributeLicenseToEmailController(c *gin.Context) {
 	//判断是否发邮件
 	//数据库查询license信息
 	var request api.DistributeLicenseRequest
@@ -496,7 +441,7 @@ func DistributeOALicenseController(c *gin.Context) {
 	}
 
 	EmailArray := strings.Split(request.Emails, ",")
-	err, existUsers := services.DistributeOALicenseServices(request.OperatorUniqueID, request.OaRequestId, request.UserUniqueIDs, request.UserAccounts, request.UserNames, EmailArray)
+	err, existUsers := services.DistributeLicenseToEmailServices(request.OperatorUniqueID, request.OaRequestId, request.UserUniqueIDs, request.UserAccounts, request.UserNames, EmailArray)
 	if err != nil {
 		global.Logger.Errorln("license分发失败  %s", err.Error())
 		c.JSON(400, gin.H{
@@ -665,9 +610,9 @@ func CaptureLicenseOnceToDb(c *gin.Context) {
 func GetDistributeButtenCheckController(c *gin.Context) {
 	//获取oa申请单号
 	name := c.Query("oa_request_id")
-
+	oaRequestID, err := strconv.ParseInt(name, 10, 64)
 	//查询oa单号的每一行license信息
-	err, isCheck := services.GetDistributeButtenCheckService(name)
+	err, isCheck := services.GetDistributeButtenCheckService(oaRequestID)
 	if err != nil {
 		c.JSON(http.StatusOK, gin.H{
 			"error": fmt.Sprintf("生成错误: ", err.Error()),
@@ -726,7 +671,7 @@ func ConditionalSearchController(c *gin.Context) {
 		return
 	}
 
-	licInfos, err := services.GetConditionalSearchService(request)
+	licInfos, _, err := services.GetConditionalSearchService(request)
 	if err != nil {
 		c.JSON(400, gin.H{
 			"error": errors.Errorf("查询失败: %s", err.Error()),
@@ -734,8 +679,90 @@ func ConditionalSearchController(c *gin.Context) {
 		return
 	}
 
-	c.JSON(http.StatusOK, gin.H{
-		"success": true,
-		"data":    licInfos,
+	if ret, err := returnLicenseInfo(licInfos); err != nil {
+		c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintln("数据转换失败: ", err.Error())})
+	} else {
+		c.JSON(http.StatusOK, gin.H{
+			"success": true,
+			"data":    ret,
+		})
+	}
+
+}
+
+func returnLicenseInfo(datas1 *[]models.OALicenseInfo) ([][]api.AllLicenseInfoResponse, error) {
+	// 初始化存储 `OARequestID` 相同的 `ApiLicenseInfoTemp` 列表的 map
+	oaRequestIDMap := make(map[int64][]api.AllLicenseInfoResponse)
+
+	for _, data := range *datas1 {
+		ApiLicenseInfo := api.AllLicenseInfoResponse{
+			UniqueID:               utils.ToString(data.LicInfo.UniqueID),
+			OAId:                   utils.ToInt64(data.LicInfo.OAId),
+			OARequestID:            utils.ToInt64(data.LicInfo.OARequestID),
+			OARequestName:          utils.ToString(data.LicInfo.OARequestName),
+			OARequestNameNew:       utils.ToString(data.LicInfo.OARequestNameNew),
+			OARequestNameHTMLNew:   utils.ToString(data.LicInfo.OARequestNameHTMLNew),
+			OAGLXMId:               utils.ToInt64(data.LicInfo.OAGLXMID),
+			OAGLXMName:             utils.ToString(data.LicInfo.OAGLXMName),
+			OASQSJ:                 utils.ToString(data.LicInfo.OASQSJ),
+			OASalespersonName:      utils.ToString(data.LicInfo.OASalespersonName),
+			OAXSJSYX:               utils.ToString(data.LicInfo.OAXSJSYX),
+			OAOperationsPersonName: utils.ToString(data.LicInfo.OAOperationsPersonName),
+			OAJFJSYX:               utils.ToString(data.LicInfo.OAJFJSYX),
+			OASYDW:                 utils.ToString(data.LicInfo.OASYDW),
+			OAXMXXMS:               utils.ToString(data.LicInfo.OAXMXXMS),
+			OAJDS:                  utils.ToInt64(data.LicInfo.OAJDS),
+			OANodeCount:            utils.ToInt64(data.LicInfo.OANodeCount),
+			OAProductCode:          utils.ToString(data.LicInfo.OAProductCode),
+			OAProductName:          utils.ToString(data.LicInfo.OAProductName),
+			OAProductVersion:       utils.ToString(data.LicInfo.OAProductVersion),
+			OACPU:                  utils.ToString(data.LicInfo.OACPU),
+			OAOperatingSystem:      utils.ToString(data.LicInfo.OAOperatingSystem),
+			OAMainMAC:              utils.ToString(data.LicInfo.OAMainMAC),
+			OASecondMAC:            utils.ToString(data.LicInfo.OASecondMAC),
+			OACreationDate:         utils.ToString(data.LicInfo.OACreationDate),
+			OACreationTime:         utils.ToString(data.LicInfo.OACreationTime),
+			OALastOperateDate:      utils.ToString(data.LicInfo.OALastOperateDate),
+			OALastOperateTime:      utils.ToString(data.LicInfo.OALastOperateTime),
+			CaptureTime:            utils.ToTimeString(data.LicInfo.CaptureTime),
+			DelTime:                utils.ToTimeString(data.LicInfo.DelTime),
+			LastOperateTime:        utils.ToTimeString(data.LicInfo.LastOperateTime),
+			LicenseFlage:           utils.ToString(data.GenrateInfo.LicenseFlage),
+			Lic1:                   utils.ToString(data.GenrateInfo.Lic1),
+			Lic2:                   utils.ToString(data.GenrateInfo.Lic2),
+			CreatorGenerate:        utils.ToTimeString(data.GenrateInfo.CreatorGenerate),
+		}
+		// 将 `ApiLicenseInfo` 添加到 `OARequestID` 对应的数组中
+		oaRequestID := utils.ToInt64(data.LicInfo.OARequestID)
+		oaRequestIDMap[oaRequestID] = append(oaRequestIDMap[oaRequestID], ApiLicenseInfo)
+	}
+
+	var datas [][]api.AllLicenseInfoResponse
+	// 将 `oaRequestIDMap` 中的所有 `ApiLicenseInfoTemp` 列表添加到 `datas` 中
+	for _, apiLicenseInfoTemp := range oaRequestIDMap {
+		datas = append(datas, apiLicenseInfoTemp)
+	}
+	// 对 datas 的第一维进行排序
+	// sort.Slice(datas, func(i, j int) bool {
+	// 	// 假设你需要根据每个数组第一个元素的 OACreationDate 和 OACreationTime 来排序
+	// 	if datas[i][0].OACreationDate == datas[j][0].OACreationDate {
+
+	// 		return datas[i][0].OACreationTime > datas[j][0].OACreationTime
+	// 	}
+	// 	return datas[i][0].OACreationDate > datas[j][0].OACreationDate
+	// })
+	// 对 datas 的第一维进行排序
+	sort.Slice(datas, func(i, j int) bool {
+		// 先按 OACreationDate 和 OACreationTime 排序
+		if datas[i][0].OACreationDate == datas[j][0].OACreationDate {
+			if datas[i][0].OACreationTime == datas[j][0].OACreationTime {
+				// 如果 OACreationDate 和 OACreationTime 相同,则按 OARequestID 从大到小排序
+				return datas[i][0].OARequestID > datas[j][0].OARequestID
+			}
+			return datas[i][0].OACreationTime > datas[j][0].OACreationTime
+		}
+		return datas[i][0].OACreationDate > datas[j][0].OACreationDate
 	})
+
+	return datas, nil
 }

+ 6 - 4
internal/models/license_info_models.go

@@ -59,7 +59,7 @@ type LicenseGenerateInfo struct {
 }
 
 // 获取多个或单个license信息,或者指定某个用户能查询到的所有license信息
-func GetOALicenseInfo(page int, pageSize int, permission string, licUniqueID string, userUniqueID string, OA_REQUESTID string) (*[]OALicenseInfo, int, error) {
+func GetOALicenseInfo(page int, pageSize int, permission string, licUniqueID string, userUniqueID string, OA_REQUESTID int64) (*[]OALicenseInfo, int, error) {
 	//offset := (page - 1) * pageSize
 	// 查询总记录数
 	// var total int
@@ -95,7 +95,7 @@ func GetOALicenseInfo(page int, pageSize int, permission string, licUniqueID str
 		}
 		return data, total, nil
 		//读取所有
-	case OA_REQUESTID != "":
+	case OA_REQUESTID != 0:
 		data, err := getLicInfoByOA_REQUESTID(OA_REQUESTID)
 		if err != nil {
 			return nil, 0, fmt.Errorf("getOAlicInfoToUniqueID query error: %v", err)
@@ -300,7 +300,9 @@ INNER JOIN
 	return &results, nil
 }
 
-func getLicInfoByOA_REQUESTID(unique_ID string) (*[]OALicenseInfo, error) {
+func getLicInfoByOA_REQUESTID(OaRequestId int64) (*[]OALicenseInfo, error) {
+	//OaRequestId, _ := strconv.Atoi(unique_ID)
+
 	sql := `
 	SELECT 
 		la.ID, la.Unique_ID, la.OA_ID, la.OA_REQUESTID, la.OA_REQUESTNAME, la.OA_REQUESTNAMENEW,
@@ -322,7 +324,7 @@ func getLicInfoByOA_REQUESTID(unique_ID string) (*[]OALicenseInfo, error) {
 	AND 
 		la.OA_REQUESTID = ?`
 
-	rows, err := global.XuguDB.Query(sql, unique_ID)
+	rows, err := global.XuguDB.Query(sql, OaRequestId)
 	if err != nil {
 		global.Logger.Errorln("getLicInfoByOAUniqueID 数据查询失败: ", err.Error())
 		return nil, fmt.Errorf("getLicInfoByOAUniqueID 数据查询失败: %v", err)

+ 20 - 8
internal/models/license_oa_models.go

@@ -38,7 +38,7 @@ type LicenseRecordToEmails struct {
 }
 
 // 插入分发记录用户表
-func InsertlicenseRecordByUserRow(oaRequestID string, LicenseUniqueID string, userUniqueID string, UserAccount string, operatorUniqueID string) error {
+func InsertlicenseRecordByUserRow(oaRequestID int64, LicenseUniqueID string, userUniqueID string, UserAccount string, operatorUniqueID string) error {
 
 	tx, err := global.XuguDB.Begin()
 	if err != nil {
@@ -65,7 +65,7 @@ func InsertlicenseRecordByUserRow(oaRequestID string, LicenseUniqueID string, us
 }
 
 // 插入分发记录邮箱表
-func InsertlicenseRecordByEmailRow(oaRequestID, LicenseUniqueID string, emails string, operatorUniqueID string) error {
+func InsertlicenseRecordByEmailRow(oaRequestID int64, LicenseUniqueID string, emails string, operatorUniqueID string) error {
 
 	tx, err := global.XuguDB.Begin()
 	if err != nil {
@@ -409,8 +409,8 @@ func CheckLicenseToUser(LicenseUniqueID string, userUNIQUEID string) (bool, erro
 }
 
 // 按oa的申请单号来检测是否分发给用户
-func CheckOaLicRequest(oaRequestID string, userUNIQUEID string) (bool, error) {
-	if oaRequestID == "" || userUNIQUEID == "" {
+func CheckOaLicRequest(oaRequestID int64, userUNIQUEID string) (bool, error) {
+	if oaRequestID == 0 || userUNIQUEID == "" {
 		global.Logger.Errorln("CheckOaLicRequest : LicenseUniqueID 或 userUNIQUEID 为空")
 		return false, fmt.Errorf("oaRequestID 或 userUNIQUEID 为空")
 	}
@@ -484,8 +484,9 @@ WHERE
                 SELECT DISTINCT OA_REQUESTID FROM TARGET_OA_LICENSE
             ) a
         ) s
-        WHERE a BETWEEN 1 AND 10
+        WHERE a BETWEEN 1 AND 1000
     )
+	AND la.del_Time IS NULL
 AND 1=1`
 
 	// 动态条件部分
@@ -518,7 +519,18 @@ AND 1=1`
 	return baseSQL, args
 }
 
-func GetConditionalSearch(params api.ConditionalSearchRequest) (*[]OALicenseInfo, error) {
+func GetConditionalSearch(params api.ConditionalSearchRequest) (*[]OALicenseInfo, int, error) {
+	total := 0
+	err := global.XuguDB.QueryRow(`
+		SELECT COUNT(*) from (SELECT OA_REQUESTID AS RequestCount
+		FROM TARGET_OA_LICENSE
+		where  Del_Time IS NULL
+		GROUP BY OA_REQUESTID 
+		)
+		HAVING COUNT(*) > 1;`).Scan(&total)
+	if err != nil {
+		return nil, 0, fmt.Errorf("count query error: %v", err)
+	}
 
 	// 构建SQL语句和参数
 	query, args := buildSQL(params)
@@ -528,7 +540,7 @@ func GetConditionalSearch(params api.ConditionalSearchRequest) (*[]OALicenseInfo
 	rows, err := global.XuguDB.Query(query, args...)
 	if err != nil {
 		global.Logger.Errorln("getLicInfoByOAUniqueID 数据查询失败: ", err.Error())
-		return nil, fmt.Errorf("getLicInfoByOAUniqueID 数据查询失败: %v", err)
+		return nil, 0, fmt.Errorf("getLicInfoByOAUniqueID 数据查询失败: %v", err)
 	}
 	defer rows.Close()
 	var rest []OALicenseInfo
@@ -557,5 +569,5 @@ func GetConditionalSearch(params api.ConditionalSearchRequest) (*[]OALicenseInfo
 		fmt.Println("info", info)
 	}
 
-	return &rest, nil
+	return &rest, total, nil
 }

+ 2 - 0
internal/router.go

@@ -82,6 +82,8 @@ func SetupRouter() *gin.Engine {
 		protected.POST("/distributeLicense", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeOALicenseController)
 		//分发按钮校验
 		protected.GET("/GetDistributeButtenCheckController", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.GetDistributeButtenCheckController)
+		protected.POST("/DistributeLicenseToUser", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeLicenseToUsersController)
+		protected.POST("/DistributeLicenseToEmail", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeLicenseToEmailController)
 
 		//上传文件的license 弃用
 		protected.GET("/distributeLicenseByUserInfo", middlewares.PermissionMiddleware(middlewares.DispatLicense), controllers.DistributeLicenseByUser)

+ 126 - 10
internal/services/OALicenseInfo_services.go

@@ -13,6 +13,113 @@ import (
 )
 
 func DistributeOALicenseServices(OperatorUniqueID, OaRequestId string, UserUniqueIDs, UserAccounts, UserNames, EmailArray []string) (error, []string) {
+	// //检测OARequest是否以及分发过给用户
+	// existUsers, err := checkDistributeToUser(OaRequestId, UserUniqueIDs, UserNames)
+	// if err != nil {
+	// 	global.Logger.Errorln("license分发请求检测是否已发放给用户失败  %s", err.Error())
+	// 	return err, nil
+	// }
+	// //返回以及分发过的用户列表
+	// if len(existUsers) != 0 {
+
+	// 	return nil, existUsers
+	// }
+	// fmt.Println("DistributeOALicenseServices : ")
+	// //获取一个申请单的多个license信息
+	// LicInfos, _, err := models.GetOALicenseInfo(1, 1, "", "", "", OaRequestId)
+	// if err != nil {
+	// 	return err, nil
+	// }
+
+	// //将分发的lic信息插入lic分发用户表中
+	// for _, licInfo := range *LicInfos {
+
+	// 	for userIdx, userUID := range UserUniqueIDs {
+
+	// 		//如果lic1为空则报错
+	// 		if licInfo.GenrateInfo.Lic1.String == "" {
+	// 			global.Logger.Errorln("DistributeOALicenseServices : license生成信息为空 ")
+	// 			return errors.New("license生成信息为空"), nil
+	// 		}
+
+	// 		err = models.InsertlicenseRecordByUserRow(OaRequestId, licInfo.LicInfo.UniqueID.String, userUID, UserAccounts[userIdx], OperatorUniqueID)
+	// 		if err != nil {
+	// 			global.Logger.Errorln("DistributeOALicenseServices: 数据库插入失败: ", err.Error())
+	// 			return err, nil
+	// 		}
+	// 	}
+	// }
+	// //发送邮件
+	// //邮箱不空则发送
+	// //将一个申请单的多个license信息用邮箱发送
+
+	// if len(EmailArray) == 0 {
+	// 	return nil, nil
+	// }
+	// //将licenses里的lic串们打包在zip里
+	// // 1. 创建 ZIP 文件并存储在内存中
+	// // var buffer bytes.Buffer
+	// // zipWriter := zip.NewWriter(&buffer)
+	// // for _, lic := range *LicInfos {
+	// // 	// 将数据添加到 ZIP 中
+	// // 	file1, err := zipWriter.Create("file1.txt")
+	// // 	if err != nil {
+	// // 		global.Logger.Errorln(err)
+	// // 	}
+	// // 	_, err = file1.Write(lic)
+	// // 	if err != nil {
+	// // 		global.Logger.Errorln(err)
+	// // 	}
+
+	// // }
+
+	// // file2, err := zipWriter.Create("file2.txt")
+	// // if err != nil {
+	// // 	global.Logger.Errorln(err)
+	// // }
+	// // _, err = file2.Write(data2)
+	// // if err != nil {
+	// // 	global.Logger.Errorln(err)
+	// // }
+
+	// fmt.Println("EmailArray : ", EmailArray)
+	// emails := strings.Join(EmailArray, ",")
+	// if !strings.Contains(emails, "@") {
+	// 	return nil, nil
+	// }
+	// for _, lic := range *LicInfos {
+
+	// 	if lic.GenrateInfo.Lic1.String == "" {
+	// 		global.Logger.Errorln("DistributeOALicenseServices : license生成信息为空 ")
+	// 		return errors.New("license生成信息为空"), nil
+	// 	}
+
+	// 	//组装邮件
+	// 	em, err := email.BuildEmail(&lic, EmailArray, lic.GenrateInfo.Lic1.String, lic.GenrateInfo.Lic2.String)
+	// 	if err != nil {
+	// 		global.Logger.Errorln("邮件生成失败", err.Error())
+	// 		return err, nil
+	// 	}
+	// 	//发送邮件
+	// 	err = email.SendEmail(em)
+	// 	if err != nil {
+	// 		global.Logger.Errorln("邮件发送失败", err.Error())
+
+	// 		return err, nil
+	// 	}
+	// 	//将分发的lic信息插入lic分发邮箱表中
+	// 	err = models.InsertlicenseRecordByEmailRow(OaRequestId, lic.LicInfo.UniqueID.String, emails, OperatorUniqueID)
+	// 	if err != nil {
+	// 		global.Logger.Errorln("数据库插入失败: ", err.Error())
+	// 		return err, nil
+	// 	}
+
+	// }
+
+	return nil, nil
+}
+
+func DistributeLicenseToUserServices(OperatorUniqueID string, OaRequestId int64, UserUniqueIDs, UserAccounts, UserNames []string) (error, []string) {
 	//检测OARequest是否以及分发过给用户
 	existUsers, err := checkDistributeToUser(OaRequestId, UserUniqueIDs, UserNames)
 	if err != nil {
@@ -49,6 +156,10 @@ func DistributeOALicenseServices(OperatorUniqueID, OaRequestId string, UserUniqu
 			}
 		}
 	}
+	return nil, nil
+}
+
+func DistributeLicenseToEmailServices(OperatorUniqueID string, OaRequestId int64, UserUniqueIDs, UserAccounts, UserNames, EmailArray []string) (error, []string) {
 	//发送邮件
 	//邮箱不空则发送
 	//将一个申请单的多个license信息用邮箱发送
@@ -82,6 +193,12 @@ func DistributeOALicenseServices(OperatorUniqueID, OaRequestId string, UserUniqu
 	// 	global.Logger.Errorln(err)
 	// }
 
+	//获取一个申请单的多个license信息
+	LicInfos, _, err := models.GetOALicenseInfo(1, 1, "", "", "", OaRequestId)
+	if err != nil {
+		return err, nil
+	}
+
 	fmt.Println("EmailArray : ", EmailArray)
 	emails := strings.Join(EmailArray, ",")
 	if !strings.Contains(emails, "@") {
@@ -113,14 +230,13 @@ func DistributeOALicenseServices(OperatorUniqueID, OaRequestId string, UserUniqu
 			global.Logger.Errorln("数据库插入失败: ", err.Error())
 			return err, nil
 		}
-
 	}
-
 	return nil, nil
 }
 
+// 生成license
 func GenerateOALicenseStrServices(request api.GenerateLicenseStrRequest) (error, bool) {
-	if request.OARequestId != "" {
+	if request.OARequestId != 0 {
 		//一个OARequestId会有多条数据UniqueID
 		OALics, _, err := models.GetOALicenseInfo(0, 0, "", "", "", request.OARequestId)
 		if err != nil || OALics == nil {
@@ -170,7 +286,7 @@ func generateLicenseStrSub(UniqueID string) error {
 	var applications *[]models.OALicenseInfo
 	var err error
 	if UniqueID != "" {
-		applications, _, err = models.GetOALicenseInfo(0, 1, "", UniqueID, "", "")
+		applications, _, err = models.GetOALicenseInfo(0, 1, "", UniqueID, "", 0)
 		if err != nil {
 			global.Logger.Errorln("LicenseInfo数据查询失败:  ", err.Error())
 			//	c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("数据查询失败: ", err.Error())})
@@ -210,8 +326,8 @@ func generateLicenseStrSub(UniqueID string) error {
 	return nil
 }
 
-func GetDistributeButtenCheckService(OARequestId string) (error, bool) {
-	if OARequestId != "" {
+func GetDistributeButtenCheckService(OARequestId int64) (error, bool) {
+	if OARequestId != 0 {
 		//一个OARequestId会有多条数据UniqueID
 		OALics, _, err := models.GetOALicenseInfo(0, 0, "", "", "", OARequestId)
 		if err != nil || OALics == nil {
@@ -250,10 +366,10 @@ func GetDistributeButtenCheckService(OARequestId string) (error, bool) {
 	return errors.Errorf("该申请单没有oa单号"), false
 }
 
-func GetConditionalSearchService(request api.ConditionalSearchRequest) (*[]models.OALicenseInfo, error) {
-	lic, err := models.GetConditionalSearch(request)
+func GetConditionalSearchService(request api.ConditionalSearchRequest) (*[]models.OALicenseInfo, int, error) {
+	lic, total, err := models.GetConditionalSearch(request)
 	if err != nil {
-		return nil, err
+		return nil, total, err
 	}
-	return lic, nil
+	return lic, total, nil
 }

+ 1 - 1
internal/services/OALicenseInfo_services_sub.go

@@ -5,7 +5,7 @@ import (
 	"xugu_license/internal/models"
 )
 
-func checkDistributeToUser(OaLicRequest string, UserUniqueIDs []string, UserNames []string) (licToUser []string, err error) {
+func checkDistributeToUser(OaLicRequest int64, UserUniqueIDs []string, UserNames []string) (licToUser []string, err error) {
 
 	for i, UserUID := range UserUniqueIDs {
 

+ 288 - 3
static/license_info/license_info.css

@@ -495,9 +495,11 @@ nav ul li a.active {
 }
 
 /* 确定按钮样式 */
-#submit-button {
+/* 确定按钮和返回按钮的统一样式 */
+#submit-button,
+#reset-button {
     padding: 12px 20px;
-    background-color: #007aff;
+    background-color: #007aff; /* iOS风格的蓝色按钮 */
     color: white;
     border: none;
     border-radius: 15px;
@@ -507,12 +509,14 @@ nav ul li a.active {
 }
 
 /* 鼠标悬停时按钮效果 */
-#submit-button:hover {
+#submit-button:hover,
+#reset-button:hover {
     background-color: #005bb5;
 }
 
 
 
+
 /*-----------------分发*/
 
 /* 模态框整体样式 */
@@ -621,3 +625,284 @@ nav ul li a.active {
 #distribute-modal .distribute-confirm-button:hover {
     background-color: #0056b3;
 }
+
+/*分发下拉框样式*/
+/* 专属下拉框容器样式 */
+.distribute-user-select-container {
+    margin-bottom: 15px;
+    width: 100%;
+    display: flex;
+    justify-content: center; /* 居中 */
+}
+
+/* 专属下拉框样式 */
+.distribute-user-select {
+    width: 80%; /* 下拉框的宽度 */
+    padding: 10px;
+    border-radius: 8px;
+    border: 1px solid #ccc;
+    font-size: 16px;
+    background-color: #f9f9f9; /* 浅灰背景 */
+    color: #333; /* 字体颜色 */
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 轻微阴影 */
+    transition: border-color 0.3s ease;
+}
+
+.distribute-user-select:focus {
+    border-color: #007bff; /* 焦点时的边框颜色 */
+    outline: none; /* 去掉默认的焦点样式 */
+    box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); /* 焦点时的阴影效果 */
+}
+
+/* 下拉框的选项样式 */
+.distribute-user-select option {
+    background-color: white; /* 默认背景颜色 */
+    color: black; /* 默认字体颜色 */
+}
+
+/* 悬停选项时的样式 */
+.distribute-user-select option:hover {
+    background-color: #007bff; /* 悬停时选项的背景颜色 */
+    color: white; /* 悬停时字体颜色 */
+}
+
+/* 选中的选项的样式 */
+.distribute-user-select option:checked {
+    background-color: #0056b3; /* 选中的选项的背景颜色 */
+    color: white; /* 选中的选项的字体颜色 */
+}
+
+
+/* 添加用户按钮样式 */
+.distribute-add-user-button {
+    padding: 10px 15px;
+    background-color: #007bff;
+    color: white;
+    border: none;
+    border-radius: 5px;
+    cursor: pointer;
+    margin-top: 10px;
+    transition: background-color 0.3s ease;
+}
+
+.distribute-add-user-button:hover {
+    background-color: #0056b3;
+}
+
+/*关闭按钮*/
+/* 分发模态框用户选择框容器样式 */
+.distribute-modal-user-select-container {
+    margin-bottom: 15px;
+    width: 100%;
+    display: flex;
+    justify-content: space-between; /* 让下拉框和关闭按钮分开对齐 */
+    align-items: center; /* 垂直居中 */
+}
+
+/* 关闭按钮样式 */
+.distribute-modal-close-select {
+    font-size: 18px; /* 关闭按钮的大小 */
+    color: #ff0000; /* 关闭按钮的颜色 */
+    cursor: pointer;
+}
+
+.distribute-modal-close-select:hover {
+    color: #d00000; /* 鼠标悬停时的颜色变化 */
+}
+
+/*分发邮箱*/
+/* 邮箱输入框样式 */
+.distribute-email-input {
+    display: block;
+    margin: 10px 0;
+    padding: 8px;
+    width: 100%;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+}
+
+/* 新增邮箱和确认分发按钮样式 */
+#distribute-email-add-button, #distribute-confirm-button {
+    margin-top: 10px;
+    padding: 10px;
+    background-color: #007bff;
+    color: white;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+}
+
+#distribute-email-add-button:hover, #distribute-confirm-button:hover {
+    background-color: #0056b3;
+}
+
+
+
+/*------------分发历史模态框*/
+/* 分发历史模态框整体样式 */
+.distributionHistory-modal {
+    display: none; /* 默认隐藏 */
+    position: fixed;
+    z-index: 1000;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.5); /* 半透明背景 */
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+}
+
+/* 分发历史模态框内容样式 */
+.distributionHistory-modal-content {
+    background-color: #fff;
+    width: 400px; /* 模态框的宽度 */
+    max-width: 90%; /* 最大宽度为视口的90% */
+    padding: 20px;
+    border-radius: 10px;
+    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); /* 轻微阴影 */
+    position: relative;
+    text-align: center;
+}
+
+/* 分发历史模态框关闭按钮样式 */
+.distributionHistory-modal-close {
+    position: absolute;
+    top: 10px;
+    right: 15px;
+    font-size: 24px;
+    color: #333;
+    cursor: pointer;
+}
+
+/* 分发历史模态框标题样式 */
+.distributionHistory-modal-header h2,
+.distributionHistory-modal-body h2 {
+    font-size: 20px;
+    font-weight: bold;
+    margin-bottom: 15px;
+    color: #333;
+}
+
+/* 分发历史模态框邮箱部分样式 */
+.distributionHistory-modal-email-section {
+    margin-bottom: 20px;
+}
+
+.distributionHistory-modal-email-section h2 {
+    font-size: 18px;
+    margin-bottom: 10px;
+    color: #007bff;
+}
+
+/* 分发历史模态框用户部分样式 */
+.distributionHistory-modal-user-section {
+    margin-top: 20px;
+}
+
+.distributionHistory-modal-user-section h2 {
+    font-size: 18px;
+    margin-bottom: 10px;
+    color: #28a745;
+}
+
+/* 分发历史模态框的输入框区域样式 */
+.distributionHistory-modal-inputs,
+.distributionHistory-modal-user-inputs {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+}
+
+.distributionHistory-modal-inputs div,
+.distributionHistory-modal-user-inputs div {
+    margin-bottom: 10px;
+}
+
+.distributionHistory-modal input[type="checkbox"] {
+    margin-right: 10px;
+}
+
+.distributionHistory-modal-label {
+    font-size: 16px;
+    color: #555;
+    cursor: pointer;
+}
+
+/* 分发历史模态框确认按钮样式 */
+.distributionHistory-modal-confirm-button {
+    background-color: #007bff;
+    color: white;
+    padding: 10px 20px;
+    border: none;
+    border-radius: 5px;
+    cursor: pointer;
+    margin-top: 20px;
+    font-size: 16px;
+}
+
+.distributionHistory-modal-confirm-button:hover {
+    background-color: #0056b3;
+}
+
+/* 分发历史模态框用户选择框容器样式 */
+.distributionHistory-modal-user-select-container {
+    margin-bottom: 15px;
+    width: 100%;
+    display: flex;
+    justify-content: center; /* 居中 */
+}
+
+/* 分发历史模态框专属下拉框样式 */
+.distributionHistory-modal-user-select {
+    width: 80%; /* 下拉框的宽度 */
+    padding: 10px;
+    border-radius: 8px;
+    border: 1px solid #ccc;
+    font-size: 16px;
+    background-color: #f9f9f9; /* 浅灰背景 */
+    color: #333; /* 字体颜色 */
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 轻微阴影 */
+    transition: border-color 0.3s ease;
+}
+
+.distributionHistory-modal-user-select:focus {
+    border-color: #007bff; /* 焦点时的边框颜色 */
+    outline: none; /* 去掉默认的焦点样式 */
+    box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); /* 焦点时的阴影效果 */
+}
+
+/* 下拉框的选项样式 */
+.distributionHistory-modal-user-select option {
+    background-color: white; /* 默认背景颜色 */
+    color: black; /* 默认字体颜色 */
+}
+
+/* 悬停选项时的样式 */
+.distributionHistory-modal-user-select option:hover {
+    background-color: #007bff; /* 悬停时选项的背景颜色 */
+    color: white; /* 悬停时字体颜色 */
+}
+
+/* 选中的选项的样式 */
+.distributionHistory-modal-user-select option:checked {
+    background-color: #0056b3; /* 选中的选项的背景颜色 */
+    color: white; /* 选中的选项的字体颜色 */
+}
+
+/* 分发历史模态框添加用户按钮样式 */
+.distributionHistory-modal-add-user-button {
+    padding: 10px 15px;
+    background-color: #007bff;
+    color: white;
+    border: none;
+    border-radius: 5px;
+    cursor: pointer;
+    margin-top: 10px;
+    transition: background-color 0.3s ease;
+}
+
+.distributionHistory-modal-add-user-button:hover {
+    background-color: #0056b3;
+}

+ 20 - 4
static/license_info/license_info.html

@@ -44,10 +44,11 @@
             <input type="date" id="end-date" placeholder="结束时间" />
         
             <!-- 搜索框 -->
-            <input type="text" id="search-bar" placeholder="搜索..." />
+            <input type="text" id="search-bar" style="display: none;" placeholder="搜索..." />
         
             <!-- 确定按钮 -->
             <button id="submit-button">确定</button>
+            <button id="reset-button">返回</button>
         </div>
             <div class="license-info-container" id="license-info-restaurant-list">   </div>
               <!-- 这是显示内容的区域 -->
@@ -78,6 +79,7 @@
     </div>
 </div>
 
+<!-- 新的分发模态框 -->
 <!-- 新的分发模态框 -->
 <div id="distribute-modal" class="distribute-modal">
     <div class="distribute-modal-content">
@@ -86,6 +88,7 @@
         <!-- 上半部分: 分发邮箱 -->
         <div id="distribute-email-section" class="distribute-header">
             <h2>分发邮箱</h2>
+            <button id="distribute-email-add-button">新增邮箱</button> <!-- 新增邮箱按钮 -->
             <div id="emailInputs">
                 <!-- 动态生成邮箱输入区域 -->
             </div>
@@ -99,18 +102,31 @@
             </div>
         </div>
 
-        <button class="distribute-confirm-button">确认分发</button>
+        <!-- 确认分发按钮 -->
+        <button id="distribute-confirm-button" class="distribute-confirm-button">确认分发</button>
+    </div>
+</div>
+
+
+<!-- 分发历史模态框 -->
+<div id="distributionHistory-modal" class="distributionHistory-modal">
+    <div class="distributionHistory-modal-content">
+        <span class="distributionHistory-modal-close">&times;</span> <!-- 修改了关闭按钮的类名 -->
+        <h2>分发历史</h2>
+        <div id="distributionHistory-user-content"></div> <!-- 修改了用户分发记录的 ID -->
+        <div id="distributionHistory-email-content"></div> <!-- 修改了邮箱分发记录的 ID -->
     </div>
 </div>
 
 
-   
 
 
 
     <script src="license_info.js"></script>
+    <script src="license_info_distribution.js"></script>
     <script
-    src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
+    src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js">
+    </script>
 
 
 </body>

+ 305 - 28
static/license_info/license_info.js

@@ -28,6 +28,27 @@ const license_info_loadingIndicator = document.getElementById('loading-indicator
 let LicApplicationData = []; // 用于存储从接口获取的数据
 
 
+// 统一的打开模态框函数
+function openModal(modalId) {
+    const modal = document.getElementById(modalId);
+    if (modal) {
+        modal.style.display = "block"; // 显示模态框
+    } else {
+        console.error('模态框不存在,ID:', modalId);
+    }
+}
+
+// 统一的关闭模态框函数
+function closeModal(modalId) {
+    const modal = document.getElementById(modalId);
+    if (modal) {
+        modal.style.display = "none"; // 隐藏模态框
+    } else {
+        console.error('模态框不存在,ID:', modalId);
+    }
+}
+
+
 //-----------侧边栏----------------------------
 
 // 获取所有菜单项
@@ -184,12 +205,14 @@ function renderLicenseCards(data, clearContainer = false) {
         console.log("-----------渲染清除");
     }
     console.log("-----------data:",data);
-       // 获取子行的数量
-   const childRowCount = data.length;
+
+  
+
 
     data.forEach(group => {
         const firstItem = group[0]; // 获取该组的第一个数据项
-
+       // 获取子行的数量
+       const childRowCount = group.length;
         let statusClass = '';
         if (firstItem.LicenseFlage === '已生成') {
             statusClass = 'license-status-green';
@@ -327,6 +350,12 @@ function removeScrollListeners() {
     license_info_mainElement.removeEventListener('scroll', handleMainScroll);
 }
 
+// 新增一个重启滑动监听功能函数,当用户清空搜索条件时调用
+function restartScrollListeners() {
+    // 重新绑定滑动监听器
+    initializeScrollListeners();
+}
+
 function handleMainScroll() {
     // console.log('handleMainScroll', license_info_mainElement.scrollHeight, license_info_mainElement.scrollTop, license_info_mainElement.clientHeight);
     checkAndLoadMore(license_info_mainElement.scrollHeight, license_info_mainElement.scrollTop, license_info_mainElement.clientHeight);
@@ -375,7 +404,7 @@ function showModalForCard(item,oaRequestId) {
     
     // 设置分页相关的变量
     let currentPage = 1;
-    const itemsPerPage = 2; // 每页显示两组
+    const itemsPerPage = 3; // 每页显示两组
 
     // 对 item 数组按 oa_id 进行升序排序
     const sortedItem = item.sort((a, b) => a.oa_id - b.oa_id);
@@ -446,9 +475,11 @@ console.log(`当前用户是否有生成权限: ${hasGeneratePermission}, ${hasD
                 : ''
             }
             <button class="license-info-modal-button" id="downloadAllLicenses-button">打包下载所有license.dat</button>
+            <button id="viewDistributionHistory-button">查看分发历史</button>
         </div>
     </div>
     `;
+
         // 绑定 button1 的点击事件(如果按钮存在)
         const generateOrDistribute = modalHeader.querySelector('#generateOrDistribute');
         console.log("generateOrDistribute",generateOrDistribute);  // 检查是否找到按钮
@@ -456,11 +487,12 @@ console.log(`当前用户是否有生成权限: ${hasGeneratePermission}, ${hasD
             generateOrDistribute.addEventListener('click', () => {
                 if (firstItem.LicenseFlage === '已生成') {
                     // 执行分发逻辑
-                    showDistributeModal(firstItem.oa_request_id, firstItem.SupportEmail, firstItem.SalesEmail, '', firstItem.oa_request_id);
+                    showDistributeModal(firstItem);
                 
                 } else {
                     // 执行生成逻辑
-                 generateLicense(firstItem.oa_request_id, true);
+                    const oaRequestID = parseInt(firstItem.oa_request_id, 10);  // 10 表示10进制
+                 generateLicense(oaRequestID, true);
                 }
                 console.log('Button 1 clicked');
             });
@@ -483,6 +515,13 @@ console.log(`当前用户是否有生成权限: ${hasGeneratePermission}, ${hasD
                 downloadAllLicenses(sortedItem);
             });
         }
+   // 在初始化完成后绑定 "查看分发历史" 按钮的点击事件
+   const viewDistributionHistoryButton = document.getElementById('viewDistributionHistory-button');
+   if (viewDistributionHistoryButton) {
+       viewDistributionHistoryButton.addEventListener('click', () => {
+           showDistributionHistory(firstItem);
+       });
+   }
 
     }
 
@@ -519,12 +558,15 @@ console.log(`当前用户是否有生成权限: ${hasGeneratePermission}, ${hasD
 
                 // 动态生成组内容,显示编号为 i+1(表示组1, 组2...)
                 groupBox.innerHTML = `
-                    <div class="license-info-group-title">组 ${i + 1}</div>
-                    <p><strong>UniqueID:</strong> ${group.UniqueID}</p>
+                    <div class="license-info-group-title">集群 ${i + 1} :</div>
+
+                    <p><strong>节点数:</strong> ${group.NodeCount}</p>
+                    <p><strong>数据库版本: </strong> ${group.ProductName}${group.ProductVersion}</p>
+                    <p><strong>CPU 型号:</strong> ${group.oa_cpu}</p>
+                    <p><strong>操作系统环境:</strong> ${group.oa_operating_system}</p>
+                    <p><strong>以下为测试显示:</strong> </p>
                     <p><strong>oa_id:</strong> ${group.oa_id}</p>
                     <p><strong>oa_request_id:</strong> ${group.oa_request_id}</p>
-                    <p><strong>Creator:</strong> ${group.Creator}</p>
-                    <p><strong>oa_request_name_new:</strong> ${group.oa_request_name_new}</p>
                 `;
 
                 // 将生成的组内容加入到 modalBody
@@ -648,32 +690,88 @@ function downloadAllLicenses(sortedApplicationArray) {
 }
 
 //分发
+let userMap = {};
+
 // 打开分发模态框
-function showDistributeModal(supportEmail, salesEmail, userOptions) {
-    console.log("showDistributeModal", supportEmail);
+function showDistributeModal(firstItem) {
+    console.log("showDistributeModal firstItem", firstItem);
     const modal = document.getElementById('distribute-modal');
     const emailInputs = document.getElementById('emailInputs');
     const userInputs = document.getElementById('userInputs');
+    let usedUsernames = []; // 存储已选择的用户
 
     // 清空内容
     emailInputs.innerHTML = '';
     userInputs.innerHTML = '';
 
     // 动态生成分发邮箱部分
-    if (supportEmail) {
-        emailInputs.innerHTML += `<div><input type="checkbox" id="supportEmail" value="${supportEmail}"> 运维邮箱: ${supportEmail}</div>`;
+    if (firstItem.SupportEmail) {
+        emailInputs.innerHTML += `<div><input type="checkbox" id="supportEmail" value="${firstItem.SupportEmail}"> 运维邮箱: ${firstItem.SupportEmail}</div>`;
     }
-    if (salesEmail) {
-        emailInputs.innerHTML += `<div><input type="checkbox" id="salesEmail" value="${salesEmail}"> 销售邮箱: ${salesEmail}</div>`;
+    if (firstItem.SalesEmail) {
+        emailInputs.innerHTML += `<div><input type="checkbox" id="salesEmail" value="${firstItem.SalesEmail}"> 销售邮箱: ${firstItem.SalesEmail}</div>`;
     }
 
-    // 动态生成分发用户部分
-    // 如果有用户选项,可以解开以下注释并生成用户选项
-    // userOptions.forEach(user => {
-    //     const userOption = document.createElement('div');
-    //     userOption.innerHTML = `<input type="checkbox" value="${user}"> 用户: ${user}`;
-    //     userInputs.appendChild(userOption);
-    // });
+    // 调用 API 获取用户信息并填充第一个用户输入框
+    fetch('http://127.0.0.1:8080/api/admin/distributeLicenseByUserInfo', {
+        method: 'GET',
+        headers: {
+            'Authorization': `Bearer ${authToken}`, // 确保 token 已经定义
+            'Content-Type': 'application/json'
+        }
+    })
+    .then(response => response.json())
+    .then(data => {
+        // 初始化 userMap
+        userMap = {};
+        
+        const availableUsers = data.data
+            .map(user => {
+                // 将用户信息存储在 userMap 中
+                userMap[user.Username] = {
+                    Account: user.Account,
+                    UniqueID: user.UniqueID,
+                    Username: user.Username,
+                    Email: user.Email,
+                    Role: user.Role,
+                    Telephone: user.Telephone
+                };
+                return user.Username;
+            })
+            .filter(user => user !== 'admin'); // 排除用户名为 "admin"
+
+      //  createUserSelect(userInputs, availableUsers, usedUsernames); // 创建第一个下拉框
+
+        // 创建“添加用户”按钮
+        const addButton = document.createElement('button');
+        addButton.className = 'distribute-add-user-button';
+        addButton.textContent = '添加用户';
+        addButton.addEventListener('click', () => {
+            createUserSelect(userInputs, availableUsers, usedUsernames); // 添加新的下拉框
+        });
+        userInputs.appendChild(addButton);
+        
+        // 创建“确定分发”按钮
+        const distributeButton = document.createElement('button');
+        distributeButton.className = 'distribute-confirm-button';
+        distributeButton.textContent = '确定分发';
+        distributeButton.addEventListener('click', () => {
+            // 弹出确认框
+            if (confirm('确定要分发许可证吗?')) {
+                // 获取选中的用户信息
+                const selectedUserInputs = Array.from(document.querySelectorAll('select.distribute-user-select'));
+
+                const userIds = selectedUserInputs.map(select => userMap[select.value].UniqueID);
+                const userAccounts = selectedUserInputs.map(select => userMap[select.value].Account);
+                const userNames = selectedUserInputs.map(select => userMap[select.value].Username);
+
+                // 将提前获取的用户信息传递给 distributeLicenseToUsers 函数
+                distributeLicenseToUsers(firstItem, userIds, userAccounts, userNames);
+            }
+        });
+        userInputs.appendChild(distributeButton);
+    })
+    .catch(error => console.error('获取用户信息失败:', error));
 
     // 显示模态框
     modal.style.display = 'flex';
@@ -693,6 +791,151 @@ function showDistributeModal(supportEmail, salesEmail, userOptions) {
 }
 
 
+//分发license 到用户
+function distributeLicenseToUsers(selectedRowData, userIds, userAccounts, userNames) {
+    console.log('Distribute button clicked');
+    console.log('userIds', userIds);
+    console.log('userAccounts', userAccounts);
+    console.log('userNames', userNames);
+
+    // 显示加载进度条并设置动态提示信息
+    showLoadingModal('正在分发 License...');
+
+    const operatorUniqueID = userMap[currentUserName].UniqueID;
+
+    if (userIds.length === 0) {
+        alert('请至少选择一个用户。');
+        hideLoadingModal();
+        return;
+    }
+
+    const requestData = {
+        LicenseUniqueID: selectedRowData.UniqueID,  // 当前选中的 License ID
+        Oa_request_id:  selectedRowData.oa_request_id,  // 当前选中的 OA 请求 ID
+        UserUniqueIDs: userIds,  // 用户 ID 数组
+        UserAccounts: userAccounts,  // 用户账号数组
+        UserNames: userNames,  // 用户名数组
+        Emails: '',  // 邮箱(可以根据需要添加或删除)
+        OperatorUniqueID: operatorUniqueID  // 操作者的唯一 ID
+    };
+
+    console.log('requestData:', requestData);
+
+    // 发起 POST 请求到分发 License 的 API
+    fetch('http://127.0.0.1:8080/api/admin/DistributeLicenseToUser', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${authToken}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify(requestData)
+    })
+    .then(response => response.json())
+    .then(data => {
+        hideLoadingModal();
+
+        if (data.success) {
+            alert('分发成功!');
+            closeModal('distribute-modal');  // 关闭模态框
+        } else {
+            const errorMessage = data.error || '分发失败。';
+            alert(`分发失败: ${errorMessage}`);
+        }
+    })
+    .catch(error => {
+        hideLoadingModal();
+        console.error('Error occurred during license distribution:', error);
+        alert('分发失败,请检查网络或后端服务。');
+    });
+}
+
+// 创建新的下拉框并过滤掉已选择的用户
+// 创建新的下拉框并过滤掉已选择的用户
+function createUserSelect(container, availableUsers, usedUsernames) {
+    // 创建下拉框容器
+    const userSelectContainer = document.createElement('div');
+    userSelectContainer.className = 'distribute-modal-user-select-container';
+
+    // 创建下拉框
+    const userSelect = document.createElement('select');
+    userSelect.className = 'distribute-modal-user-select';
+
+    // 过滤掉已经选中的用户
+    const filteredUsers = availableUsers.filter(user => !usedUsernames.includes(user));
+
+    // 填充下拉框选项
+    filteredUsers.forEach(user => {
+        const option = document.createElement('option');
+        option.value = user;
+        option.textContent = user;
+        userSelect.appendChild(option);
+    });
+
+    // 创建关闭按钮
+    const closeButton = document.createElement('span');
+    closeButton.textContent = 'X';
+    closeButton.className = 'distribute-modal-close-select'; // 添加类名以便样式化
+    closeButton.style.cursor = 'pointer'; // 鼠标样式
+    closeButton.style.marginLeft = '10px'; // 与下拉框之间的间距
+
+    // 关闭按钮点击事件,删除下拉框和自身,并从已选择用户名数组中移除
+    closeButton.addEventListener('click', function() {
+        // 从已选择的用户名中移除
+        const selectedValue = userSelect.value;
+        const index = usedUsernames.indexOf(selectedValue);
+        if (index > -1) {
+            usedUsernames.splice(index, 1); // 移除已选择的用户名
+        }
+        container.removeChild(userSelectContainer); // 删除下拉框容器
+    });
+
+    // 将下拉框和关闭按钮添加到容器中
+    userSelectContainer.appendChild(userSelect);
+    userSelectContainer.appendChild(closeButton);
+
+    // 将下拉框容器添加到父容器中
+    container.appendChild(userSelectContainer);
+
+    // 当选择新用户时,将其添加到已选择的用户名数组中
+    userSelect.addEventListener('change', function() {
+        const previousValue = usedUsernames.find(u => u === this.defaultValue);
+        if (previousValue) {
+            // 如果之前的值存在且不同于新值,则移除之前的值
+            usedUsernames.splice(usedUsernames.indexOf(previousValue), 1);
+        }
+        usedUsernames.push(this.value); // 添加新选中的用户名
+        this.defaultValue = this.value; // 更新默认值
+        console.log('已选择的用户:', usedUsernames);
+    });
+}
+
+
+// 更新下拉框选项,过滤掉已选择的用户名
+function updateUserSelectOptions(availableUsers, usedUsernames, container) {
+    const allSelects = container.querySelectorAll('.distribute-modal-user-select');
+    
+    allSelects.forEach(select => {
+        const currentValue = select.value; // 保存当前选中值
+        // 清空下拉框
+        select.innerHTML = '';
+
+        // 重新填充选项,排除已选中的用户,确保当前选择保留
+        availableUsers.forEach(user => {
+            if (!usedUsernames.includes(user) || user === currentValue) {
+                const option = document.createElement('option');
+                option.value = user;
+                option.textContent = user;
+                if (user === currentValue) {
+                    option.selected = true; // 保留当前选中项
+                }
+                select.appendChild(option);
+            }
+        });
+    });
+}
+
+
+
 
 
 // 刷新数据并滚动到目标卡片的函数
@@ -736,8 +979,11 @@ async function refreshLicenseDataAndScrollAndOpenModal(selfPage,selfPageSize, ta
 function generateLicense(id, isParentRow) {
         // 显示加载进度条并设置动态提示信息
         showLoadingModal('正在生成 License...');
-    const payload = isParentRow ? { oa_request_id: JSON.stringify(id) } : { uniqueID:JSON.stringify(id) };
-    
+   // const payload = isParentRow ? { oa_request_id: JSON.stringify(id) } : { uniqueID:JSON.stringify(id) };
+   const payload = isParentRow 
+   ? { oa_request_id: parseInt(id, 10) }  // 将 id 转换为整数
+   : { uniqueID: parseInt(id, 10) };  // 将 id 转换为整数
+
     console.log("generateLicense",payload ,id, isParentRow)
     fetch('http://127.0.0.1:8080/api/admin/GenerateLicense', {
         method: 'POST',
@@ -934,7 +1180,13 @@ document.addEventListener('DOMContentLoaded', createLoadingModal);
 
 
 
-//----------------------------------------
+
+
+
+
+
+
+
 
 
 
@@ -951,12 +1203,12 @@ const endDate = document.getElementById('end-date');
 const submitButton = document.getElementById('submit-button');
 const licenseInfoContainer = document.getElementById('license-info-restaurant-list');
 
-// 监听确定按钮的点击事件,点击后触发过滤功能
-submitButton.addEventListener('click', filterContent);
 
 // 过滤功能实现
 function filterContent() {
     console.log('过滤功能触发');
+        // 移除滚动监听器,停止滚动加载
+       // removeScrollListeners();
     // 构建请求体参数
     const requestData = {
         license_flag: statusFilter.value || undefined,
@@ -996,4 +1248,29 @@ function displayLicenseInfo(data) {
       renderLicenseCards(data, true);
     
 }
+// 确定按钮点击事件的修改(停止滚动监听)
+submitButton.addEventListener('click', function() {
+    // 执行过滤内容功能
+    filterContent();
+
+    // 隐藏滚动加载,防止继续加载更多内容
+    removeScrollListeners();
+});
+
+
+
+// 监听返回按钮的点击事件,刷新页面并恢复滚动监听
+const resetButton = document.getElementById('reset-button');
+resetButton.addEventListener('click', function() {
+    // 刷新页面
+    location.reload();
+});
+
+// 修改当搜索栏没有输入时,重新启动滚动监听
+searchBar.addEventListener('input', function() {
+    if (!searchBar.value && !statusFilter.value && !startDate.value && !endDate.value) {
+        console.log("搜索条件清空,重新启动滚动监听");
+        restartScrollListeners();
+    }
+});
 

+ 71 - 0
static/license_info/license_info_distribution.js

@@ -0,0 +1,71 @@
+
+
+//--------------分发历史模态框------------------------
+function showDistributionHistory(selectedRowData) {
+    fetch('http://127.0.0.1:8080/api/admin/GetlicenseRecord', {
+        method: 'POST',
+        headers: {
+            'Authorization': `Bearer ${authToken}`,
+            'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({ uniqueID: selectedRowData.UniqueID, oa_request_id: selectedRowData.oa_request_id })
+    })
+    .then(response => response.json())
+    .then(data => {
+        const userDistributionContent = document.getElementById('distributionHistory-user-content');
+        const emailDistributionContent = document.getElementById('distributionHistory-email-content');
+        
+        // 检查 license_record_to_user 是否是数组,如果不是则默认为空数组
+        const userRecords = Array.isArray(data?.data?.license_record_to_user) ? data.data.license_record_to_user : [];
+        
+        // 如果 license_record_to_emails 是 null,则设置为空数组
+        const emailRecords = Array.isArray(data?.data?.license_record_to_emails) ? data.data.license_record_to_emails : [];
+    
+        // 显示用户分发记录
+        userDistributionContent.innerHTML = userRecords.length > 0 
+            ? userRecords.map(record => `<p>已转发给用户: ${record.user_account} 时间: ${formatDateTime(record.up_time)}</p>`).join('') 
+            : '<p>没有用户分发记录。</p>';
+    
+        // 显示邮箱分发记录
+        emailDistributionContent.innerHTML = emailRecords.length > 0 
+            ? emailRecords.map(record => `<p>已发给邮箱: ${record.emails} 时间: ${formatDateTime(record.up_time)}</p>`).join('') 
+            : '<p>没有邮箱分发记录。</p>';
+    
+        // 显示模态框
+        document.getElementById('distributionHistory-modal').style.display = 'block';
+    })
+    .catch(error => {
+        console.error('Error fetching distribution history:', error);
+    });
+
+    // 关闭模态框 (点击关闭按钮)
+    document.querySelector('.distributionHistory-modal-close').addEventListener('click', () => {  
+        document.getElementById('distributionHistory-modal').style.display = 'none';
+    });
+
+    // 点击模态框外部关闭模态框
+    window.addEventListener('click', function(event) {
+        const modal = document.getElementById('distributionHistory-modal');
+        if (event.target === modal) {  // 检查点击的是否是模态框背景
+            modal.style.display = 'none';  // 关闭模态框
+        }
+    });
+}
+
+function formatDateTime(dateString) {
+    const date = new Date(dateString);
+
+    // 获取 UTC 时间
+    const year = date.getUTCFullYear();
+    const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // 月份从0开始,所以+1
+    const day = String(date.getUTCDate()).padStart(2, '0');
+    const hours = String(date.getUTCHours()).padStart(2, '0');
+    const minutes = String(date.getUTCMinutes()).padStart(2, '0');
+    const seconds = String(date.getUTCSeconds()).padStart(2, '0');
+
+    // 返回格式化后的字符串,格式为 YYYY-MM-DD HH:mm:ss
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+
+
+
+}