ProcessCanvas.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <script setup lang="ts">
  2. import {onMounted, ref, type Ref, watch} from "vue";
  3. import * as echarts from 'echarts';
  4. import {inject} from "vue-demi";
  5. import type {EChartsType} from "echarts";
  6. import useApis from "@/apis";
  7. const props = defineProps<{
  8. assignmentId:number,
  9. splitNumber:number,
  10. }>()
  11. const currentEngagement = inject('currentEngagement') as Ref<any>;
  12. let productData = [];
  13. let cursorData = [];
  14. let processData = [];
  15. watch(currentEngagement,()=>{
  16. noData.value = false
  17. setTimeout(()=>{
  18. let chartDom = document.getElementById('process-canvas');
  19. if (!chartDom)return;
  20. let myChart = echarts.getInstanceByDom(chartDom);
  21. if (!myChart){
  22. myChart = echarts.init(chartDom);
  23. }
  24. getCanvasData(myChart);
  25. },0)
  26. });
  27. const loadingStatus = inject('loadingStatus') as Ref<{
  28. edit:boolean,
  29. pause:boolean,
  30. process:boolean,
  31. total:boolean
  32. }>;
  33. function formatTimeWithMilliseconds(stamp:number,flag = false ){
  34. const date = new Date(stamp);
  35. const hours = date.getHours().toString().padStart(2, '0');
  36. const minutes = date.getMinutes().toString().padStart(2, '0');
  37. const seconds = date.getSeconds().toString().padStart(2, '0');
  38. if (flag){
  39. return `${hours}:${minutes}:${seconds}`
  40. }
  41. const milliseconds = date.getMilliseconds().toString().padStart(3, '0');
  42. return `${hours}:${minutes}:${seconds}.${milliseconds}`;
  43. }
  44. const apis = useApis();
  45. //停顿数据
  46. const pauseData:any[] = [];
  47. let chartData:any[] = [];
  48. //visualMap 上下限
  49. const limit = {
  50. max:0,
  51. min:0
  52. }
  53. let versionIndex = inject('currentVersionIndex') satisfies Ref<number>
  54. watch(versionIndex,()=>{
  55. setTimeout(()=>{
  56. let chartDom = document.getElementById('process-canvas');
  57. if (!chartDom)return;
  58. let myChart = echarts.getInstanceByDom(chartDom);
  59. if (!myChart){
  60. myChart = echarts.init(chartDom);
  61. }
  62. getCanvasData(myChart);
  63. },0)
  64. })
  65. function getCanvasData(chart:EChartsType){
  66. //TODO
  67. if (!currentEngagement.value){
  68. return;
  69. }
  70. chart.showLoading({text:'加载中'});
  71. loadingStatus.value.process = true;
  72. let studentId = currentEngagement.value.studentId;
  73. let assignmentId = currentEngagement.value.assignmentId;
  74. apis.selectBehaviorRecordVersions(studentId,assignmentId)
  75. .then((res:any) => {
  76. if (res.data && res.data.code == 200 && res.data.data && res.data.data.versions
  77. && Array.isArray(res.data.data.versions[versionIndex.value]?.events)){
  78. let rowData = res.data.data.versions[versionIndex.value].events as any[];
  79. console.log("行为数据",rowData);
  80. //数组初始化
  81. let clock = new Date(0);
  82. clock.setHours(clock.getHours() + 16);
  83. // clock.setFullYear(2025)
  84. // clock.setMonth(6)
  85. // clock.setDate(26);
  86. cursorData = [[clock,0]]
  87. productData = [[clock,0]]
  88. processData = [[clock,0]]
  89. pauseData.length = 0;
  90. chartData.length = 0;
  91. let processCount = 0;
  92. let zeroCount =0;
  93. if (!rowData){
  94. chart.hideLoading();
  95. loadingStatus.value.process = false;
  96. noData.value = true
  97. return
  98. }
  99. else{
  100. loadingStatus.value.process = false;
  101. noData.value = false
  102. }
  103. rowData.forEach((item:any) => {
  104. // console.log("item",item)
  105. let startStamp = 0;
  106. if (item.startStamp){
  107. startStamp = item.startStamp;
  108. }
  109. else{
  110. return;
  111. }
  112. if (item.pauseTime < 0){
  113. return;
  114. }
  115. if (startStamp == 0){
  116. zeroCount++;
  117. }
  118. if (zeroCount>1){
  119. zeroCount = 0;
  120. return;
  121. }
  122. let clock = new Date(startStamp);
  123. clock.setHours(clock.getHours() + 16);
  124. // clock.setFullYear(2025)
  125. // clock.setMonth(6)
  126. // clock.setDate(26);
  127. cursorData.push([clock,item.retain+1])
  128. productData.push([clock,item.docLength])
  129. pauseData.push([clock,item.pauseTime])
  130. chartData.push([clock,item.pauseTime])
  131. limit.max = Math.max(limit.max,item.pauseTime);
  132. let temp = 0;
  133. if (productData.length == 1){
  134. temp = productData[0][1];
  135. }
  136. else{
  137. let pre = productData[productData.length-2][1];
  138. if (item.docLength > pre){
  139. temp += item.docLength - pre;
  140. }
  141. }
  142. processCount+=temp;
  143. processData.push([clock,processCount])
  144. })
  145. let option = {
  146. xAxis: {
  147. type: 'time',
  148. axisPointer: {
  149. label: {
  150. show: true,
  151. formatter: function(params) {
  152. return formatTimeWithMilliseconds(params.value);
  153. }
  154. },
  155. show: true,
  156. type: "line"
  157. },
  158. splitNumber: props.splitNumber,
  159. axisLabel:{
  160. formatter: function(value) {
  161. return formatTimeWithMilliseconds(value,true);
  162. }
  163. }
  164. },
  165. yAxis: [{
  166. type: 'value',
  167. name:'characters',
  168. position:'left',
  169. alignTicks:true
  170. },{
  171. type: 'value',
  172. name:'停顿时间(s)',
  173. position: 'right',
  174. axisLabel:{
  175. formatter: function (value:number) {
  176. return (value/1000).toFixed(2) + 's';
  177. }
  178. }
  179. }],
  180. tooltip:{
  181. },
  182. dataZoom: [
  183. {
  184. type: 'inside',
  185. },
  186. {
  187. type: 'slider',
  188. labelFormatter: function (value) {
  189. return formatTimeWithMilliseconds(value,true);
  190. },
  191. left:60,
  192. right:60
  193. }
  194. ],
  195. legend:{
  196. left:0
  197. },
  198. visualMap: {
  199. type: 'continuous', // 连续型映射
  200. calculable: true,
  201. min: 0, // 数据最小值
  202. max: limit.max, // 数据最大值
  203. dimension: 1, // 根据第2个维度(y值)映射颜色
  204. inRange: {
  205. color: ['orange', 'red'] // 渐变范围:小值→蓝色,大值→红色
  206. },
  207. seriesIndex: [3],
  208. itemWidth: 10,
  209. top:0,
  210. right:0,
  211. orient:'horizontal',
  212. align: 'right',
  213. formatter: function (value:number) {
  214. return (value/1000).toFixed(3)+'s'; // 范围标签显示内容。
  215. }
  216. },
  217. series: [
  218. {
  219. itemStyle: {
  220. color:'#37ff00',
  221. opacity: 0
  222. },
  223. name:'product',
  224. data: productData,
  225. type: 'line',
  226. yAxisIndex: 0
  227. },
  228. {
  229. itemStyle: {
  230. color:'#37ff00',
  231. opacity: 0
  232. },
  233. lineStyle: {
  234. type: "dotted"
  235. },
  236. name:'cursor',
  237. data: cursorData,
  238. type: 'line',
  239. yAxisIndex: 0
  240. },
  241. {
  242. itemStyle: {
  243. color:'#1d86dc',
  244. opacity: 0
  245. },
  246. name:'process',
  247. data: processData,
  248. type: 'line',
  249. yAxisIndex: 0
  250. },
  251. {
  252. symbolSize: 10,
  253. data: chartData,
  254. type: 'scatter',
  255. yAxisIndex: 1
  256. }
  257. ]
  258. };
  259. chart.setOption( option);
  260. chart.hideLoading();
  261. loadingStatus.value.process = false;
  262. chart.on('datarangeselected', (params:any) => {
  263. let range = params.selected as [number,number];
  264. chartData = pauseData.filter((item:any) => {
  265. return item[1] >= range[0] && item[1] <= range[1];
  266. })
  267. option.series[3].data = chartData;
  268. chart.setOption(option)
  269. });
  270. }
  271. else{
  272. loadingStatus.value.process = false
  273. chart.hideLoading()
  274. noData.value = true
  275. }
  276. })
  277. //测试用数据
  278. }
  279. let noData = ref(false)
  280. onMounted(()=>{
  281. let chartDom = document.getElementById('process-canvas');
  282. let myChart = echarts.init(chartDom);
  283. getCanvasData(myChart)
  284. window.addEventListener('resize', ()=>{
  285. myChart.resize()
  286. })
  287. })
  288. </script>
  289. <template>
  290. <div id="process-canvas" class="canvas-container" v-if="!noData">
  291. </div>
  292. <div class="canvas-container" v-else>
  293. <el-empty description="暂无数据"/>
  294. </div>
  295. </template>
  296. <style scoped>
  297. .canvas-container{
  298. width: 100%;
  299. height: 100%;
  300. }
  301. </style>