market.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <template>
  2. <div class="market-container">
  3. <div class="market-title">
  4. <img src="@/assets/images/shb.png" class="title-icon" />
  5. 市场拓展
  6. </div>
  7. <div class="legend">
  8. <div class="legend-item">上月</div>
  9. <div class="legend-item">本月</div>
  10. </div>
  11. <div id="marketChart" class="chart"></div>
  12. </div>
  13. </template>
  14. <script>
  15. import { mapState } from "vuex"
  16. import { api } from "@/api"
  17. import * as echarts from "echarts"
  18. export default {
  19. name: "MarketExpansion",
  20. data() {
  21. return {
  22. chartInstance: null,
  23. chartData: {
  24. categories: [
  25. "新增企业",
  26. "跟进项目",
  27. "新增联系人",
  28. "新增合同",
  29. "新增项目",
  30. "新增户数",
  31. ],
  32. lastMonthData: [-9, -9, -9, -9, -3, -12], // 上月数据
  33. thisMonthData: [9, 9, 1, 1, 9, 10], // 本月数据
  34. },
  35. }
  36. },
  37. computed: {
  38. ...mapState(["entCode", "communityId"]),
  39. },
  40. mounted() {
  41. this.init()
  42. window.addEventListener("resize", this.handleResize)
  43. },
  44. beforeDestroy() {
  45. if (this.chartInstance) {
  46. this.chartInstance.dispose()
  47. }
  48. window.removeEventListener("resize", this.handleResize)
  49. },
  50. methods: {
  51. // 初始化组件
  52. init() {
  53. this.initChart()
  54. this.loadData()
  55. },
  56. // 初始化图表
  57. initChart() {
  58. this.chartInstance = echarts.init(
  59. document.getElementById("marketChart")
  60. )
  61. const option = {
  62. tooltip: {
  63. trigger: "axis",
  64. axisPointer: {
  65. type: "shadow",
  66. },
  67. backgroundColor: "rgba(17, 28, 49, 0.9)",
  68. borderColor: "rgba(64, 158, 255, 0.2)",
  69. textStyle: {
  70. color: "#ffffff",
  71. },
  72. formatter: (params) => {
  73. // 自定义tooltip格式
  74. let result = params[0].name + "<br/>"
  75. params.forEach((item) => {
  76. result +=
  77. item.marker +
  78. item.seriesName +
  79. ": " +
  80. Math.abs(item.value) +
  81. "<br/>"
  82. })
  83. return result
  84. },
  85. },
  86. grid: {
  87. left: "25%",
  88. right: "25%",
  89. bottom: "3%",
  90. top: 50,
  91. containLabel: true,
  92. },
  93. xAxis: {
  94. type: "value",
  95. axisLabel: {
  96. formatter: (value) => {
  97. if (value < 0) return -value //这里是针对取负值
  98. else return value
  99. },
  100. },
  101. show: false, // 隐藏x轴
  102. },
  103. yAxis: [
  104. {
  105. type: "category",
  106. data: this.chartData.categories,
  107. axisLine: {
  108. show: false,
  109. },
  110. axisTick: {
  111. show: false,
  112. },
  113. axisLabel: {
  114. show: false,
  115. },
  116. },
  117. {
  118. type: "category",
  119. data: this.chartData.categories,
  120. axisLine: {
  121. show: false,
  122. },
  123. axisTick: {
  124. show: false,
  125. },
  126. axisLabel: {
  127. show: false,
  128. color: "#a0b3d6",
  129. fontSize: 14,
  130. },
  131. },
  132. ],
  133. series: [
  134. {
  135. name: "上月",
  136. type: "bar",
  137. // stack: "sameStack",
  138. stack: "Total",
  139. emphasis: {
  140. focus: "series",
  141. },
  142. barMinHeight: 4,
  143. data: this.chartData.lastMonthData,
  144. barWidth: 16,
  145. itemStyle: {
  146. // 左侧渐变色:从#F66757到#FCE2B4
  147. color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
  148. { offset: 0, color: "#FCE2B4" },
  149. { offset: 1, color: "#F66757" },
  150. ]),
  151. borderRadius: [20, 0, 0, 20],
  152. },
  153. label: {
  154. show: true,
  155. position: "left",
  156. formatter: "{c}",
  157. color: "#ffffff",
  158. fontSize: 12,
  159. formatter: (value) => {
  160. return -value.data
  161. },
  162. },
  163. },
  164. {
  165. name: "本月",
  166. type: "bar",
  167. // stack: "sameStack",
  168. stack: "Total",
  169. emphasis: {
  170. focus: "series",
  171. },
  172. barMinHeight: 4,
  173. data: this.chartData.thisMonthData,
  174. barWidth: 16,
  175. itemStyle: {
  176. // 右侧渐变色:从#1620D4到#3AB3E3
  177. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  178. { offset: 0, color: "#3AB3E3" },
  179. { offset: 1, color: "#1620D4" },
  180. ]),
  181. borderRadius: [0, 20, 20, 0],
  182. },
  183. label: {
  184. show: true,
  185. position: "right",
  186. formatter: "{c}",
  187. color: "#ffffff",
  188. fontSize: 12,
  189. },
  190. },
  191. ],
  192. }
  193. this.chartInstance.setOption(option)
  194. this.chartInstance.resize()
  195. },
  196. // 加载数据
  197. async loadData() {
  198. try {
  199. const params = {
  200. entCode: this.entCode,
  201. communityId: this.communityId,
  202. }
  203. // 这里应该调用实际的API获取数据
  204. // const res = await api.getMarketExpansionData(params)
  205. // this.chartData = res.data || this.chartData
  206. // 暂时使用模拟数据
  207. this.updateChart()
  208. } catch (error) {
  209. console.error("获取市场拓展数据失败:", error)
  210. }
  211. },
  212. // 更新图表
  213. updateChart() {
  214. if (this.chartInstance) {
  215. this.chartInstance.setOption({
  216. yAxis: [
  217. {
  218. data: this.chartData.categories,
  219. },
  220. {
  221. data: this.chartData.categories,
  222. },
  223. ],
  224. series: [
  225. {
  226. data: this.chartData.lastMonthData,
  227. },
  228. {
  229. data: this.chartData.thisMonthData,
  230. },
  231. ],
  232. })
  233. }
  234. },
  235. // 处理窗口大小变化
  236. handleResize() {
  237. if (this.chartInstance) {
  238. this.chartInstance.resize()
  239. }
  240. },
  241. },
  242. }
  243. </script>
  244. <style lang="scss" scoped>
  245. @import "@/assets/css/theme.scss";
  246. .market-container {
  247. background: #0d1629;
  248. border-radius: halfW(4);
  249. height: 100%;
  250. display: flex;
  251. flex-direction: column;
  252. background: var(--content-bg);
  253. }
  254. .market-title {
  255. border-radius: halfW(4);
  256. background: var(--title-bg);
  257. padding: halfH(4) halfW(10);
  258. font-size: halfW(18);
  259. font-weight: 500;
  260. color: var(--title-primary);
  261. display: flex;
  262. align-items: center;
  263. }
  264. .legend {
  265. display: flex;
  266. justify-content: space-around;
  267. align-items: center;
  268. padding: halfH(10) halfW(20);
  269. font-size: halfW(14);
  270. font-weight: 500;
  271. color: #fff;
  272. border-bottom: 1px solid rgba(64, 158, 255, 0.2);
  273. }
  274. .chart {
  275. width: 100%;
  276. height: 100%;
  277. background: var(--content-bg);
  278. }
  279. </style>