Performance.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. package controllers
  2. import (
  3. "ERP_salary/Nats/NatsServer"
  4. "ERP_salary/conf"
  5. "ERP_salary/dto"
  6. "ERP_salary/logs"
  7. "ERP_salary/models/Account"
  8. "ERP_salary/models/Performance"
  9. "ERP_salary/services"
  10. "encoding/json"
  11. "fmt"
  12. "io"
  13. "math"
  14. "net/http"
  15. "net/url"
  16. "strconv"
  17. "strings"
  18. "time"
  19. "github.com/robfig/cron/v3"
  20. "github.com/xuri/excelize/v2"
  21. beego "github.com/beego/beego/v2/server/web"
  22. userlibs "gogs.baozhida.cn/zoie/ERP_libs/User"
  23. "gogs.baozhida.cn/zoie/ERP_libs/lib"
  24. )
  25. type PerformanceController struct {
  26. beego.Controller
  27. User userlibs.User
  28. }
  29. // calculateTotalScore 计算总得分百分比
  30. func calculateTotalScore(perf Performance.Perf) float64 {
  31. if perf.T_assess_points == 0 {
  32. return 0
  33. }
  34. return (perf.T_workload / float64(perf.T_assess_points)) * 100
  35. }
  36. // calculatePerfTotal 计算应发绩效
  37. func calculatePerfTotal(perf Performance.Perf) float64 {
  38. score := calculateTotalScore(perf)
  39. if score >= 100 {
  40. return perf.T_perf
  41. }
  42. return (score / 100) * perf.T_perf
  43. }
  44. func (c *PerformanceController) Prepare() {
  45. c.User = *Account.User_r
  46. }
  47. func (c *PerformanceController) Points_List() {
  48. s := services.PerformancePoints{}
  49. reqData := dto.PerformancePointsPageReq{}
  50. if err := c.ParseForm(&reqData); err != nil {
  51. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  52. c.ServeJSON()
  53. return
  54. }
  55. if err := Validate(&reqData); err != nil {
  56. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  57. c.ServeJSON()
  58. return
  59. }
  60. R_List, R_cnt := s.GetPage(&reqData)
  61. var r_jsons lib.R_JSONS
  62. r_jsons.Num = R_cnt
  63. r_jsons.Data = R_List
  64. r_jsons.Page = reqData.Page
  65. r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(reqData.PageSize)))
  66. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
  67. c.ServeJSON()
  68. return
  69. }
  70. func (c *PerformanceController) Points_Add() {
  71. s := services.PerformancePoints{}
  72. reqData := dto.PerformancePointsInsertReq{}
  73. if err := c.ParseForm(&reqData); err != nil {
  74. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  75. c.ServeJSON()
  76. return
  77. }
  78. if err := Validate(&reqData); err != nil {
  79. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  80. c.ServeJSON()
  81. return
  82. }
  83. Id, err := s.Insert(&reqData)
  84. if err != nil {
  85. c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败"}
  86. c.ServeJSON()
  87. return
  88. }
  89. NatsServer.AddUserLogs(c.User.T_uuid, "绩效点", "添加", reqData)
  90. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
  91. c.ServeJSON()
  92. return
  93. }
  94. func (c *PerformanceController) Points_Edit() {
  95. s := services.PerformancePoints{}
  96. reqData := dto.PerformancePointsUpdateReq{}
  97. if err := c.ParseForm(&reqData); err != nil {
  98. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  99. c.ServeJSON()
  100. return
  101. }
  102. if err := Validate(&reqData); err != nil {
  103. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  104. c.ServeJSON()
  105. return
  106. }
  107. if err := s.Update(&reqData); err != nil {
  108. c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败"}
  109. c.ServeJSON()
  110. return
  111. }
  112. NatsServer.AddUserLogs(c.User.T_uuid, "绩效点", "修改", reqData)
  113. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  114. c.ServeJSON()
  115. return
  116. }
  117. func (c *PerformanceController) Points_Del() {
  118. s := services.PerformancePoints{}
  119. reqData := dto.PerformancePointsDeleteReq{}
  120. if err := c.ParseForm(&reqData); err != nil {
  121. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  122. c.ServeJSON()
  123. return
  124. }
  125. if err := Validate(&reqData); err != nil {
  126. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  127. c.ServeJSON()
  128. return
  129. }
  130. if err := s.Delete(&reqData); err != nil {
  131. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  132. c.ServeJSON()
  133. return
  134. }
  135. NatsServer.AddUserLogs(c.User.T_uuid, "绩效点", "删除", strconv.Itoa(reqData.T_id))
  136. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  137. c.ServeJSON()
  138. return
  139. }
  140. func (c *PerformanceController) Target_List() {
  141. s := services.PerformanceTarget{}
  142. reqData := dto.PerformanceTargetPageReq{}
  143. if err := c.ParseForm(&reqData); err != nil {
  144. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  145. c.ServeJSON()
  146. return
  147. }
  148. if err := Validate(&reqData); err != nil {
  149. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  150. c.ServeJSON()
  151. return
  152. }
  153. R_List, R_cnt := s.GetPage(&reqData)
  154. var r_jsons lib.R_JSONS
  155. r_jsons.Num = R_cnt
  156. r_jsons.Data = R_List
  157. r_jsons.Page = reqData.Page
  158. r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(reqData.PageSize)))
  159. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
  160. c.ServeJSON()
  161. return
  162. }
  163. func (c *PerformanceController) Target_Add() {
  164. s := services.PerformanceTarget{}
  165. reqData := dto.PerformanceTargetInsertReq{}
  166. if err := c.ParseForm(&reqData); err != nil {
  167. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  168. c.ServeJSON()
  169. return
  170. }
  171. if err := Validate(&reqData); err != nil {
  172. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  173. c.ServeJSON()
  174. return
  175. }
  176. Id, err := s.Insert(&reqData)
  177. if err != nil {
  178. c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败"}
  179. c.ServeJSON()
  180. return
  181. }
  182. NatsServer.AddUserLogs(c.User.T_uuid, "绩效指标", "添加", reqData)
  183. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
  184. c.ServeJSON()
  185. return
  186. }
  187. func (c *PerformanceController) Target_Edit() {
  188. s := services.PerformanceTarget{}
  189. reqData := dto.PerformanceTargetUpdateReq{}
  190. if err := c.ParseForm(&reqData); err != nil {
  191. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  192. c.ServeJSON()
  193. return
  194. }
  195. if err := Validate(&reqData); err != nil {
  196. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  197. c.ServeJSON()
  198. return
  199. }
  200. if err := s.Update(&reqData); err != nil {
  201. c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败"}
  202. c.ServeJSON()
  203. return
  204. }
  205. NatsServer.AddUserLogs(c.User.T_uuid, "绩效指标", "修改", reqData)
  206. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  207. c.ServeJSON()
  208. return
  209. }
  210. func (c *PerformanceController) Target_Del() {
  211. s := services.PerformanceTarget{}
  212. reqData := dto.PerformanceTargetDeleteReq{}
  213. if err := c.ParseForm(&reqData); err != nil {
  214. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  215. c.ServeJSON()
  216. return
  217. }
  218. if err := Validate(&reqData); err != nil {
  219. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  220. c.ServeJSON()
  221. return
  222. }
  223. if err := s.Delete(&reqData); err != nil {
  224. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  225. c.ServeJSON()
  226. return
  227. }
  228. NatsServer.AddUserLogs(c.User.T_uuid, "绩效指标", "删除", strconv.Itoa(reqData.T_id))
  229. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  230. c.ServeJSON()
  231. return
  232. }
  233. // 绩效-用户
  234. func (c *PerformanceController) List() {
  235. s := services.Performance{}
  236. reqData := dto.PerformancePageReq{}
  237. if err := c.ParseForm(&reqData); err != nil {
  238. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  239. c.ServeJSON()
  240. return
  241. }
  242. if err := Validate(&reqData); err != nil {
  243. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  244. c.ServeJSON()
  245. return
  246. }
  247. userList, _ := NatsServer.Read_User_List_All()
  248. Account.Read_User_All_Map(userList)
  249. R_List, R_cnt := s.GetManagerPage(&reqData)
  250. var r_jsons lib.R_JSONS
  251. r_jsons.Num = R_cnt
  252. r_jsons.Data = R_List
  253. r_jsons.Page = reqData.Page
  254. r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(reqData.PageSize)))
  255. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
  256. c.ServeJSON()
  257. return
  258. }
  259. func (c *PerformanceController) Excel() {
  260. s := services.Performance{}
  261. reqData := dto.PerformancePageReq{}
  262. if err := c.ParseForm(&reqData); err != nil {
  263. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  264. c.ServeJSON()
  265. return
  266. }
  267. if err := Validate(&reqData); err != nil {
  268. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  269. c.ServeJSON()
  270. return
  271. }
  272. reqData.PageSize = 9999
  273. userList, _ := NatsServer.Read_User_List_All()
  274. Account.Read_User_All_Map(userList)
  275. R_List, R_cnt := s.GetManagerPage(&reqData)
  276. // 创建Excel文件
  277. f := excelize.NewFile()
  278. defer func() {
  279. if err := f.Close(); err != nil {
  280. logs.Error("关闭Excel文件失败: %s", err)
  281. }
  282. }()
  283. // 设置工作表名称
  284. sheetName := "绩效管理"
  285. index, err := f.NewSheet(sheetName)
  286. if err != nil {
  287. logs.Error("创建工作表失败: %s", err)
  288. c.Data["json"] = lib.JSONS{Code: 500, Msg: "创建Excel文件失败"}
  289. c.ServeJSON()
  290. return
  291. }
  292. f.SetActiveSheet(index)
  293. // 设置表头
  294. headers := []string{"序号", "姓名", "工资级别", "绩效工资(元)", "所属月份", "工作量", "考核工作量", "得分", "应发绩效"}
  295. for i, header := range headers {
  296. cell := fmt.Sprintf("%c1", 'A'+i)
  297. f.SetCellValue(sheetName, cell, header)
  298. }
  299. // 设置表头样式
  300. headerStyle, err := f.NewStyle(&excelize.Style{
  301. Font: &excelize.Font{
  302. Bold: true,
  303. },
  304. Alignment: &excelize.Alignment{
  305. Horizontal: "center",
  306. Vertical: "center",
  307. },
  308. Fill: excelize.Fill{
  309. Type: "pattern",
  310. Color: []string{"#E6F3FF"},
  311. Pattern: 1,
  312. },
  313. })
  314. if err == nil {
  315. f.SetCellStyle(sheetName, "A1", fmt.Sprintf("%c1", 'A'+len(headers)-1), headerStyle)
  316. }
  317. // 填充数据
  318. for i, perf := range R_List {
  319. row := i + 2 // 从第2行开始(第1行是表头)
  320. // 序号
  321. f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), i+1)
  322. // 姓名
  323. f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), perf.T_submit_name)
  324. // 工资级别
  325. f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), perf.Target.T_name)
  326. // 绩效工资(元)
  327. f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), perf.T_perf)
  328. // 所属月份
  329. f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), perf.T_date)
  330. // 工作量
  331. f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), perf.T_workload)
  332. // 考核工作量
  333. f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), perf.T_assess_points)
  334. // 得分
  335. score := calculateTotalScore(perf)
  336. f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("%.1f%%", score))
  337. // 应发绩效
  338. perfTotal := calculatePerfTotal(perf)
  339. f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), fmt.Sprintf("%.2f", perfTotal))
  340. }
  341. // 设置列宽
  342. f.SetColWidth(sheetName, "A", "A", 8) // 序号
  343. f.SetColWidth(sheetName, "B", "B", 12) // 姓名
  344. f.SetColWidth(sheetName, "C", "C", 12) // 工资级别
  345. f.SetColWidth(sheetName, "D", "D", 15) // 绩效工资(元)
  346. f.SetColWidth(sheetName, "E", "E", 12) // 所属月份
  347. f.SetColWidth(sheetName, "F", "F", 12) // 工作量
  348. f.SetColWidth(sheetName, "G", "G", 15) // 考核工作量
  349. f.SetColWidth(sheetName, "H", "H", 12) // 得分
  350. f.SetColWidth(sheetName, "I", "I", 15) // 应发绩效
  351. // 设置数据区域样式
  352. dataStyle, err := f.NewStyle(&excelize.Style{
  353. Alignment: &excelize.Alignment{
  354. Horizontal: "center",
  355. Vertical: "center",
  356. },
  357. Border: []excelize.Border{
  358. {Type: "left", Color: "CCCCCC", Style: 1},
  359. {Type: "top", Color: "CCCCCC", Style: 1},
  360. {Type: "bottom", Color: "CCCCCC", Style: 1},
  361. {Type: "right", Color: "CCCCCC", Style: 1},
  362. },
  363. })
  364. if err == nil && len(R_List) > 0 {
  365. f.SetCellStyle(sheetName, "A2", fmt.Sprintf("I%d", len(R_List)+1), dataStyle)
  366. }
  367. // 生成文件名
  368. fileName := fmt.Sprintf("绩效管理_%s.xlsx", time.Now().Format("20060102_150405"))
  369. // 设置响应头
  370. c.Ctx.Output.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
  371. c.Ctx.Output.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
  372. c.Ctx.Output.Header("Content-Transfer-Encoding", "binary")
  373. // 写入响应
  374. if err := f.Write(c.Ctx.ResponseWriter); err != nil {
  375. logs.Error("写入Excel文件失败: %s", err)
  376. c.Data["json"] = lib.JSONS{Code: 500, Msg: "导出Excel失败"}
  377. c.ServeJSON()
  378. return
  379. }
  380. logs.Println(fmt.Sprintf("成功导出绩效管理Excel文件,共%d条记录", R_cnt))
  381. }
  382. func (c *PerformanceController) User_List() {
  383. s := services.Performance{}
  384. reqData := dto.PerformanceUserPageReq{}
  385. if err := c.ParseForm(&reqData); err != nil {
  386. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  387. c.ServeJSON()
  388. return
  389. }
  390. if err := Validate(&reqData); err != nil {
  391. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  392. c.ServeJSON()
  393. return
  394. }
  395. userList, _ := NatsServer.Read_User_List_All()
  396. Account.Read_User_All_Map(userList)
  397. reqData.T_submit = c.User.T_uuid
  398. R_List, R_cnt := s.GetPage(&reqData)
  399. var r_jsons lib.R_JSONS
  400. r_jsons.Num = R_cnt
  401. r_jsons.Data = R_List
  402. r_jsons.Page = reqData.Page
  403. r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(reqData.PageSize)))
  404. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
  405. c.ServeJSON()
  406. return
  407. }
  408. func (c *PerformanceController) User_Excel() {
  409. s := services.Performance{}
  410. reqData := dto.PerformanceUserPageReq{}
  411. if err := c.ParseForm(&reqData); err != nil {
  412. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  413. c.ServeJSON()
  414. return
  415. }
  416. if err := Validate(&reqData); err != nil {
  417. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  418. c.ServeJSON()
  419. return
  420. }
  421. reqData.PageSize = 9999
  422. reqData.T_submit = c.User.T_uuid
  423. userList, _ := NatsServer.Read_User_List_All()
  424. Account.Read_User_All_Map(userList)
  425. R_List, R_cnt := s.GetPage(&reqData)
  426. // 创建Excel文件
  427. f := excelize.NewFile()
  428. defer func() {
  429. if err := f.Close(); err != nil {
  430. logs.Error("关闭Excel文件失败: %s", err)
  431. }
  432. }()
  433. // 设置工作表名称
  434. sheetName := "绩效管理"
  435. index, err := f.NewSheet(sheetName)
  436. if err != nil {
  437. logs.Error("创建工作表失败: %s", err)
  438. c.Data["json"] = lib.JSONS{Code: 500, Msg: "创建Excel文件失败"}
  439. c.ServeJSON()
  440. return
  441. }
  442. f.SetActiveSheet(index)
  443. // 设置表头
  444. headers := []string{"序号", "姓名", "工资级别", "绩效工资(元)", "所属月份", "工作量", "考核工作量", "得分", "应发绩效"}
  445. for i, header := range headers {
  446. cell := fmt.Sprintf("%c1", 'A'+i)
  447. f.SetCellValue(sheetName, cell, header)
  448. }
  449. // 设置表头样式
  450. headerStyle, err := f.NewStyle(&excelize.Style{
  451. Font: &excelize.Font{
  452. Bold: true,
  453. },
  454. Alignment: &excelize.Alignment{
  455. Horizontal: "center",
  456. Vertical: "center",
  457. },
  458. Fill: excelize.Fill{
  459. Type: "pattern",
  460. Color: []string{"#E6F3FF"},
  461. Pattern: 1,
  462. },
  463. })
  464. if err == nil {
  465. f.SetCellStyle(sheetName, "A1", fmt.Sprintf("%c1", 'A'+len(headers)-1), headerStyle)
  466. }
  467. // 填充数据
  468. for i, perf := range R_List {
  469. row := i + 2 // 从第2行开始(第1行是表头)
  470. // 序号
  471. f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), i+1)
  472. // 姓名
  473. f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), perf.T_submit_name)
  474. // 工资级别
  475. f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), perf.Target.T_name)
  476. // 绩效工资(元)
  477. f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), perf.T_perf)
  478. // 所属月份
  479. f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), perf.T_date)
  480. // 工作量
  481. f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), perf.T_workload)
  482. // 考核工作量
  483. f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), perf.T_assess_points)
  484. // 得分
  485. score := calculateTotalScore(perf)
  486. f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("%.1f%%", score))
  487. // 应发绩效
  488. perfTotal := calculatePerfTotal(perf)
  489. f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), fmt.Sprintf("%.2f", perfTotal))
  490. }
  491. // 设置列宽
  492. f.SetColWidth(sheetName, "A", "A", 8) // 序号
  493. f.SetColWidth(sheetName, "B", "B", 12) // 姓名
  494. f.SetColWidth(sheetName, "C", "C", 12) // 工资级别
  495. f.SetColWidth(sheetName, "D", "D", 15) // 绩效工资(元)
  496. f.SetColWidth(sheetName, "E", "E", 12) // 所属月份
  497. f.SetColWidth(sheetName, "F", "F", 12) // 工作量
  498. f.SetColWidth(sheetName, "G", "G", 15) // 考核工作量
  499. f.SetColWidth(sheetName, "H", "H", 12) // 得分
  500. f.SetColWidth(sheetName, "I", "I", 15) // 应发绩效
  501. // 设置数据区域样式
  502. dataStyle, err := f.NewStyle(&excelize.Style{
  503. Alignment: &excelize.Alignment{
  504. Horizontal: "center",
  505. Vertical: "center",
  506. },
  507. Border: []excelize.Border{
  508. {Type: "left", Color: "CCCCCC", Style: 1},
  509. {Type: "top", Color: "CCCCCC", Style: 1},
  510. {Type: "bottom", Color: "CCCCCC", Style: 1},
  511. {Type: "right", Color: "CCCCCC", Style: 1},
  512. },
  513. })
  514. if err == nil && len(R_List) > 0 {
  515. f.SetCellStyle(sheetName, "A2", fmt.Sprintf("I%d", len(R_List)+1), dataStyle)
  516. }
  517. // 生成文件名
  518. fileName := fmt.Sprintf("绩效管理_%s.xlsx", time.Now().Format("20060102_150405"))
  519. // 设置响应头
  520. c.Ctx.Output.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
  521. c.Ctx.Output.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
  522. c.Ctx.Output.Header("Content-Transfer-Encoding", "binary")
  523. // 写入响应
  524. if err := f.Write(c.Ctx.ResponseWriter); err != nil {
  525. logs.Error("写入Excel文件失败: %s", err)
  526. c.Data["json"] = lib.JSONS{Code: 500, Msg: "导出Excel失败"}
  527. c.ServeJSON()
  528. return
  529. }
  530. logs.Println(fmt.Sprintf("成功导出绩效管理Excel文件,共%d条记录", R_cnt))
  531. }
  532. func (c *PerformanceController) Submit_User() {
  533. s := services.Performance{}
  534. page, _ := c.GetInt("page")
  535. if page < 1 {
  536. page = 1
  537. }
  538. page_z, _ := c.GetInt("page_z")
  539. if page_z < 1 {
  540. page_z = conf.Page_size
  541. }
  542. T_name := c.GetString("T_name")
  543. userList, _ := NatsServer.Read_User_List_All()
  544. Account.Read_User_All_Map(userList)
  545. uuidList := s.GetSubmitUserPage()
  546. R_List, R_cnt, err := NatsServer.Read_User_List_T_uuid(T_name, uuidList, page, page_z)
  547. if err != nil {
  548. c.Data["json"] = lib.JSONS{Code: 202, Msg: "查询失败"}
  549. c.ServeJSON()
  550. return
  551. }
  552. var U_List []userlibs.User
  553. for _, user := range R_List {
  554. U_List = append(U_List, user)
  555. }
  556. var r_jsons lib.R_JSONS
  557. r_jsons.Num = R_cnt
  558. r_jsons.Data = U_List
  559. r_jsons.Page = page
  560. r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(page_z)))
  561. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
  562. c.ServeJSON()
  563. return
  564. }
  565. func (c *PerformanceController) Add() {
  566. s := services.Performance{}
  567. reqData := dto.PerformanceInsertReq{}
  568. if err := c.ParseForm(&reqData); err != nil {
  569. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  570. c.ServeJSON()
  571. return
  572. }
  573. if err := json.Unmarshal([]byte(reqData.Points), &reqData.PointList); err != nil {
  574. c.Data["json"] = lib.JSONS{Code: 202, Msg: "绩效明细 参数错误"}
  575. c.ServeJSON()
  576. return
  577. }
  578. if err := Validate(&reqData); err != nil {
  579. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  580. c.ServeJSON()
  581. return
  582. }
  583. reqData.T_submit = c.User.T_uuid
  584. // 如传入绩效点,则校验非空
  585. if len(reqData.PointList) == 0 {
  586. c.Data["json"] = lib.JSONS{Code: 202, Msg: "绩效明细不能为空"}
  587. c.ServeJSON()
  588. return
  589. }
  590. Id, err := s.Insert(&reqData)
  591. if err != nil {
  592. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  593. c.ServeJSON()
  594. return
  595. }
  596. NatsServer.AddUserLogs(c.User.T_uuid, "绩效考核", "添加", reqData)
  597. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
  598. c.ServeJSON()
  599. return
  600. }
  601. func (c *PerformanceController) Edit() {
  602. s := services.Performance{}
  603. reqData := dto.PerformanceUpdateReq{}
  604. if err := c.ParseForm(&reqData); err != nil {
  605. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  606. c.ServeJSON()
  607. return
  608. }
  609. if err := json.Unmarshal([]byte(reqData.Points), &reqData.PointList); err != nil {
  610. c.Data["json"] = lib.JSONS{Code: 202, Msg: "绩效明细 参数错误"}
  611. c.ServeJSON()
  612. return
  613. }
  614. if err := Validate(&reqData); err != nil {
  615. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  616. c.ServeJSON()
  617. return
  618. }
  619. if err := s.Update(&reqData); err != nil {
  620. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  621. c.ServeJSON()
  622. return
  623. }
  624. NatsServer.AddUserLogs(c.User.T_uuid, "绩效考核", "修改", reqData)
  625. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  626. c.ServeJSON()
  627. return
  628. }
  629. func (c *PerformanceController) Edit_Audit() {
  630. s := services.Performance{}
  631. reqData := dto.PerformanceUpdateAuditReq{}
  632. if err := c.ParseForm(&reqData); err != nil {
  633. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  634. c.ServeJSON()
  635. return
  636. }
  637. if err := Validate(&reqData); err != nil {
  638. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  639. c.ServeJSON()
  640. return
  641. }
  642. if err := s.UpdateAudit(&reqData); err != nil {
  643. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  644. c.ServeJSON()
  645. return
  646. }
  647. NatsServer.AddUserLogs(c.User.T_uuid, "绩效考核", "修改状态", reqData)
  648. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  649. c.ServeJSON()
  650. return
  651. }
  652. func (c *PerformanceController) Del() {
  653. s := services.Performance{}
  654. reqData := dto.PerformanceDeleteReq{}
  655. if err := c.ParseForm(&reqData); err != nil {
  656. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  657. c.ServeJSON()
  658. return
  659. }
  660. if err := Validate(&reqData); err != nil {
  661. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  662. c.ServeJSON()
  663. return
  664. }
  665. if err := s.Delete(&reqData); err != nil {
  666. c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
  667. c.ServeJSON()
  668. return
  669. }
  670. NatsServer.AddUserLogs(c.User.T_uuid, "绩效考核", "删除", strconv.Itoa(reqData.T_id))
  671. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
  672. c.ServeJSON()
  673. return
  674. }
  675. // GetPerformanceDetail 根据ID获取绩效详情
  676. func (c *PerformanceController) GetPerformanceDetail() {
  677. s := services.Performance{}
  678. reqData := dto.PerformanceGetReq{}
  679. if err := c.ParseForm(&reqData); err != nil {
  680. c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
  681. c.ServeJSON()
  682. return
  683. }
  684. if reqData.T_id <= 0 {
  685. c.Data["json"] = lib.JSONS{Code: 202, Msg: "ID参数无效"}
  686. c.ServeJSON()
  687. return
  688. }
  689. perf, err := s.Get(reqData)
  690. if err != nil {
  691. c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取绩效详情失败: " + err.Error()}
  692. c.ServeJSON()
  693. return
  694. }
  695. // 获取关联的绩效点详情
  696. pointList, err := s.GetPerfPointsByPerfId(reqData.T_id)
  697. if err != nil {
  698. c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取绩效点详情失败: " + err.Error()}
  699. c.ServeJSON()
  700. return
  701. }
  702. // 组装返回数据
  703. result := map[string]interface{}{
  704. "perf": perf,
  705. "pointList": pointList,
  706. }
  707. c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: result}
  708. c.ServeJSON()
  709. return
  710. }
  711. func Cron_Percentage() {
  712. time.Sleep(10 * time.Second) // 等待10秒,确保数据库初始化完成
  713. //创建一个定时任务对象
  714. c := cron.New(cron.WithSeconds())
  715. //给对象增加定时任务 - 测试用:每分钟执行一次
  716. c.AddFunc("0 0 1 * *", SyncVerifyPercentage) // 生产环境:每月1日凌晨0点0分执行
  717. //启动定时任务
  718. c.Start()
  719. defer c.Stop()
  720. //查询语句,阻塞,让main函数不退出,保持程序运行
  721. select {}
  722. }
  723. // VerifyTaskResponse 冷链验证任务响应结构
  724. type VerifyTaskResponse struct {
  725. Data []Performance.VerifyTask
  726. Code int64
  727. Msg string
  728. }
  729. // buildVerifyRequest 构建冷链验证请求并处理响应
  730. func GetTaskList(startTime, endTime, requestType string) (*VerifyTaskResponse, error) {
  731. urls := "/openapi/task/list2"
  732. signature, timestamp := lib.GenColdVerifySignature()
  733. // 使用标准HTTP库替换resty
  734. formData := url.Values{}
  735. formData.Set("T_start_time", startTime)
  736. formData.Set("T_end_time", endTime)
  737. formData.Set("T_type", requestType)
  738. formData.Set("X-API-KEY", lib.ColdVerify_OpenApi_Key)
  739. formData.Set("X-API-SIGNATURE", signature)
  740. formData.Set("X-API-TIMESTAMP", timestamp)
  741. // 构建完整URL
  742. fullURL := conf.ColdVerify_OpenApi_Host + urls
  743. // 创建POST请求
  744. req, err := http.NewRequest("POST", fullURL, strings.NewReader(formData.Encode()))
  745. if err != nil {
  746. logs.Error("创建HTTP请求失败: %v", err)
  747. return nil, err
  748. }
  749. // 设置请求头
  750. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  751. // 创建HTTP客户端
  752. client := &http.Client{
  753. Timeout: 30 * time.Second,
  754. }
  755. // 发送请求
  756. resp, err := client.Do(req)
  757. if err != nil {
  758. logs.Error("请求冷链验证任务列表接口失败: %v", err)
  759. return nil, err
  760. }
  761. defer resp.Body.Close()
  762. // 读取响应体
  763. body, err := io.ReadAll(resp.Body)
  764. if err != nil {
  765. logs.Error("读取响应体失败: %v", err)
  766. return nil, err
  767. }
  768. // 检查响应状态码
  769. if resp.StatusCode != http.StatusOK {
  770. logs.Error("请求冷链验证任务列表接口失败,状态码: %d", resp.StatusCode)
  771. return nil, fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
  772. }
  773. // 解析响应
  774. var res VerifyTaskResponse
  775. if err = json.Unmarshal(body, &res); err != nil {
  776. logs.Error("解析响应数据失败: %v", err)
  777. return nil, err
  778. }
  779. return &res, nil
  780. }
  781. // processWorkloadStats 处理工作量统计逻辑
  782. func processWorkloadStats(res *VerifyTaskResponse, workType string) map[string]map[int]int {
  783. pointsMap := GetPerformancePointsMap()
  784. coldVerifyUUIDMap := GetColdVerifyUUIDMap()
  785. // 创建统计映射
  786. stat := map[string]map[int]int{}
  787. // 遍历所有任务,统计指定类型的工作量
  788. for _, task := range res.Data {
  789. verifyItem := GetPerformancePoints(Performance.DeviceTypeMap[task.T_device_type], task.T_verify_type, pointsMap)
  790. if verifyItem.Id == 0 {
  791. continue
  792. }
  793. var userUUID string
  794. if workType == "reporting" {
  795. // 报告编写人员统计
  796. userUUID = coldVerifyUUIDMap[task.T_reporting]
  797. } else if workType == "collection" {
  798. // 数据采集人员统计
  799. userUUID = coldVerifyUUIDMap[task.T_collection]
  800. }
  801. if userUUID != "" {
  802. updateWorkloadStat(stat, userUUID, verifyItem.Id)
  803. }
  804. }
  805. return stat
  806. }
  807. func SyncVerifyPercentage() {
  808. // 构建请求数据
  809. start_time := lib.GetFirstDayOfLastMonth() + " 00:00:00"
  810. end_time := lib.GetLastDayOfLastMonth() + " 23:59:59"
  811. // 请求报告编写类型的数据
  812. reportingRes, err := GetTaskList(start_time, end_time, "reporting")
  813. if err != nil {
  814. logs.Error("请求报告编写任务列表失败: %v", err)
  815. return
  816. }
  817. // 请求数据采集类型的数据
  818. collectionRes, err := GetTaskList(start_time, end_time, "collection")
  819. if err != nil {
  820. logs.Error("请求数据采集任务列表失败: %v", err)
  821. return
  822. }
  823. // 初始化绩效目标
  824. Performance.Read_PerformanceTarget_All_Map()
  825. userList, _ := NatsServer.Read_User_List_All()
  826. Account.Read_User_All_Map(userList)
  827. // 处理报告编写人员统计
  828. reportingStat := processWorkloadStats(reportingRes, "reporting")
  829. // 处理数据采集人员统计
  830. collectionStat := processWorkloadStats(collectionRes, "collection")
  831. // 保存统计结果到数据库
  832. saveReportingStatsToDB(reportingStat, "reporting")
  833. saveCollectionStatsToDB(collectionStat, "collection")
  834. }
  835. // updateWorkloadStat 更新工作量统计的辅助函数
  836. func updateWorkloadStat(stat map[string]map[int]int, userUUID string, pointID int) {
  837. // 如果UUID为空则跳过
  838. if userUUID == "" {
  839. return
  840. }
  841. // 初始化用户映射表
  842. if stat[userUUID] == nil {
  843. stat[userUUID] = make(map[int]int)
  844. }
  845. // 增加工作量计数
  846. stat[userUUID][pointID]++
  847. }
  848. // saveReportingStatsToDB 保存报告编写人员统计结果到数据库
  849. func saveReportingStatsToDB(stat map[string]map[int]int, workType string) {
  850. s := services.Performance{}
  851. // 获取当前日期(用于T_date字段)
  852. currentDate := time.Now().Format("2006-01")
  853. // 遍历统计结果并保存到数据库
  854. for userUUID, points := range stat {
  855. // 计算总工作量
  856. totalWorkload := 0.0
  857. totalPoints := 0 // 总绩效点
  858. // 收集所有绩效点信息用于创建PerfPoint列表
  859. var pointList []Performance.PerfPoint
  860. for pointID, count := range points {
  861. // 获取绩效点信息以计算工作量
  862. pointsInfo := getPerformancePointsInfo(pointID)
  863. if pointsInfo.Id > 0 {
  864. // 计算工作量:T_points_numerator/T_points_denominator*统计出来的工作量
  865. workload := float64(pointsInfo.T_points_numerator) / float64(pointsInfo.T_points_denominator) * float64(count)
  866. totalWorkload += workload
  867. // 累计总绩效点和总数量
  868. totalPoints += pointsInfo.T_points_numerator
  869. // 创建绩效点记录
  870. point := Performance.PerfPoint{
  871. T_performance_points_id: pointID,
  872. T_quantity: count,
  873. T_points_numerator: pointsInfo.T_points_numerator,
  874. T_points_denominator: pointsInfo.T_points_denominator,
  875. T_type: workType,
  876. }
  877. pointList = append(pointList, point)
  878. }
  879. }
  880. User := Account.Read_User_Get(userUUID)
  881. target := Performance.Read_PerformanceTarget_Get(User.T_verify_perf_target)
  882. // 创建Perf记录
  883. perf := Performance.Perf{
  884. T_date: currentDate,
  885. T_submit: userUUID,
  886. T_workload: totalWorkload,
  887. T_audit: 1, // 待提交状态
  888. T_State: 1, // 正常状态
  889. T_assess_points: target.T_assess_points, // 考核绩效点
  890. T_perf: target.T_perf, // 考核绩效点
  891. T_performance_target_id: target.Id, // 考核绩效点
  892. }
  893. // 保存到数据库
  894. _, err := s.InsertFromStats(&perf, pointList)
  895. if err != nil {
  896. logs.Error("保存报告编写人员统计结果失败: %v", err)
  897. } else {
  898. logs.Info("成功保存报告编写人员 %s 的统计结果", userUUID)
  899. }
  900. }
  901. }
  902. // saveCollectionStatsToDB 保存数据采集人员统计结果到数据库
  903. func saveCollectionStatsToDB(stat map[string]map[int]int, workType string) {
  904. s := services.Performance{}
  905. // 获取当前日期(用于T_date字段)
  906. currentDate := time.Now().AddDate(0, -1, 0).Format("2006-01")
  907. // 遍历统计结果并保存到数据库
  908. for userUUID, points := range stat {
  909. // 计算总工作量
  910. totalWorkload := 0.0
  911. totalPoints := 0 // 总绩效点
  912. totalCount := 0 // 总数量
  913. // 收集所有绩效点信息用于创建PerfPoint列表
  914. var pointList []Performance.PerfPoint
  915. for pointID, count := range points {
  916. // 获取绩效点信息以计算工作量
  917. pointsInfo := getPerformancePointsInfo(pointID)
  918. if pointsInfo.Id > 0 {
  919. // 计算工作量:T_points_numerator/T_points_denominator*统计出来的工作量
  920. workload := float64(pointsInfo.T_points_numerator) / float64(pointsInfo.T_points_denominator) * float64(count)
  921. totalWorkload += workload
  922. // 累计总绩效点和总数量
  923. totalPoints += pointsInfo.T_points_numerator
  924. totalCount += count
  925. // 创建绩效点记录
  926. point := Performance.PerfPoint{
  927. T_performance_points_id: pointID,
  928. T_quantity: count,
  929. T_points_numerator: pointsInfo.T_points_numerator,
  930. T_points_denominator: pointsInfo.T_points_denominator,
  931. T_type: workType,
  932. }
  933. pointList = append(pointList, point)
  934. }
  935. }
  936. User := Account.Read_User_Get(userUUID)
  937. target := Performance.Read_PerformanceTarget_Get(User.T_verify_perf_target)
  938. // 创建Perf记录
  939. perf := Performance.Perf{
  940. T_date: currentDate,
  941. T_submit: userUUID,
  942. T_workload: totalWorkload,
  943. T_audit: 1, // 待提交状态
  944. T_State: 1, // 正常状态
  945. T_assess_points: target.T_assess_points, // 考核绩效点
  946. T_perf: target.T_perf, // 考核绩效
  947. T_performance_target_id: target.Id, // 工资级别id
  948. }
  949. // 保存到数据库
  950. _, err := s.InsertFromStats(&perf, pointList)
  951. if err != nil {
  952. logs.Error("保存数据采集人员统计结果失败: %v", err)
  953. } else {
  954. logs.Info(fmt.Sprintf("成功保存数据采集人员 %s 的统计结果", userUUID))
  955. }
  956. }
  957. }
  958. // getPerformancePointsInfo 获取绩效点信息
  959. func getPerformancePointsInfo(pointID int) Performance.PerformancePoints {
  960. s := services.PerformancePoints{}
  961. points, err := s.Get(pointID)
  962. if err != nil {
  963. logs.Error("获取绩效点信息失败: %v", err)
  964. return Performance.PerformancePoints{}
  965. }
  966. return points
  967. }
  968. func GetPerformancePointsMap() map[string]Performance.PerformancePoints {
  969. s := services.PerformancePoints{}
  970. reqData := dto.PerformancePointsPageReq{}
  971. reqData.PageSize = 9999
  972. performancePointsList, _ := s.GetPage(&reqData)
  973. var pointsMap = make(map[string]Performance.PerformancePoints) // 实施
  974. for _, item := range performancePointsList {
  975. pointsMap[item.T_name] = item
  976. }
  977. return pointsMap
  978. }
  979. func GetColdVerifyUUIDMap() (uuidMap map[string]string) {
  980. uuidMap = make(map[string]string)
  981. userList, _ := NatsServer.Read_User_List_All()
  982. for _, user := range userList {
  983. uuidMap[user.T_verify_cold_uuid] = user.T_uuid
  984. }
  985. return uuidMap
  986. }
  987. // 获取实施提成金额
  988. func GetPerformancePoints(T_device_type, T_verify_type string, pointsMap map[string]Performance.PerformancePoints) (money Performance.PerformancePoints) {
  989. if strings.Contains(T_device_type, "箱") {
  990. return pointsMap["箱"]
  991. }
  992. if strings.Contains(T_device_type, "车") {
  993. if strings.Contains(T_verify_type, "空载") {
  994. return pointsMap["车(空载)"]
  995. } else {
  996. return pointsMap["车(满载)"]
  997. }
  998. }
  999. if strings.Contains(T_device_type, "柜") {
  1000. if strings.Contains(T_verify_type, "空载") {
  1001. return pointsMap["库(空载)"]
  1002. } else {
  1003. return pointsMap["库(满载)"]
  1004. }
  1005. }
  1006. if strings.Contains(T_device_type, "库") {
  1007. if strings.Contains(T_verify_type, "空载") {
  1008. return pointsMap["库(空载)"]
  1009. } else {
  1010. return pointsMap["库(满载)"]
  1011. }
  1012. }
  1013. if strings.Contains(T_device_type, "系统") {
  1014. return pointsMap["系统"]
  1015. }
  1016. if strings.Contains(T_device_type, "位置") {
  1017. return pointsMap["位置"]
  1018. }
  1019. if strings.Contains(T_device_type, "巡检") {
  1020. return pointsMap["巡检"]
  1021. }
  1022. if strings.Contains(T_device_type, "培训") {
  1023. return pointsMap["培训"]
  1024. }
  1025. return Performance.PerformancePoints{}
  1026. }