index.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <div class="track-wrapper">
  3. <div class="track-header flex">
  4. <div class="manageTitle">运单轨迹地图</div>
  5. <div class="search flex">
  6. <el-input
  7. v-model="inputValue"
  8. class="search-input"
  9. size="default"
  10. placeholder="请输入运单号"
  11. :prefix-icon="Search"
  12. clearable
  13. @clear="clearHandler"
  14. />
  15. <el-button
  16. class="search-button"
  17. size="default"
  18. type="primary"
  19. @click="searchHandler"
  20. >运单查询</el-button
  21. >
  22. </div>
  23. </div>
  24. <div class="track-map-wrapper">
  25. <div ref="trackMap" class="track-map" />
  26. </div>
  27. </div>
  28. </template>
  29. <script lang="ts" setup>
  30. import { Search } from '@element-plus/icons-vue'
  31. import { init, ECharts } from 'echarts'
  32. import { ElMessage } from 'element-plus'
  33. const inputValue = ref('')
  34. const searchHandler = () => {
  35. ElMessage.info('开发中')
  36. }
  37. const clearHandler = () => {}
  38. const activeColor = '#AC014D'
  39. const inActiveColor = '#9C9FA5'
  40. const trackMap = ref<HTMLElement | null>(null)
  41. let trackMapCharts: ECharts
  42. const option = reactive({
  43. tooltip: {
  44. show: false,
  45. },
  46. animationDurationUpdate: 1500,
  47. animationEasingUpdate: 'quinticInOut',
  48. series: [
  49. {
  50. type: 'graph',
  51. layout: 'none',
  52. top: 150,
  53. bottom: 80,
  54. symbolSize: 24,
  55. itemStyle: {
  56. color: activeColor,
  57. },
  58. label: {
  59. show: true,
  60. offset: [0, -70],
  61. width: 120,
  62. height: 90,
  63. lineHeight: 24,
  64. backgroundColor: activeColor,
  65. borderRadius: 4,
  66. align: 'center',
  67. color: '#FFFFFF',
  68. fontSize: 16,
  69. fontFamily: 'Microsoft YaHei',
  70. fontWeight: 'bold',
  71. formatter: '{b}\n{c}',
  72. },
  73. data: [
  74. {
  75. name: '收运核单',
  76. x: 200,
  77. y: 500,
  78. value: '',
  79. },
  80. {
  81. name: '安检',
  82. x: 350,
  83. y: 450,
  84. value: '',
  85. },
  86. {
  87. name: '理货',
  88. x: 520,
  89. y: 300,
  90. value: '',
  91. },
  92. {
  93. name: '待运区',
  94. x: 680,
  95. y: 300,
  96. value: '',
  97. },
  98. {
  99. name: '货站交接',
  100. x: 890,
  101. y: 200,
  102. value: '',
  103. },
  104. {
  105. name: '机下交接',
  106. x: 930,
  107. y: 40,
  108. value: '',
  109. },
  110. {
  111. name: '装机',
  112. x: 780,
  113. y: 0,
  114. value: '',
  115. },
  116. ] as any[],
  117. links: [] as any[],
  118. lineStyle: {
  119. width: 6,
  120. color: activeColor,
  121. opacity: 1,
  122. curveness: 0,
  123. },
  124. },
  125. ],
  126. })
  127. watch(
  128. () => option.series[0].data,
  129. array => {
  130. option.series[0].links = array.reduce(
  131. (preArray, currentData, currentIndex, orginArray) => {
  132. if (currentIndex > 0) {
  133. const preData = orginArray[currentIndex - 1]
  134. const link = {
  135. source: preData.name,
  136. target: currentData.name,
  137. }
  138. if (!preData.value || !currentData.value) {
  139. Object.assign(link, {
  140. lineStyle: {
  141. color: inActiveColor,
  142. },
  143. })
  144. }
  145. preArray.push(link)
  146. }
  147. return preArray
  148. },
  149. []
  150. )
  151. trackMapCharts.setOption(option)
  152. },
  153. { deep: true }
  154. )
  155. onMounted(() => {
  156. trackMapCharts = init(trackMap.value as HTMLElement)
  157. const nodeValues = getNodeValues()
  158. nodeValues.forEach((value, index) => {
  159. option.series[0].data[index].value = value
  160. if (!value) {
  161. option.series[0].data[index].label = {
  162. backgroundColor: inActiveColor,
  163. }
  164. option.series[0].data[index].itemStyle = {
  165. color: '#FFFFFF',
  166. borderColor: inActiveColor,
  167. borderWidth: 3,
  168. }
  169. } else {
  170. delete option.series[0].data[index].label
  171. delete option.series[0].data[index].itemStyle
  172. }
  173. })
  174. window.addEventListener('resize', resizeHandler)
  175. })
  176. onBeforeUnmount(() => {
  177. window.removeEventListener('resize', resizeHandler)
  178. })
  179. const resizeHandler = () => {
  180. trackMapCharts.resize()
  181. }
  182. const getNodeValues = () => {
  183. return [
  184. 'A32/534件/\n通过/10:25',
  185. 'B24/534件/\n通过/10:40',
  186. 'C24/534件/\n通过/11:01',
  187. 'D32/534件/\n通过/11:25',
  188. 'E24/534件/\n通过/11:40',
  189. 'F24/534件/\n通过/12:02',
  190. '',
  191. ]
  192. }
  193. </script>
  194. <style lang="scss" scoped>
  195. .track-wrapper {
  196. width: 100%;
  197. height: 100%;
  198. .track-header {
  199. margin-bottom: 16px;
  200. .search {
  201. &-input {
  202. width: 240px;
  203. margin-right: 12px;
  204. box-shadow: 0px 3px 3px 0px rgba(0, 0, 0, 0.06);
  205. }
  206. &-button {
  207. background: #d5327b;
  208. border-radius: 4px;
  209. border: none;
  210. }
  211. }
  212. }
  213. .track-map-wrapper {
  214. width: 100%;
  215. height: calc(100% - 32px - 16px);
  216. background: url('@/assets/bg_map.jpg') no-repeat center/100% 100%;
  217. .track-map {
  218. height: 100%;
  219. }
  220. }
  221. }
  222. </style>