rd-value.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <script lang="ts" setup>
  2. import * as echarts from 'echarts'
  3. import {
  4. ANIMATION,
  5. CHART_RENDERER,
  6. createLegend,
  7. createTooltip,
  8. FONT_FAMILY,
  9. THEME
  10. } from '@/utils/kb'
  11. interface ValueDistributionItem {
  12. projectDept: string
  13. originalValue: number
  14. netValue: number
  15. }
  16. const chartData: ValueDistributionItem[] = [
  17. {
  18. projectDept: '公摊',
  19. originalValue: 2760.06,
  20. netValue: 622.61
  21. },
  22. {
  23. projectDept: '新疆',
  24. originalValue: 3051.49,
  25. netValue: 920.62
  26. },
  27. {
  28. projectDept: '青海',
  29. originalValue: 10038.67,
  30. netValue: 3388.01
  31. },
  32. {
  33. projectDept: '东部',
  34. originalValue: 6060.15,
  35. netValue: 881.46
  36. },
  37. {
  38. projectDept: '西南连油',
  39. originalValue: 4059.36,
  40. netValue: 743.24
  41. },
  42. {
  43. projectDept: '西南压裂',
  44. originalValue: 11557.18,
  45. netValue: 4401.63
  46. },
  47. {
  48. projectDept: '伊拉克',
  49. originalValue: 15417.01,
  50. netValue: 6318.24
  51. },
  52. {
  53. projectDept: '利比亚',
  54. originalValue: 1942.14,
  55. netValue: 1700.17
  56. }
  57. ]
  58. const chartRef = ref<HTMLDivElement>()
  59. let chart: echarts.ECharts | null = null
  60. const BAR_WIDTH = 22
  61. const LABEL_FONT_SIZE = 13
  62. function getBarStyle(color: (typeof THEME.color)[keyof typeof THEME.color]) {
  63. return {
  64. borderRadius: [12, 12, 0, 0],
  65. shadowBlur: 12,
  66. shadowColor: color.bg,
  67. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  68. { offset: 0, color: color.light },
  69. { offset: 0.55, color: color.mid },
  70. { offset: 1, color: color.line }
  71. ])
  72. }
  73. }
  74. function formatMoney(value: number | string) {
  75. return Number(value || 0).toLocaleString('en-US', {
  76. minimumFractionDigits: 2,
  77. maximumFractionDigits: 2
  78. })
  79. }
  80. function formatProjectDept(value: string) {
  81. if (value.length <= 5) return value
  82. return value.replace('项目部', '\n项目部').replace('折算RMB', '\n折算RMB')
  83. }
  84. function getChartOption(data: ValueDistributionItem[]): echarts.EChartsOption {
  85. const projectDepts = data.map((item) => item.projectDept)
  86. return {
  87. ...ANIMATION,
  88. grid: {
  89. ...THEME.grid,
  90. top: 58,
  91. right: 20,
  92. bottom: 4
  93. },
  94. tooltip: createTooltip({
  95. trigger: 'axis',
  96. axisPointer: {
  97. type: 'shadow',
  98. shadowStyle: {
  99. color: THEME.split
  100. }
  101. },
  102. valueFormatter(value: number | string) {
  103. return `${formatMoney(value)} 万元`
  104. }
  105. }),
  106. legend: createLegend(
  107. {
  108. top: 4,
  109. itemWidth: 12,
  110. itemHeight: 12
  111. },
  112. ['原值', '净值']
  113. ),
  114. xAxis: {
  115. type: 'category',
  116. data: projectDepts,
  117. axisLine: {
  118. show: false
  119. },
  120. axisTick: {
  121. show: false
  122. },
  123. axisLabel: {
  124. interval: 0,
  125. color: THEME.text.regular,
  126. fontSize: 12,
  127. fontFamily: FONT_FAMILY,
  128. formatter(value: string) {
  129. return formatProjectDept(value)
  130. }
  131. }
  132. },
  133. yAxis: {
  134. type: 'value',
  135. name: '价值(万元)',
  136. splitNumber: 4,
  137. nameTextStyle: {
  138. color: THEME.text.regular,
  139. fontSize: 13,
  140. fontFamily: FONT_FAMILY
  141. },
  142. axisLine: {
  143. show: false
  144. },
  145. axisTick: {
  146. show: false
  147. },
  148. axisLabel: {
  149. color: THEME.text.regular,
  150. fontSize: 12,
  151. fontFamily: FONT_FAMILY,
  152. formatter(value: number) {
  153. return formatMoney(value)
  154. }
  155. },
  156. splitLine: {
  157. lineStyle: {
  158. color: THEME.split,
  159. type: 'dashed'
  160. }
  161. }
  162. },
  163. series: [
  164. {
  165. name: '原值',
  166. type: 'bar',
  167. data: data.map((item) => item.originalValue),
  168. barWidth: BAR_WIDTH,
  169. barMaxWidth: 28,
  170. barGap: '18%',
  171. itemStyle: getBarStyle(THEME.color.blue),
  172. label: {
  173. show: true,
  174. position: 'top',
  175. distance: 10,
  176. color: THEME.color.blue.strong,
  177. fontSize: LABEL_FONT_SIZE,
  178. fontWeight: 700,
  179. fontFamily: FONT_FAMILY,
  180. formatter(params: any) {
  181. return Number(params.value) ? formatMoney(params.value) : ''
  182. }
  183. },
  184. emphasis: {
  185. focus: 'series',
  186. itemStyle: {
  187. ...getBarStyle(THEME.color.blue),
  188. shadowColor: THEME.color.blue.shadow,
  189. shadowBlur: 18
  190. }
  191. }
  192. },
  193. {
  194. name: '净值',
  195. type: 'bar',
  196. data: data.map((item) => item.netValue),
  197. barWidth: BAR_WIDTH,
  198. barMaxWidth: 28,
  199. itemStyle: getBarStyle(THEME.color.green),
  200. label: {
  201. show: true,
  202. position: 'top',
  203. distance: 6,
  204. color: THEME.color.green.strong,
  205. fontSize: LABEL_FONT_SIZE,
  206. fontWeight: 700,
  207. fontFamily: FONT_FAMILY,
  208. formatter(params: any) {
  209. return Number(params.value) ? formatMoney(params.value) : ''
  210. }
  211. },
  212. emphasis: {
  213. focus: 'series',
  214. itemStyle: {
  215. ...getBarStyle(THEME.color.green),
  216. shadowColor: THEME.color.green.shadow,
  217. shadowBlur: 18
  218. }
  219. }
  220. }
  221. ]
  222. }
  223. }
  224. function initChart() {
  225. if (!chartRef.value) return
  226. chart?.dispose()
  227. chart = echarts.init(chartRef.value, undefined, {
  228. renderer: CHART_RENDERER
  229. })
  230. renderChart()
  231. }
  232. function renderChart() {
  233. chart?.setOption(getChartOption(chartData), true)
  234. }
  235. function resizeChart() {
  236. chart?.resize()
  237. }
  238. function destroyChart() {
  239. chart?.dispose()
  240. chart = null
  241. }
  242. onMounted(() => {
  243. initChart()
  244. window.addEventListener('resize', resizeChart)
  245. window.addEventListener('rdkb:resize', resizeChart)
  246. })
  247. onUnmounted(() => {
  248. window.removeEventListener('resize', resizeChart)
  249. window.removeEventListener('rdkb:resize', resizeChart)
  250. destroyChart()
  251. })
  252. </script>
  253. <template>
  254. <div class="panel flex flex-col">
  255. <div class="panel-title">
  256. <div class="icon-decorator">
  257. <span></span>
  258. <span></span>
  259. </div>
  260. 价值分布
  261. </div>
  262. <div ref="chartRef" class="flex-1 min-h-0"></div>
  263. </div>
  264. </template>
  265. <style lang="scss" scoped>
  266. @import url('@/styles/kb.scss');
  267. </style>