课程运行.go 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250
  1. package controllers
  2. import (
  3. // 根据实际项目结构调整导入路径
  4. "Tech/common"
  5. "Tech/models"
  6. "bytes"
  7. "encoding/json"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "strings"
  12. "time"
  13. "github.com/beego/beego/v2/client/orm"
  14. beego "github.com/beego/beego/v2/server/web"
  15. // 新增导入
  16. )
  17. var (
  18. dtLastPauseTime time.Time // 全局变量记录上次暂停时间
  19. )
  20. type CourseRunController struct {
  21. beego.Controller
  22. }
  23. func (c *CourseRunController) CourseRun() {
  24. type Request struct {
  25. CourseID int `json:"courseID"`
  26. TraineeGUID string `json:"traineeGUID"`
  27. TrainingImplementationID string `json:"trainingImplementationID"`
  28. TrainingPlanID string `json:"trainingPlanID"`
  29. TrainingPlanName string `json:"trainingPlanName"`
  30. }
  31. var req Request
  32. requestBody := c.Ctx.Input.RequestBody
  33. println("Request Body:", string(requestBody))
  34. if err := json.Unmarshal(requestBody, &req); err != nil {
  35. c.Ctx.Output.SetStatus(400)
  36. c.Data["json"] = map[string]interface{}{
  37. "code": 400,
  38. "msg": "请求参数格式错误: " + err.Error(),
  39. }
  40. c.ServeJSON()
  41. return
  42. }
  43. if req.CourseID == 0 {
  44. c.Ctx.Output.SetStatus(400)
  45. c.Data["json"] = map[string]interface{}{
  46. "code": 400,
  47. "msg": "缺少课程ID参数",
  48. }
  49. c.ServeJSON()
  50. return
  51. }
  52. o := orm.NewOrm()
  53. // 查询是否存在正在运行的课程(课程用时为0表示正在运行)
  54. var runningCourse models.CourseRunLog
  55. err := o.QueryTable(new(models.CourseRunLog)).
  56. Filter("CourseTime", 0).
  57. OrderBy("-RunLogID").
  58. One(&runningCourse)
  59. if err == nil {
  60. // 存在正在运行的课程
  61. c.Data["json"] = map[string]interface{}{
  62. "code": 500,
  63. "msg": "有课程正在运行中,无法开始新课程",
  64. }
  65. c.ServeJSON()
  66. return
  67. } else if err != orm.ErrNoRows {
  68. // 查询出错
  69. c.Data["json"] = map[string]interface{}{
  70. "code": 500,
  71. "msg": "查询运行课程状态失败: " + err.Error(),
  72. }
  73. c.ServeJSON()
  74. return
  75. }
  76. // 查询课程信息
  77. var course models.CourseInfo
  78. err = o.QueryTable(new(models.CourseInfo)).
  79. Filter("CourseID", req.CourseID).
  80. One(&course)
  81. if err != nil {
  82. c.Data["json"] = map[string]interface{}{
  83. "code": 500,
  84. "msg": "查询课程信息失败: " + err.Error(),
  85. }
  86. c.ServeJSON()
  87. return
  88. }
  89. // 获取最大的课程运行ID号,然后ID号加1
  90. var maxRunLogID int
  91. err = o.Raw("SELECT COALESCE(MAX(运行记录编号), 0) FROM CourseRunLog").QueryRow(&maxRunLogID)
  92. if err != nil {
  93. c.Data["json"] = map[string]interface{}{
  94. "code": 500,
  95. "msg": "查询最大运行日志ID失败: " + err.Error(),
  96. }
  97. c.ServeJSON()
  98. return
  99. }
  100. nextRunLogID := maxRunLogID + 1
  101. // 从用户信息缓存中通过TraineeGUID查询TraineeName
  102. traineeName := ""
  103. if req.TraineeGUID != "" {
  104. // 从缓存中获取用户信息
  105. userInfo, exists := GetUserInfoFromCache_RYEMPID(req.TraineeGUID)
  106. if exists {
  107. traineeName = userInfo.XM
  108. }
  109. }
  110. // 生成唯一的TrainingRecordGUID,使用时间戳+随机数确保唯一性
  111. trainingRecordGUID := fmt.Sprintf("%s-%d", time.Now().Format("20060102150405"), time.Now().UnixNano()%1000000)
  112. // 创建新的课程运行记录
  113. newRunLog := models.CourseRunLog{
  114. RunLogID: nextRunLogID, // 使用计算出的ID
  115. RunCourseID: req.CourseID,
  116. RunCourseName: course.CourseName,
  117. RunDateTime: time.Now().Format("2006-01-02 15:04:05"),
  118. CourseTime: 0, // 初始为0,表示正在运行
  119. CourseScore: 0,
  120. TraineeGUID: req.TraineeGUID,
  121. TraineeName: traineeName,
  122. TrainingRecordGUID: trainingRecordGUID,
  123. TrainingImplementationID: req.TrainingImplementationID,
  124. TrainingPlanID: req.TrainingPlanID,
  125. }
  126. // 插入课程运行记录
  127. id, err := o.Insert(&newRunLog)
  128. if err != nil {
  129. c.Data["json"] = map[string]interface{}{
  130. "code": 500,
  131. "msg": "创建课程运行记录失败: " + err.Error(),
  132. }
  133. c.ServeJSON()
  134. return
  135. }
  136. if req.TrainingImplementationID != "" && req.TrainingPlanID != "" && CurrentLoginMode == 0 {
  137. // 通知信息化系统开始培训
  138. err = common.NotifyTMSStartTraining(int(id), course, req.TraineeGUID, req.TrainingImplementationID, req.TrainingPlanID, "")
  139. if err != nil {
  140. // 如果通知信息化系统失败,删除刚刚创建的课程运行记录
  141. o.Delete(&newRunLog)
  142. c.Data["json"] = map[string]interface{}{
  143. "code": 500,
  144. "msg": "通知信息化系统开始培训失败: " + err.Error(),
  145. }
  146. c.ServeJSON()
  147. return
  148. }
  149. }
  150. // 通知电调开课
  151. isret, err := c.tellEStartCourse(req.CourseID, int(id), course.LineNo)
  152. if !isret || err != nil {
  153. // 如果通知电调开课失败,删除刚刚创建的课程运行记录
  154. o.Delete(&newRunLog)
  155. // 错误信息已经在 tellEStartCourse 中设置
  156. c.ServeJSON()
  157. return
  158. }
  159. // 开课成功则继续后续操作
  160. // 根据课程评价列表生成评价日志记录
  161. var evaList []*models.CourseEvaList
  162. _, err = o.QueryTable(new(models.CourseEvaList)).
  163. Filter("CourseID", req.CourseID).
  164. OrderBy("SeqNo").
  165. All(&evaList)
  166. if err != nil {
  167. c.Data["json"] = map[string]interface{}{
  168. "code": 500,
  169. "msg": "查询课程评价列表失败: " + err.Error(),
  170. }
  171. c.ServeJSON()
  172. return
  173. }
  174. // 为每个评价项创建评价日志记录
  175. for _, eva := range evaList {
  176. evaLog := models.CourseEvaLog{
  177. RunLogID: int(id), // 使用运行记录ID作为关联标识
  178. RunCourseID: req.CourseID,
  179. RunOperID: eva.SeqNo, // 使用评价序号作为操作ID
  180. OperTime: 0, // 初始化时间为0
  181. OperScore: 0, // 初始化得分为0
  182. SeqNo: eva.SeqNo,
  183. EvaTargetRole: eva.EvaTargetRole,
  184. EvaName: eva.EvaName,
  185. EvaMapID: eva.EvaMapID,
  186. EvaType: eva.EvaType,
  187. EvaSource: eva.EvaSource,
  188. EvaScore: eva.EvaScore,
  189. EvaDeduction: eva.EvaDeduction,
  190. DisqualificationItem: eva.DisqualificationItem,
  191. IsOperated: 0, // 节点是否操作 0 未操作 1 已操作
  192. }
  193. _, err = o.Insert(&evaLog)
  194. if err != nil {
  195. c.Data["json"] = map[string]interface{}{
  196. "code": 500,
  197. "msg": "创建课程评价日志失败: " + err.Error(),
  198. }
  199. c.ServeJSON()
  200. return
  201. }
  202. }
  203. // 成功返回记录ID
  204. c.Data["json"] = map[string]interface{}{
  205. "code": 200,
  206. "msg": "课程开始运行",
  207. "data": map[string]interface{}{
  208. "runLogID": id,
  209. "TrainingPlanName": req.TrainingPlanName,
  210. },
  211. }
  212. c.ServeJSON()
  213. }
  214. // / 通知电调服务课程开始
  215. func (c *CourseRunController) tellEStartCourse(courseID int, runLogID int, lineNo int) (bool, error) {
  216. // 从配置文件读取电调服务IP和端口
  217. electricalIP, err := beego.AppConfig.String("ElectricalIP")
  218. if err != nil {
  219. c.Data["json"] = map[string]interface{}{
  220. "code": 500,
  221. "msg": "读取电调服务IP配置失败: " + err.Error(),
  222. }
  223. c.ServeJSON()
  224. return false, err
  225. }
  226. electricalPort, err := beego.AppConfig.Int("ElectricalPort")
  227. if err != nil {
  228. c.Data["json"] = map[string]interface{}{
  229. "code": 500,
  230. "msg": "读取电调服务端口配置失败: " + err.Error(),
  231. }
  232. c.ServeJSON()
  233. return false, err
  234. }
  235. // 构造电调服务地址
  236. electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/Run", electricalIP, electricalPort)
  237. // 准备请求数据
  238. type CourseStartReq struct {
  239. CourseID int `json:"CourseID"`
  240. CourseRunID int `json:"CourseRunID"`
  241. LineNo int `json:"LineID"`
  242. SubParam1 string `json:"subParam1"`
  243. SubParam2 string `json:"subParam2"`
  244. }
  245. startReq := CourseStartReq{
  246. CourseID: courseID,
  247. CourseRunID: runLogID,
  248. LineNo: lineNo,
  249. SubParam1: "",
  250. SubParam2: "",
  251. }
  252. reqBody, err := json.Marshal(startReq)
  253. if err != nil {
  254. c.Data["json"] = map[string]interface{}{
  255. "code": 500,
  256. "msg": "构造通知电调服务请求体失败: " + err.Error(),
  257. }
  258. c.ServeJSON()
  259. return false, err
  260. }
  261. // 调用电调服务CourseStart接口
  262. resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(reqBody))
  263. if err != nil {
  264. c.Data["json"] = map[string]interface{}{
  265. "code": 500,
  266. "msg": "调用电调服务开课接口失败: " + err.Error(),
  267. }
  268. c.ServeJSON()
  269. return false, err
  270. }
  271. defer resp.Body.Close()
  272. // 检查响应状态
  273. if resp.StatusCode != http.StatusOK {
  274. bodyBytes, _ := io.ReadAll(resp.Body)
  275. c.Data["json"] = map[string]interface{}{
  276. "code": 500,
  277. "msg": fmt.Sprintf("电调服务返回异常状态码: %d,响应内容: %s", resp.StatusCode, string(bodyBytes)),
  278. }
  279. c.ServeJSON()
  280. return false, fmt.Errorf("电调服务返回异常状态码: %d", resp.StatusCode)
  281. }
  282. // 读取响应体(可根据实际需求解析响应内容)
  283. _, _ = io.ReadAll(resp.Body)
  284. return true, nil
  285. }
  286. // / 通知电调服务课程结束
  287. func (c *CourseRunController) tellEStopCourse(courseID int, runLogID int) (bool, error) {
  288. // 从配置文件读取电调服务IP和端口
  289. electricalIP, err := beego.AppConfig.String("ElectricalIP")
  290. if err != nil {
  291. c.Data["json"] = map[string]interface{}{
  292. "code": 500,
  293. "msg": "读取电调服务IP配置失败: " + err.Error(),
  294. }
  295. c.ServeJSON()
  296. return false, err
  297. }
  298. electricalPort, err := beego.AppConfig.Int("ElectricalPort")
  299. if err != nil {
  300. c.Data["json"] = map[string]interface{}{
  301. "code": 500,
  302. "msg": "读取电调服务端口配置失败: " + err.Error(),
  303. }
  304. c.ServeJSON()
  305. return false, err
  306. }
  307. // 构造电调服务地址
  308. electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/Stop", electricalIP, electricalPort)
  309. // 准备请求数据
  310. type CourseStopReq struct {
  311. CourseID int `json:"CourseID"`
  312. CourseRunID int `json:"CourseRunID"`
  313. CtrlStatus int `json:"CtrlStatus"`
  314. }
  315. stopReq := CourseStopReq{
  316. CourseID: courseID,
  317. CourseRunID: runLogID,
  318. CtrlStatus: 0,
  319. }
  320. reqBody, err := json.Marshal(stopReq)
  321. if err != nil {
  322. c.Data["json"] = map[string]interface{}{
  323. "code": 500,
  324. "msg": "构造通知电调服务请求体失败: " + err.Error(),
  325. }
  326. c.ServeJSON()
  327. return false, err
  328. }
  329. // 调用电调服务CourseStop接口
  330. resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(reqBody))
  331. if err != nil {
  332. c.Data["json"] = map[string]interface{}{
  333. "code": 500,
  334. "msg": "调用电调服务停课接口失败: " + err.Error(),
  335. }
  336. c.ServeJSON()
  337. return false, err
  338. }
  339. defer resp.Body.Close()
  340. // 检查响应状态
  341. if resp.StatusCode != http.StatusOK {
  342. bodyBytes, _ := io.ReadAll(resp.Body)
  343. c.Data["json"] = map[string]interface{}{
  344. "code": 500,
  345. "msg": fmt.Sprintf("电调服务返回异常状态码: %d,响应内容: %s", resp.StatusCode, string(bodyBytes)),
  346. }
  347. c.ServeJSON()
  348. return false, fmt.Errorf("电调服务返回异常状态码: %d", resp.StatusCode)
  349. }
  350. // 读取响应体(可根据实际需求解析响应内容)
  351. _, _ = io.ReadAll(resp.Body)
  352. return true, nil
  353. }
  354. func (c *CourseRunController) CoursePause() {
  355. type Request struct {
  356. SetFlag int `json:"setFlag"` // 1表示暂停,2表示恢复
  357. }
  358. var req Request
  359. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
  360. c.Ctx.Output.SetStatus(400)
  361. c.Data["json"] = map[string]interface{}{
  362. "code": 400,
  363. "msg": "请求参数格式错误: " + err.Error(),
  364. }
  365. c.ServeJSON()
  366. return
  367. }
  368. if req.SetFlag != 1 && req.SetFlag != 2 {
  369. c.Ctx.Output.SetStatus(400)
  370. c.Data["json"] = map[string]interface{}{
  371. "code": 400,
  372. "msg": "参数值错误,SetFlag应为1或2",
  373. }
  374. c.ServeJSON()
  375. return
  376. }
  377. o := orm.NewOrm()
  378. // 查询正在进行的课程(课程用时为0表示正在运行)
  379. var runningCourse models.CourseRunLog
  380. err := o.QueryTable(new(models.CourseRunLog)).
  381. Filter("CourseTime", 0).
  382. OrderBy("-RunLogID").
  383. One(&runningCourse)
  384. if err != nil {
  385. if err == orm.ErrNoRows {
  386. c.Data["json"] = map[string]interface{}{
  387. "code": 500,
  388. "msg": "没有正在运行的课程",
  389. }
  390. c.ServeJSON()
  391. return
  392. }
  393. c.Data["json"] = map[string]interface{}{
  394. "code": 500,
  395. "msg": "查询运行课程状态失败: " + err.Error(),
  396. }
  397. c.ServeJSON()
  398. return
  399. }
  400. switch req.SetFlag {
  401. case 1: // 暂停课程
  402. if runningCourse.PauseFlag == 1 {
  403. c.Data["json"] = map[string]interface{}{
  404. "code": 500,
  405. "msg": "课程已在暂停状态",
  406. }
  407. c.ServeJSON()
  408. return
  409. }
  410. // 设置暂停标记并记录暂停开始时间
  411. runningCourse.PauseFlag = 1
  412. dtLastPauseTime = time.Now()
  413. case 2: // 恢复课程
  414. if runningCourse.PauseFlag != 1 {
  415. c.Data["json"] = map[string]interface{}{
  416. "code": 500,
  417. "msg": "课程未处于暂停状态",
  418. }
  419. c.ServeJSON()
  420. return
  421. }
  422. // 如果有暂停开始时间,则计算暂停时长并累加到总暂停时长
  423. if !dtLastPauseTime.IsZero() {
  424. pauseDuration := int(time.Since(dtLastPauseTime).Seconds())
  425. if pauseDuration > 0 {
  426. runningCourse.PauseTotalTime += pauseDuration
  427. }
  428. // 清除暂停开始时间
  429. dtLastPauseTime = time.Time{}
  430. }
  431. // 清除暂停标记
  432. runningCourse.PauseFlag = 0
  433. }
  434. // 更新课程运行记录,修改PauseFlag和PauseTotalTime字段
  435. _, err = o.Update(&runningCourse, "PauseFlag", "PauseTotalTime")
  436. if err != nil {
  437. c.Data["json"] = map[string]interface{}{
  438. "code": 500,
  439. "msg": "更新课程暂停状态失败: " + err.Error(),
  440. }
  441. c.ServeJSON()
  442. return
  443. }
  444. var msg string
  445. if req.SetFlag == 1 {
  446. msg = "课程已暂停"
  447. } else {
  448. msg = "课程已恢复"
  449. }
  450. c.Data["json"] = map[string]interface{}{
  451. "code": 200,
  452. "msg": msg,
  453. "data": runningCourse, // 返回完整的CourseRunLog数据
  454. }
  455. c.ServeJSON()
  456. }
  457. // /course/stop 停止课程运行
  458. func (c *CourseRunController) CourseStop() {
  459. o := orm.NewOrm()
  460. // 查询最新的课程运行记录
  461. var latestCourse models.CourseRunLog
  462. err := o.QueryTable(new(models.CourseRunLog)).
  463. OrderBy("-RunLogID").
  464. One(&latestCourse)
  465. if err != nil {
  466. if err == orm.ErrNoRows {
  467. c.Data["json"] = map[string]interface{}{
  468. "code": 500,
  469. "msg": "没有找到任何课程运行记录",
  470. }
  471. c.ServeJSON()
  472. return
  473. }
  474. c.Data["json"] = map[string]interface{}{
  475. "code": 500,
  476. "msg": "查询课程运行记录失败: " + err.Error(),
  477. }
  478. c.ServeJSON()
  479. return
  480. }
  481. // 检查课程是否已经结束
  482. if latestCourse.CourseTime > 0 {
  483. c.Data["json"] = map[string]interface{}{
  484. "code": 500,
  485. "msg": "课程已经结束,无法再次结束",
  486. }
  487. c.ServeJSON()
  488. return
  489. }
  490. // 计算课程用时(从开始时间到当前时间的秒数)
  491. startTime, err := time.ParseInLocation("2006-01-02 15:04:05", latestCourse.RunDateTime, time.Local)
  492. if err != nil {
  493. c.Data["json"] = map[string]interface{}{
  494. "code": 500,
  495. "msg": "解析课程开始时间失败: " + err.Error(),
  496. "runStatus": 0,
  497. "data": nil,
  498. }
  499. c.ServeJSON()
  500. return
  501. }
  502. courseDuration := int(time.Since(startTime).Seconds())
  503. // 更新课程记录
  504. latestCourse.CourseTime = courseDuration
  505. latestCourse.PauseFlag = -1
  506. latestCourse.FinishDateTime = time.Now().Format("2006-01-02 15:04:05")
  507. _, err = o.Update(&latestCourse, "CourseTime", "PauseFlag", "FinishDateTime")
  508. if err != nil {
  509. c.Data["json"] = map[string]interface{}{
  510. "code": 500,
  511. "msg": "更新课程运行记录失败: " + err.Error(),
  512. }
  513. c.ServeJSON()
  514. return
  515. }
  516. c.Data["json"] = map[string]interface{}{
  517. "code": 200,
  518. "msg": "课程运行已停止",
  519. "data": map[string]interface{}{
  520. "runLogID": latestCourse.RunLogID,
  521. "courseID": latestCourse.RunCourseID,
  522. "duration": courseDuration,
  523. "startTime": latestCourse.RunDateTime,
  524. },
  525. }
  526. // 通知电调服务课程结束
  527. _, err = c.tellEStopCourse(latestCourse.RunCourseID, latestCourse.RunLogID)
  528. if err != nil {
  529. fmt.Println("通知电调服务停止课程失败: " + err.Error())
  530. // c.Data["json"] = map[string]interface{}{
  531. // "code": 500,
  532. // "msg": "通知电调服务停止课程失败: " + err.Error(),
  533. // }
  534. // c.ServeJSON()
  535. // return
  536. }
  537. if CurrentLoginMode == 0 {
  538. // 通知信息化系统结束培训
  539. err = common.NotifyTMSStopTraining(latestCourse.TrainingRecordGUID)
  540. if err != nil {
  541. // 记录错误日志,但不中断操作
  542. fmt.Println("通知信息化系统结束培训失败: " + err.Error())
  543. }
  544. err = DoUploadTMS(latestCourse.RunLogID)
  545. if err != nil {
  546. fmt.Println("上传电子考评表失败: " + err.Error())
  547. }
  548. }
  549. c.ServeJSON()
  550. }
  551. // /course/status 查询课程运行状态
  552. func (c *CourseRunController) CourseStatus() {
  553. o := orm.NewOrm()
  554. // 查询最新的课程运行记录
  555. var latestCourse models.CourseRunLog
  556. err := o.QueryTable(new(models.CourseRunLog)).
  557. OrderBy("-RunLogID").
  558. One(&latestCourse)
  559. if err != nil {
  560. if err == orm.ErrNoRows {
  561. // 没有课程运行记录
  562. c.Data["json"] = map[string]interface{}{
  563. "code": 200,
  564. "msg": "成功",
  565. "data": map[string]interface{}{
  566. "runStatus": 0, // 0表示无记录/未运行
  567. },
  568. }
  569. c.ServeJSON()
  570. return
  571. }
  572. c.Data["json"] = map[string]interface{}{
  573. "code": 500,
  574. "msg": "查询课程运行记录失败: " + err.Error(),
  575. "data": map[string]interface{}{
  576. "runStatus": 0,
  577. },
  578. }
  579. c.ServeJSON()
  580. return
  581. }
  582. // 判断课程是否结束
  583. if latestCourse.CourseTime > 0 {
  584. // 课程已结束,返回空data
  585. c.Data["json"] = map[string]interface{}{
  586. "code": 200,
  587. "msg": "成功",
  588. "data": map[string]interface{}{
  589. "runStatus": 0, // 0表示未运行(课程已结束)
  590. },
  591. }
  592. } else {
  593. // 课程正在进行中,计算运行时间并返回详细信息
  594. startTime, err := time.ParseInLocation("2006-01-02 15:04:05", latestCourse.RunDateTime, time.Local)
  595. if err != nil {
  596. c.Data["json"] = map[string]interface{}{
  597. "code": 500,
  598. "msg": "解析课程开始时间失败: " + err.Error(),
  599. "data": map[string]interface{}{
  600. "runStatus": 0,
  601. },
  602. }
  603. c.ServeJSON()
  604. return
  605. }
  606. // 获取当前时间
  607. now := time.Now()
  608. fmt.Printf("目标时间: %v\n", startTime)
  609. fmt.Printf("当前时间: %v\n", now)
  610. // 计算时间差(秒)
  611. diff := int(now.Sub(startTime).Seconds())
  612. // 确定运行状态
  613. runStatus := 1 // 默认为正在运行
  614. if latestCourse.PauseFlag == 1 {
  615. runStatus = 2 // 2表示暂停中
  616. }
  617. // 计算calTime为开始时间加上暂停时间后的格式化时间
  618. calTime := startTime.Add(time.Duration(latestCourse.PauseTotalTime) * time.Second).Format("2006-01-02 15:04:05")
  619. // 课程正在进行中,返回详细信息
  620. c.Data["json"] = map[string]interface{}{
  621. "code": 200,
  622. "msg": "成功",
  623. "data": map[string]interface{}{
  624. "runLogID": latestCourse.RunLogID,
  625. "runCourseID": latestCourse.RunCourseID,
  626. "runCourseName": latestCourse.RunCourseName,
  627. "runDateTime": latestCourse.RunDateTime,
  628. "courseTime": diff, // 实时计算的运行时间
  629. "courseScore": latestCourse.CourseScore,
  630. "pauseFlag": latestCourse.PauseFlag,
  631. "pauseTotalTime": latestCourse.PauseTotalTime,
  632. "calTime": calTime, // 开始时间+暂停时间后的时间
  633. "runStatus": runStatus, // 0表示未运行,1表示正在运行,2表示暂停中
  634. },
  635. }
  636. }
  637. c.ServeJSON()
  638. }
  639. // /runrecord/listone 获取课程运行记录数据
  640. func (c *CourseRunController) RunRecordListOne() {
  641. // 定义请求参数结构体
  642. type Request struct {
  643. RunLogID int `json:"runLogID"`
  644. }
  645. var req Request
  646. // 解析请求参数
  647. if len(c.Ctx.Input.RequestBody) > 0 {
  648. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
  649. c.Ctx.Output.SetStatus(400)
  650. c.Data["json"] = map[string]interface{}{
  651. "code": 400,
  652. "msg": "请求参数格式错误: " + err.Error(),
  653. }
  654. c.ServeJSON()
  655. return
  656. }
  657. }
  658. o := orm.NewOrm()
  659. var runRecords []models.CourseRunLog
  660. var err error
  661. // 如果RunLogID > 0,则查询对应运行记录ID的记录
  662. // 如果RunLogID = 0 或者没有传参,则查询最新一条记录
  663. if req.RunLogID > 0 {
  664. // 查询指定RunLogID的运行记录
  665. var record models.CourseRunLog
  666. err = o.QueryTable(new(models.CourseRunLog)).Filter("RunLogID", req.RunLogID).One(&record)
  667. if err != nil && err != orm.ErrNoRows {
  668. c.Data["json"] = map[string]interface{}{
  669. "code": 500,
  670. "msg": "查询课程运行记录失败: " + err.Error(),
  671. }
  672. c.ServeJSON()
  673. return
  674. }
  675. // 如果找到了记录,则添加到数组中
  676. if err != orm.ErrNoRows {
  677. runRecords = append(runRecords, record)
  678. }
  679. } else {
  680. // 查询最新一条运行记录
  681. var latestRecord models.CourseRunLog
  682. err = o.QueryTable(new(models.CourseRunLog)).OrderBy("-RunLogID").One(&latestRecord)
  683. if err != nil && err != orm.ErrNoRows {
  684. c.Data["json"] = map[string]interface{}{
  685. "code": 500,
  686. "msg": "查询课程运行记录失败: " + err.Error(),
  687. }
  688. c.ServeJSON()
  689. return
  690. }
  691. // 如果找到了记录,则添加到数组中
  692. if err != orm.ErrNoRows {
  693. runRecords = append(runRecords, latestRecord)
  694. }
  695. }
  696. //判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
  697. // 构建结果
  698. type RunRecordDetail struct {
  699. RunLogID int `json:"runLogID"`
  700. RunCourseID int `json:"runCourseID"`
  701. RunCourseName string `json:"runCourseName"`
  702. RunDateTime string `json:"runDateTime"`
  703. CourseTime int `json:"courseTime"`
  704. CourseScore float64 `json:"courseScore"`
  705. PauseFlag int `json:"pauseFlag"` //1:已经暂停,1运行中,-1课程结束
  706. PauseTotalTime int `json:"pauseTotalTime"`
  707. RunStatus int `json:"runStatus"` // 0表示未运行,1表示正在运行,2表示暂停中
  708. }
  709. var results []RunRecordDetail
  710. // 遍历运行记录并获取课程详细信息及应用筛选
  711. for _, record := range runRecords {
  712. // 查询对应的课程信息
  713. var courseInfo models.CourseInfo
  714. err = o.QueryTable(new(models.CourseInfo)).Filter("CourseID", record.RunCourseID).One(&courseInfo)
  715. if err != nil && err != orm.ErrNoRows {
  716. c.Data["json"] = map[string]interface{}{
  717. "code": 500,
  718. "msg": "查询课程信息失败: " + err.Error(),
  719. }
  720. c.ServeJSON()
  721. return
  722. }
  723. // 判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
  724. if record.PauseFlag != -1 {
  725. // 课程未结束,重新计算运行时间
  726. // 将字符串转换为时间
  727. startTime, err := time.ParseInLocation("2006-01-02 15:04:05", record.RunDateTime, time.Local)
  728. if err == nil {
  729. // 计算从开始时间到当前时间的时间差(秒)
  730. duration := time.Since(startTime).Seconds()
  731. // 减去暂停的总时间得到实际运行时间
  732. record.CourseTime = int(duration) - record.PauseTotalTime
  733. if record.CourseTime < 0 {
  734. record.CourseTime = 0
  735. }
  736. }
  737. }
  738. detail := RunRecordDetail{
  739. RunLogID: record.RunLogID,
  740. RunCourseID: record.RunCourseID,
  741. RunCourseName: record.RunCourseName,
  742. RunDateTime: record.RunDateTime,
  743. CourseTime: record.CourseTime,
  744. CourseScore: record.CourseScore,
  745. PauseFlag: record.PauseFlag,
  746. PauseTotalTime: record.PauseTotalTime,
  747. RunStatus: func() int {
  748. // 根据PauseFlag确定运行状态
  749. if record.PauseFlag == 1 {
  750. return 2 // 暂停中(默认情况)
  751. } else if record.PauseFlag == -1 {
  752. return 0 // 课程结束(未运行)
  753. } else {
  754. return 1
  755. }
  756. }(),
  757. }
  758. results = append(results, detail)
  759. }
  760. c.Data["json"] = map[string]interface{}{
  761. "code": 200,
  762. "msg": "查询成功",
  763. "count": len(results),
  764. "data": results,
  765. }
  766. c.ServeJSON()
  767. }
  768. // /runrecord/list 获取课程运行记录数据列表
  769. func (c *CourseRunController) RunRecordList() {
  770. // 定义请求参数结构体
  771. type Request struct {
  772. CourseName string `json:"courseName"`
  773. TypeID int `json:"typeID"`
  774. CourseID int `json:"courseID"`
  775. LineNo int `json:"lineNo"`
  776. Creator string `json:"creator"`
  777. StartTime string `json:"startTime"`
  778. EndTime string `json:"endTime"`
  779. }
  780. var req Request
  781. // 解析请求参数
  782. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
  783. c.Ctx.Output.SetStatus(400)
  784. c.Data["json"] = map[string]interface{}{
  785. "code": 400,
  786. "msg": "请求参数格式错误: " + err.Error(),
  787. }
  788. c.ServeJSON()
  789. return
  790. }
  791. o := orm.NewOrm()
  792. // 构建结果
  793. type RunRecordDetail struct {
  794. RunLogID int `json:"runLogID"`
  795. RunCourseID int `json:"runCourseID"`
  796. RunCourseName string `json:"runCourseName"`
  797. RunDateTime string `json:"runDateTime"`
  798. CourseTime int `json:"courseTime"`
  799. CourseScore float64 `json:"courseScore"`
  800. PauseFlag int `json:"pauseFlag"`
  801. PauseTotalTime int `json:"pauseTotalTime"`
  802. RunStatus int `json:"runStatus"` // 0表示未运行,1表示正在运行,2表示暂停中
  803. }
  804. var results []RunRecordDetail
  805. // 使用原生SQL进行联合查询,提高查询效率
  806. sql := `SELECT
  807. r.运行记录编号,
  808. r.运行课程ID,
  809. r.运行课程名称,
  810. r.运行日期时间,
  811. r.课程用时,
  812. r.课程得分,
  813. r.暂停标记,
  814. r.暂停累计时长
  815. FROM CourseRunLog r`
  816. // 构建WHERE条件
  817. var conditions []string
  818. var args []interface{}
  819. // 添加课程ID筛选条件
  820. if req.CourseID != 0 {
  821. conditions = append(conditions, "r.运行课程ID = ?")
  822. args = append(args, req.CourseID)
  823. }
  824. // 添加时间范围筛选条件
  825. if req.StartTime != "" && req.EndTime != "" {
  826. conditions = append(conditions, "r.运行日期时间 >= ?")
  827. args = append(args, req.StartTime)
  828. conditions = append(conditions, "r.运行日期时间 <= ?")
  829. args = append(args, req.EndTime)
  830. }
  831. // 如果有其他筛选条件,则需要JOIN CourseInfo表
  832. needJoin := req.CourseName != "" || req.TypeID != 0 || req.LineNo != 0 || req.Creator != ""
  833. if needJoin {
  834. sql += " LEFT JOIN CourseInfo c ON r.运行课程ID = c.课程ID"
  835. if req.CourseName != "" {
  836. conditions = append(conditions, "c.课程名称 LIKE ?")
  837. args = append(args, "%"+req.CourseName+"%")
  838. }
  839. if req.TypeID != 0 {
  840. conditions = append(conditions, "c.分类ID = ?")
  841. args = append(args, req.TypeID)
  842. }
  843. if req.LineNo != 0 {
  844. conditions = append(conditions, "c.线路号 = ?")
  845. args = append(args, req.LineNo)
  846. }
  847. if req.Creator != "" {
  848. conditions = append(conditions, "c.创建人 LIKE ?")
  849. args = append(args, "%"+req.Creator+"%")
  850. }
  851. }
  852. // 添加WHERE条件到SQL
  853. if len(conditions) > 0 {
  854. sql += " WHERE " + strings.Join(conditions, " AND ")
  855. }
  856. // 添加排序
  857. sql += " ORDER BY r.运行记录编号 DESC"
  858. // 执行查询
  859. var runRecords []models.CourseRunLog
  860. _, err := o.Raw(sql, args...).QueryRows(&runRecords)
  861. if err != nil {
  862. c.Data["json"] = map[string]interface{}{
  863. "code": 500,
  864. "msg": "查询课程运行记录失败: " + err.Error(),
  865. }
  866. c.ServeJSON()
  867. return
  868. }
  869. // 转换为结果格式
  870. for _, record := range runRecords {
  871. // 判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
  872. courseTime := record.CourseTime
  873. if record.PauseFlag != -1 {
  874. // 课程未结束,重新计算运行时间
  875. // 将字符串转换为时间
  876. startTime, err := time.ParseInLocation("2006-01-02 15:04:05", record.RunDateTime, time.Local)
  877. if err == nil {
  878. // 计算从开始时间到当前时间的时间差(秒)
  879. duration := time.Since(startTime).Seconds()
  880. // 减去暂停的总时间得到实际运行时间
  881. calculatedTime := int(duration) - record.PauseTotalTime
  882. if calculatedTime > 0 {
  883. courseTime = calculatedTime
  884. }
  885. }
  886. }
  887. detail := RunRecordDetail{
  888. RunLogID: record.RunLogID,
  889. RunCourseID: record.RunCourseID,
  890. RunCourseName: record.RunCourseName,
  891. RunDateTime: record.RunDateTime,
  892. CourseTime: courseTime,
  893. CourseScore: record.CourseScore,
  894. PauseFlag: record.PauseFlag,
  895. PauseTotalTime: record.PauseTotalTime,
  896. RunStatus: func() int {
  897. // 根据PauseFlag确定运行状态
  898. if record.PauseFlag == 1 {
  899. return 2 // 暂停中(默认情况)
  900. } else if record.PauseFlag == -1 {
  901. return 0 // 课程结束(未运行)
  902. } else {
  903. return 1
  904. }
  905. }(),
  906. }
  907. results = append(results, detail)
  908. }
  909. c.Data["json"] = map[string]interface{}{
  910. "code": 200,
  911. "msg": "查询成功",
  912. "count": len(results),
  913. "data": results,
  914. }
  915. c.ServeJSON()
  916. }
  917. // /runrecord/delete 删除课程运行记录
  918. func (c *CourseRunController) RunRecordDelete() {
  919. // 定义请求参数结构体
  920. type Request struct {
  921. RunLogID int `json:"runLogID"`
  922. }
  923. var req Request
  924. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
  925. c.Data["json"] = map[string]interface{}{
  926. "code": 400,
  927. "msg": "请求参数格式错误: " + err.Error(),
  928. }
  929. c.ServeJSON()
  930. return
  931. }
  932. if req.RunLogID == 0 {
  933. c.Data["json"] = map[string]interface{}{
  934. "code": 400,
  935. "msg": "请提供有效的运行记录ID",
  936. }
  937. c.ServeJSON()
  938. return
  939. }
  940. o := orm.NewOrm()
  941. // 删除课程运行记录
  942. n, err := o.Delete(&models.CourseRunLog{RunLogID: req.RunLogID})
  943. if err != nil {
  944. c.Data["json"] = map[string]interface{}{
  945. "code": 500,
  946. "msg": "删除失败: " + err.Error(),
  947. }
  948. c.ServeJSON()
  949. return
  950. }
  951. if n == 0 {
  952. c.Data["json"] = map[string]interface{}{
  953. "code": 404,
  954. "msg": "运行记录不存在",
  955. }
  956. c.ServeJSON()
  957. return
  958. }
  959. // 同时删除相关的操作记录和评价记录
  960. o.QueryTable(new(models.CourseOperLog)).Filter("RunLogID", req.RunLogID).Delete()
  961. o.QueryTable(new(models.CourseEvaLog)).Filter("RunLogID", req.RunLogID).Delete()
  962. // 构造返回结果
  963. c.Data["json"] = map[string]interface{}{
  964. "code": 200,
  965. "msg": "删除成功",
  966. }
  967. c.ServeJSON()
  968. }
  969. // /oper/runrecord/list 获取操作运行记录列表
  970. func (c *CourseRunController) OperRunRecordList() {
  971. // 定义请求参数结构体
  972. type Request struct {
  973. RunLogID int `json:"runLogID"`
  974. }
  975. // 解析请求参数
  976. var req Request
  977. if len(c.Ctx.Input.RequestBody) > 0 {
  978. if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
  979. c.Data["json"] = map[string]interface{}{
  980. "code": 400,
  981. "msg": "请求参数格式错误: " + err.Error(),
  982. }
  983. c.ServeJSON()
  984. return
  985. }
  986. }
  987. // 获取数据库连接
  988. o := orm.NewOrm()
  989. // 查找课程运行记录:如果RunLogID > 0,则查询对应的记录,否则查询最近一条记录
  990. var latestCourseRun models.CourseRunLog
  991. var err error
  992. if req.RunLogID > 0 {
  993. // 查询指定RunLogID的课程运行记录
  994. err = o.QueryTable(new(models.CourseRunLog)).
  995. Filter("RunLogID", req.RunLogID).
  996. One(&latestCourseRun)
  997. } else {
  998. // 查找最近的课程运行记录(按RunLogID倒序排列,取第一个)
  999. err = o.QueryTable(new(models.CourseRunLog)).
  1000. OrderBy("-RunLogID").
  1001. One(&latestCourseRun)
  1002. }
  1003. if err != nil {
  1004. if err == orm.ErrNoRows {
  1005. c.Data["json"] = map[string]interface{}{
  1006. "code": 404,
  1007. "msg": "未找到任何课程运行记录",
  1008. }
  1009. } else {
  1010. c.Data["json"] = map[string]interface{}{
  1011. "code": 500,
  1012. "msg": "查询课程运行记录失败: " + err.Error(),
  1013. }
  1014. }
  1015. c.ServeJSON()
  1016. return
  1017. }
  1018. // 查找该课程运行记录对应的所有操作日志,并按RunOperID排序
  1019. var operLogs []models.CourseOperLog
  1020. _, err = o.QueryTable(new(models.CourseOperLog)).
  1021. Filter("RunLogID", latestCourseRun.RunLogID).
  1022. OrderBy("RunOperID").
  1023. All(&operLogs)
  1024. if err != nil {
  1025. c.Data["json"] = map[string]interface{}{
  1026. "code": 500,
  1027. "msg": "查询操作日志失败: " + err.Error(),
  1028. }
  1029. c.ServeJSON()
  1030. return
  1031. }
  1032. // 一次性查询所有模板信息到内存中
  1033. var allTemplates []models.TemplateOperation
  1034. _, err = o.QueryTable(new(models.TemplateOperation)).All(&allTemplates)
  1035. if err != nil && err != orm.ErrNoRows {
  1036. c.Data["json"] = map[string]interface{}{
  1037. "code": 500,
  1038. "msg": "查询模板信息失败: " + err.Error(),
  1039. }
  1040. c.ServeJSON()
  1041. return
  1042. }
  1043. // 建立模板ID到模板信息的映射
  1044. templateMap := make(map[int]models.TemplateOperation)
  1045. for _, tmpl := range allTemplates {
  1046. templateMap[tmpl.TemplateID] = tmpl
  1047. }
  1048. // 为每个操作日志添加课程名称和模板信息
  1049. type OperLogWithCourseName struct {
  1050. RunLogID int `json:"runLogID"`
  1051. RunCourseID int `json:"runCourseID"`
  1052. RunOperID int `json:"runOperID"`
  1053. TemplateID int `json:"templateID"`
  1054. CategoryName string `json:"categoryName"`
  1055. SubCategoryName string `json:"subCategoryName"`
  1056. TemplateName string `json:"templateName"`
  1057. TemplateType int `json:"templateType"`
  1058. OperName string `json:"operName"`
  1059. OperTime int `json:"operTime"`
  1060. OperScore float64 `json:"operScore"`
  1061. OperParam1 string `json:"operParam1"`
  1062. OperParam2 string `json:"operParam2"`
  1063. OperParam3 string `json:"operParam3"`
  1064. OperParam4 string `json:"operParam4"`
  1065. OperParam5 string `json:"operParam5"`
  1066. CourseName string `json:"courseName"`
  1067. }
  1068. operLogsWithCourseName := make([]OperLogWithCourseName, len(operLogs))
  1069. for i, log := range operLogs {
  1070. // 从内存中获取模板信息
  1071. categoryName := ""
  1072. subCategoryName := ""
  1073. templateName := ""
  1074. templateType := 0
  1075. if template, exists := templateMap[log.TemplateID]; exists {
  1076. categoryName = template.CategoryName
  1077. subCategoryName = template.SubCategoryName
  1078. templateName = template.TemplateName
  1079. templateType = template.TemplateType
  1080. }
  1081. operLogsWithCourseName[i] = OperLogWithCourseName{
  1082. RunLogID: log.RunLogID,
  1083. RunCourseID: log.RunCourseID,
  1084. RunOperID: log.RunOperID,
  1085. TemplateID: log.TemplateID,
  1086. CategoryName: categoryName,
  1087. SubCategoryName: subCategoryName,
  1088. TemplateName: templateName,
  1089. TemplateType: templateType,
  1090. OperName: log.OperName,
  1091. OperTime: log.OperTime,
  1092. OperScore: log.OperScore,
  1093. OperParam1: log.OperParam1,
  1094. OperParam2: log.OperParam2,
  1095. OperParam3: log.OperParam3,
  1096. OperParam4: log.OperParam4,
  1097. OperParam5: log.OperParam5,
  1098. CourseName: latestCourseRun.RunCourseName,
  1099. }
  1100. }
  1101. // 返回结果,返回操作日志列表和课程名称
  1102. c.Data["json"] = map[string]interface{}{
  1103. "code": 200,
  1104. "msg": "获取操作日志列表成功",
  1105. "data": operLogsWithCourseName,
  1106. }
  1107. c.ServeJSON()
  1108. }