license.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. package handlers
  2. import (
  3. "encoding/json"
  4. "license-admin/models"
  5. "math/rand"
  6. "net/http"
  7. "strconv"
  8. "github.com/gin-gonic/gin"
  9. "gorm.io/gorm"
  10. )
  11. // CreateLicenseRequest 创建 License 请求结构
  12. type CreateLicenseRequest struct {
  13. Key string `json:"key" binding:"required"` // 激活码(必填)
  14. MaxDevices int `json:"max_devices"` // 最大设备数(可选,默认2)
  15. BoundDevices string `json:"bound_devices,omitempty"` // 初始绑定设备列表(可选,默认为空数组)
  16. }
  17. // UpdateLicenseRequest 更新 License 请求结构
  18. type UpdateLicenseRequest struct {
  19. Key string `json:"key,omitempty"` // 激活码(可选)
  20. MaxDevices *int `json:"max_devices,omitempty"` // 最大设备数(可选,使用指针以区分零值)
  21. BoundDevices string `json:"bound_devices,omitempty"` // 绑定设备列表(可选)
  22. }
  23. // LicenseResponse License 响应结构
  24. type LicenseResponse struct {
  25. Code int `json:"code"` // 状态码:0 表示成功,非0 表示失败
  26. Msg string `json:"msg"` // 响应消息
  27. Data *models.License `json:"data,omitempty"` // License 数据
  28. }
  29. // LicenseListResponse License 列表响应结构
  30. type LicenseListResponse struct {
  31. Code int `json:"code"` // 状态码:0 表示成功,非0 表示失败
  32. Msg string `json:"msg"` // 响应消息
  33. Data []models.License `json:"data"` // License 列表
  34. Total int64 `json:"total"` // 总数
  35. }
  36. // CreateLicense 创建新的 License
  37. // POST /api/licenses
  38. func CreateLicense(db *gorm.DB) gin.HandlerFunc {
  39. return func(c *gin.Context) {
  40. var req CreateLicenseRequest
  41. if err := c.ShouldBindJSON(&req); err != nil {
  42. c.JSON(http.StatusBadRequest, LicenseResponse{
  43. Code: 400,
  44. Msg: "请求参数错误: " + err.Error(),
  45. })
  46. return
  47. }
  48. // 检查 Key 是否已存在
  49. var existingLicense models.License
  50. result := db.Where("key = ?", req.Key).First(&existingLicense)
  51. if result.Error == nil {
  52. // Key 已存在
  53. c.JSON(http.StatusBadRequest, LicenseResponse{
  54. Code: 400,
  55. Msg: "激活码已存在",
  56. })
  57. return
  58. }
  59. if result.Error != gorm.ErrRecordNotFound {
  60. // 数据库查询错误
  61. c.JSON(http.StatusInternalServerError, LicenseResponse{
  62. Code: 500,
  63. Msg: "数据库查询错误: " + result.Error.Error(),
  64. })
  65. return
  66. }
  67. // 设置默认值
  68. if req.MaxDevices <= 0 {
  69. req.MaxDevices = 2 // 默认最大设备数为 2
  70. }
  71. if req.BoundDevices == "" {
  72. req.BoundDevices = "[]" // 默认为空数组
  73. }
  74. // 创建新的 License
  75. license := models.License{
  76. Key: req.Key,
  77. MaxDevices: req.MaxDevices,
  78. BoundDevices: req.BoundDevices,
  79. }
  80. if err := db.Create(&license).Error; err != nil {
  81. c.JSON(http.StatusInternalServerError, LicenseResponse{
  82. Code: 500,
  83. Msg: "创建 License 失败: " + err.Error(),
  84. })
  85. return
  86. }
  87. c.JSON(http.StatusOK, LicenseResponse{
  88. Code: 0,
  89. Msg: "创建成功",
  90. Data: &license,
  91. })
  92. }
  93. }
  94. // GetLicenseList 获取 License 列表
  95. // GET /api/licenses?page=1&page_size=10
  96. func GetLicenseList(db *gorm.DB) gin.HandlerFunc {
  97. return func(c *gin.Context) {
  98. // 解析分页参数
  99. page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
  100. pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
  101. if page < 1 {
  102. page = 1
  103. }
  104. if pageSize < 1 || pageSize > 100 {
  105. pageSize = 10
  106. }
  107. var licenses []models.License
  108. var total int64
  109. // 获取总数
  110. if err := db.Model(&models.License{}).Count(&total).Error; err != nil {
  111. c.JSON(http.StatusInternalServerError, LicenseListResponse{
  112. Code: 500,
  113. Msg: "查询总数失败: " + err.Error(),
  114. Data: []models.License{},
  115. Total: 0,
  116. })
  117. return
  118. }
  119. // 分页查询
  120. offset := (page - 1) * pageSize
  121. if err := db.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&licenses).Error; err != nil {
  122. c.JSON(http.StatusInternalServerError, LicenseListResponse{
  123. Code: 500,
  124. Msg: "查询 License 列表失败: " + err.Error(),
  125. Data: []models.License{},
  126. Total: 0,
  127. })
  128. return
  129. }
  130. c.JSON(http.StatusOK, LicenseListResponse{
  131. Code: 0,
  132. Msg: "success",
  133. Data: licenses,
  134. Total: total,
  135. })
  136. }
  137. }
  138. // GetLicense 获取单个 License
  139. // GET /api/licenses/:id
  140. func GetLicense(db *gorm.DB) gin.HandlerFunc {
  141. return func(c *gin.Context) {
  142. id, err := strconv.ParseUint(c.Param("id"), 10, 32)
  143. if err != nil {
  144. c.JSON(http.StatusBadRequest, LicenseResponse{
  145. Code: 400,
  146. Msg: "无效的 ID 参数",
  147. })
  148. return
  149. }
  150. var license models.License
  151. result := db.First(&license, id)
  152. if result.Error != nil {
  153. if result.Error == gorm.ErrRecordNotFound {
  154. c.JSON(http.StatusNotFound, LicenseResponse{
  155. Code: 404,
  156. Msg: "License 不存在",
  157. })
  158. return
  159. }
  160. c.JSON(http.StatusInternalServerError, LicenseResponse{
  161. Code: 500,
  162. Msg: "查询失败: " + result.Error.Error(),
  163. })
  164. return
  165. }
  166. c.JSON(http.StatusOK, LicenseResponse{
  167. Code: 0,
  168. Msg: "success",
  169. Data: &license,
  170. })
  171. }
  172. }
  173. // UpdateLicense 更新 License
  174. // PUT /api/licenses/:id
  175. func UpdateLicense(db *gorm.DB) gin.HandlerFunc {
  176. return func(c *gin.Context) {
  177. id, err := strconv.ParseUint(c.Param("id"), 10, 32)
  178. if err != nil {
  179. c.JSON(http.StatusBadRequest, LicenseResponse{
  180. Code: 400,
  181. Msg: "无效的 ID 参数",
  182. })
  183. return
  184. }
  185. // 查找 License
  186. var license models.License
  187. result := db.First(&license, id)
  188. if result.Error != nil {
  189. if result.Error == gorm.ErrRecordNotFound {
  190. c.JSON(http.StatusNotFound, LicenseResponse{
  191. Code: 404,
  192. Msg: "License 不存在",
  193. })
  194. return
  195. }
  196. c.JSON(http.StatusInternalServerError, LicenseResponse{
  197. Code: 500,
  198. Msg: "查询失败: " + result.Error.Error(),
  199. })
  200. return
  201. }
  202. // 解析更新请求
  203. var req UpdateLicenseRequest
  204. if err := c.ShouldBindJSON(&req); err != nil {
  205. c.JSON(http.StatusBadRequest, LicenseResponse{
  206. Code: 400,
  207. Msg: "请求参数错误: " + err.Error(),
  208. })
  209. return
  210. }
  211. // 更新字段
  212. if req.Key != "" {
  213. // 检查新 Key 是否与其他 License 冲突
  214. var existingLicense models.License
  215. checkResult := db.Where("key = ? AND id != ?", req.Key, id).First(&existingLicense)
  216. if checkResult.Error == nil {
  217. c.JSON(http.StatusBadRequest, LicenseResponse{
  218. Code: 400,
  219. Msg: "激活码已存在",
  220. })
  221. return
  222. }
  223. if checkResult.Error != gorm.ErrRecordNotFound {
  224. c.JSON(http.StatusInternalServerError, LicenseResponse{
  225. Code: 500,
  226. Msg: "检查激活码失败: " + checkResult.Error.Error(),
  227. })
  228. return
  229. }
  230. license.Key = req.Key
  231. }
  232. if req.MaxDevices != nil {
  233. if *req.MaxDevices <= 0 {
  234. c.JSON(http.StatusBadRequest, LicenseResponse{
  235. Code: 400,
  236. Msg: "最大设备数必须大于 0",
  237. })
  238. return
  239. }
  240. license.MaxDevices = *req.MaxDevices
  241. }
  242. if req.BoundDevices != "" {
  243. // 验证 BoundDevices 是否为有效的 JSON 数组
  244. var testDevices []string
  245. if err := json.Unmarshal([]byte(req.BoundDevices), &testDevices); err != nil {
  246. c.JSON(http.StatusBadRequest, LicenseResponse{
  247. Code: 400,
  248. Msg: "bound_devices 必须是有效的 JSON 数组: " + err.Error(),
  249. })
  250. return
  251. }
  252. license.BoundDevices = req.BoundDevices
  253. }
  254. // 保存更新
  255. if err := db.Save(&license).Error; err != nil {
  256. c.JSON(http.StatusInternalServerError, LicenseResponse{
  257. Code: 500,
  258. Msg: "更新失败: " + err.Error(),
  259. })
  260. return
  261. }
  262. c.JSON(http.StatusOK, LicenseResponse{
  263. Code: 0,
  264. Msg: "更新成功",
  265. Data: &license,
  266. })
  267. }
  268. }
  269. // DeleteLicense 删除 License
  270. // DELETE /api/licenses/:id
  271. func DeleteLicense(db *gorm.DB) gin.HandlerFunc {
  272. return func(c *gin.Context) {
  273. id, err := strconv.ParseUint(c.Param("id"), 10, 32)
  274. if err != nil {
  275. c.JSON(http.StatusBadRequest, gin.H{
  276. "code": 400,
  277. "msg": "无效的 ID 参数",
  278. })
  279. return
  280. }
  281. // 查找 License
  282. var license models.License
  283. result := db.First(&license, id)
  284. if result.Error != nil {
  285. if result.Error == gorm.ErrRecordNotFound {
  286. c.JSON(http.StatusNotFound, gin.H{
  287. "code": 404,
  288. "msg": "License 不存在",
  289. })
  290. return
  291. }
  292. c.JSON(http.StatusInternalServerError, gin.H{
  293. "code": 500,
  294. "msg": "查询失败: " + result.Error.Error(),
  295. })
  296. return
  297. }
  298. // 删除 License
  299. if err := db.Delete(&license).Error; err != nil {
  300. c.JSON(http.StatusInternalServerError, gin.H{
  301. "code": 500,
  302. "msg": "删除失败: " + err.Error(),
  303. })
  304. return
  305. }
  306. c.JSON(http.StatusOK, gin.H{
  307. "code": 0,
  308. "msg": "删除成功",
  309. })
  310. }
  311. }
  312. // BatchDeleteLicenseRequest 批量删除 License 请求结构
  313. type BatchDeleteLicenseRequest struct {
  314. IDs []uint `json:"ids" binding:"required"` // License ID 列表
  315. }
  316. // BatchDeleteLicenseResponse 批量删除响应结构
  317. type BatchDeleteLicenseResponse struct {
  318. Code int `json:"code"` // 状态码:0 表示成功,非0 表示失败
  319. Msg string `json:"msg"` // 响应消息
  320. Total int `json:"total"` // 成功删除的数量
  321. }
  322. // BatchDeleteLicense 批量删除 License
  323. // DELETE /api/licenses/batch
  324. func BatchDeleteLicense(db *gorm.DB) gin.HandlerFunc {
  325. return func(c *gin.Context) {
  326. var req BatchDeleteLicenseRequest
  327. if err := c.ShouldBindJSON(&req); err != nil {
  328. c.JSON(http.StatusBadRequest, BatchDeleteLicenseResponse{
  329. Code: 400,
  330. Msg: "请求参数错误: " + err.Error(),
  331. Total: 0,
  332. })
  333. return
  334. }
  335. // 验证参数
  336. if len(req.IDs) == 0 {
  337. c.JSON(http.StatusBadRequest, BatchDeleteLicenseResponse{
  338. Code: 400,
  339. Msg: "请至少选择一个 License",
  340. Total: 0,
  341. })
  342. return
  343. }
  344. if len(req.IDs) > 100 {
  345. c.JSON(http.StatusBadRequest, BatchDeleteLicenseResponse{
  346. Code: 400,
  347. Msg: "一次最多只能删除 100 个 License",
  348. Total: 0,
  349. })
  350. return
  351. }
  352. // 批量删除
  353. result := db.Where("id IN ?", req.IDs).Delete(&models.License{})
  354. if result.Error != nil {
  355. c.JSON(http.StatusInternalServerError, BatchDeleteLicenseResponse{
  356. Code: 500,
  357. Msg: "批量删除失败: " + result.Error.Error(),
  358. Total: 0,
  359. })
  360. return
  361. }
  362. deletedCount := int(result.RowsAffected)
  363. c.JSON(http.StatusOK, BatchDeleteLicenseResponse{
  364. Code: 0,
  365. Msg: "成功删除 " + strconv.Itoa(deletedCount) + " 个 License",
  366. Total: deletedCount,
  367. })
  368. }
  369. }
  370. // BatchCreateLicenseRequest 批量创建 License 请求结构
  371. type BatchCreateLicenseRequest struct {
  372. Prefix string `json:"prefix" binding:"required"` // 激活码前缀(必填)
  373. Count int `json:"count" binding:"required"` // 生成数量(必填)
  374. MaxDevices int `json:"max_devices"` // 最大设备数(可选,默认2)
  375. }
  376. // BatchCreateLicenseResponse 批量创建响应结构
  377. type BatchCreateLicenseResponse struct {
  378. Code int `json:"code"` // 状态码:0 表示成功,非0 表示失败
  379. Msg string `json:"msg"` // 响应消息
  380. Data []models.License `json:"data"` // 创建的 License 列表
  381. Total int `json:"total"` // 成功创建的数量
  382. }
  383. // BatchCreateLicense 批量创建 License
  384. // POST /api/licenses/batch
  385. func BatchCreateLicense(db *gorm.DB) gin.HandlerFunc {
  386. return func(c *gin.Context) {
  387. var req BatchCreateLicenseRequest
  388. if err := c.ShouldBindJSON(&req); err != nil {
  389. c.JSON(http.StatusBadRequest, BatchCreateLicenseResponse{
  390. Code: 400,
  391. Msg: "请求参数错误: " + err.Error(),
  392. Data: []models.License{},
  393. Total: 0,
  394. })
  395. return
  396. }
  397. // 验证参数
  398. if req.Count <= 0 || req.Count > 1000 {
  399. c.JSON(http.StatusBadRequest, BatchCreateLicenseResponse{
  400. Code: 400,
  401. Msg: "生成数量必须在 1-1000 之间",
  402. Data: []models.License{},
  403. Total: 0,
  404. })
  405. return
  406. }
  407. // 设置默认值
  408. if req.MaxDevices <= 0 {
  409. req.MaxDevices = 2
  410. }
  411. // 批量创建 License
  412. var licenses []models.License
  413. var successCount int
  414. var failedKeys []string
  415. for i := 1; i <= req.Count; i++ {
  416. // 生成激活码:前缀 + 32位随机字符串
  417. key := req.Prefix + "-" + generateRandomKey(32)
  418. // 检查 Key 是否已存在
  419. var existingLicense models.License
  420. result := db.Where("key = ?", key).First(&existingLicense)
  421. if result.Error == nil {
  422. // Key 已存在,跳过并记录
  423. failedKeys = append(failedKeys, key)
  424. continue
  425. }
  426. if result.Error != gorm.ErrRecordNotFound {
  427. // 数据库查询错误
  428. failedKeys = append(failedKeys, key)
  429. continue
  430. }
  431. // 创建新的 License
  432. license := models.License{
  433. Key: key,
  434. MaxDevices: req.MaxDevices,
  435. BoundDevices: "[]",
  436. }
  437. if err := db.Create(&license).Error; err != nil {
  438. failedKeys = append(failedKeys, key)
  439. continue
  440. }
  441. licenses = append(licenses, license)
  442. successCount++
  443. }
  444. // 构建响应消息
  445. msg := "成功创建 " + strconv.Itoa(successCount) + " 个 License"
  446. if len(failedKeys) > 0 {
  447. msg += ",跳过 " + strconv.Itoa(len(failedKeys)) + " 个重复或失败的激活码"
  448. }
  449. c.JSON(http.StatusOK, BatchCreateLicenseResponse{
  450. Code: 0,
  451. Msg: msg,
  452. Data: licenses,
  453. Total: successCount,
  454. })
  455. }
  456. }
  457. // generateRandomKey 生成随机激活码后缀
  458. func generateRandomKey(length int) string {
  459. const charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  460. b := make([]byte, length)
  461. for i := range b {
  462. b[i] = charset[getRandomInt(len(charset))]
  463. }
  464. return string(b)
  465. }
  466. // getRandomInt 获取随机整数
  467. func getRandomInt(max int) int {
  468. return rand.Intn(max)
  469. }