index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <template>
  2. <div class="process">
  3. <svg
  4. viewBox="0 0 1440 780"
  5. @click.stop="details({ X: -10000, Y: -10000, name: '', sTime: 0, eTime: 0 })"
  6. >
  7. <defs>
  8. <!-- 24小时文字样式 -->
  9. <g id="default">
  10. <line
  11. x1="0"
  12. y1="0"
  13. x2="1440"
  14. y2="0"
  15. stroke=" #195481"
  16. stroke-width="1"
  17. />
  18. <rect
  19. x="0"
  20. y="0"
  21. width="1440"
  22. height="29"
  23. fill="#2469C9"
  24. fill-opacity="0.2"
  25. />
  26. <line
  27. x1="0"
  28. y1="30"
  29. x2="1440"
  30. y2="30"
  31. stroke=" #195481"
  32. stroke-width="1"
  33. />
  34. <g
  35. v-for="(item, index) in time"
  36. :key="index"
  37. >
  38. <g v-if="index < 24">
  39. <text
  40. :x="index * 60 + 15"
  41. y="20"
  42. font-size="14"
  43. fill="white"
  44. >
  45. {{ index === 23 ? '00:00' : item + ':00' }}
  46. </text>
  47. <line
  48. :x1="index * 60"
  49. y1="0"
  50. :x2="index * 60"
  51. y2="780"
  52. stroke="#195481"
  53. stroke-width="1"
  54. />
  55. </g>
  56. <line
  57. v-else
  58. :x1="index * 60"
  59. y1="0"
  60. :x2="index * 60"
  61. y2="780"
  62. stroke="#195481"
  63. stroke-width="1"
  64. />
  65. </g>
  66. </g>
  67. <!-- tip -->
  68. <g id="tip">
  69. <image
  70. href="./img/1.png"
  71. width="130"
  72. height="80"
  73. />
  74. <text
  75. fill="white"
  76. y="28"
  77. x="15"
  78. font-size="13"
  79. >
  80. {{ tipData.name }}
  81. </text>
  82. <text
  83. fill="white"
  84. y="48"
  85. x="15"
  86. font-size="12"
  87. >
  88. 开始时间:{{ tipData.st }}
  89. </text>
  90. <text
  91. fill="white"
  92. y="68"
  93. x="15"
  94. font-size="12"
  95. >
  96. 结束时间:{{ tipData.et }}
  97. </text>
  98. </g>
  99. </defs>
  100. <!-- 24小时 -->
  101. <use xlink:href="#default" />
  102. <!-- 工序格 -->
  103. <rect
  104. v-for="(item, index) in planDetail"
  105. :key="index"
  106. :x="item.X"
  107. :y="item.Y"
  108. rx="2"
  109. ry="2"
  110. :width="item.width"
  111. height="20"
  112. :fill="colorDic[item.name!]"
  113. @click.stop="details(item)"
  114. />
  115. <!-- tips -->
  116. <use
  117. xlink:href="#tip"
  118. :x="tipData.X"
  119. :y="tipData.Y"
  120. />
  121. </svg>
  122. </div>
  123. </template>
  124. <script setup lang='ts'>
  125. import { onMounted, ref, watch } from 'vue'
  126. import { format } from 'date-fns'
  127. interface Item {
  128. name: string,
  129. X?: number,
  130. Y?: number,
  131. width?: number,
  132. sTime: number,
  133. eTime: number,
  134. st?: string,
  135. et?: string
  136. }
  137. const props = withDefaults(defineProps<{
  138. data?: Item[]
  139. }>(), {
  140. data: () => [
  141. {
  142. name: '地质钻探',
  143. sTime: 1730795400000,
  144. eTime: 1730797200000
  145. },
  146. {
  147. name: '开挖(装药)',
  148. sTime: 1730795400000,
  149. eTime: 1730797200000
  150. },
  151. {
  152. name: '通风除尘',
  153. sTime: 1730797200000,
  154. eTime: 1730800800000
  155. },
  156. {
  157. name: '装渣',
  158. sTime: 1730795400000,
  159. eTime: 1730797200000
  160. },
  161. {
  162. name: '运渣',
  163. sTime: 1730795400000,
  164. eTime: 1730797200000
  165. },
  166. {
  167. name: '拱架安装',
  168. sTime: 1730795400000,
  169. eTime: 1730797200000
  170. },
  171. {
  172. name: '锚杆安装',
  173. sTime: 1730795400000,
  174. eTime: 1730797200000
  175. },
  176. {
  177. name: '湿喷混凝土',
  178. sTime: 1730795400000,
  179. eTime: 1730797200000
  180. },
  181. {
  182. name: '超前支护',
  183. sTime: 1730795400000,
  184. eTime: 1730797200000
  185. },
  186. {
  187. name: '仰拱作业',
  188. sTime: 1730795400000,
  189. eTime: 1730797200000
  190. },
  191. {
  192. name: '防排水',
  193. sTime: 1730795400000,
  194. eTime: 1730797200000
  195. },
  196. {
  197. name: '二衬作业',
  198. sTime: 1730795400000,
  199. eTime: 1730797200000
  200. },
  201. {
  202. name: '养护',
  203. sTime: 1730795400000,
  204. eTime: 1730797200000
  205. },
  206. {
  207. name: '水电槽',
  208. sTime: 1730795400000,
  209. eTime: 1730797200000
  210. }
  211. ]
  212. })
  213. const colorDic: Object = {
  214. 地质钻探: '#6fff8c',
  215. '开挖(装药)': '#439bff',
  216. 通风除尘: '#ff7e47',
  217. 装渣: '#ff64d3',
  218. 运渣: '#3cecda',
  219. 拱架安装: '#ffc941',
  220. 锚杆安装: '#956dff',
  221. 湿喷混凝土: '#ffeb81',
  222. 超前支护: '#20c8ff',
  223. 仰拱作业: '#d510ff',
  224. 防排水: '#0000FF',
  225. 二衬作业: '#0000CD',
  226. 养护: '#B0C4DE',
  227. 水电槽: '#B0E0E6'
  228. }
  229. const time = new Array(25).fill(null).map((_, i) => i + 1)
  230. const planDetail = ref([] as Item[])
  231. const tipData = ref({
  232. X: -100000, name: '', st: '', et: '', Y: -10000
  233. } as Item)
  234. function countTime(item: Item[]) {
  235. const arr = item.map((el, k) => ({
  236. ...el,
  237. st: `${format(el.sTime, 'HH:mm')}`,
  238. et: `${format(el.eTime, 'HH:mm')}`,
  239. width: Math.floor((el.eTime! - el.sTime!) / 1000 / 60 / 60 * 10) / 10 * 60,
  240. X: (new Date(el.sTime!).getHours() - 1 + new Date(el.sTime!).getMinutes() / 60) * 60,
  241. Y: 50 + k * 40
  242. }))
  243. return arr
  244. }
  245. function details(item: Item) {
  246. tipData.value = {
  247. ...item,
  248. X: item.X! + item.width! / 2 - (130 / 2),
  249. Y: item.Y! + 20
  250. }
  251. }
  252. watch(() => props.data, (v) => {
  253. planDetail.value = countTime(v)
  254. }, { immediate: true })
  255. onMounted(() => { document.title = 'SVG进度' })
  256. </script>
  257. <style lang="scss" scoped>
  258. .process {
  259. width: 100%;
  260. height: 100%;
  261. padding: 15px;
  262. box-sizing: border-box;
  263. background: #0c1f3a;
  264. svg {
  265. user-select: none;
  266. }
  267. }
  268. </style>