pestEchart.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <template>
  2. <view class="pest-echart" v-show="tabs.length">
  3. <view class="pest-echart__header">
  4. <view class="tab-list">
  5. <view
  6. v-for="(tab, index) in tabs"
  7. :key="index"
  8. class="tab-item"
  9. :class="{ active: activeTab === index }"
  10. @click="switchTab(index)"
  11. >
  12. {{ tab.name }}
  13. </view>
  14. </view>
  15. </view>
  16. <view class="pest-echart__content" v-show="dayData.length">
  17. <!-- 三个关键时期 -->
  18. <view class="period-section">
  19. <view class="period-item">
  20. <view class="period-label">始见期</view>
  21. <view class="period-value">{{ periodData.firstDate }}</view>
  22. </view>
  23. <view class="period-item">
  24. <view class="period-label">高峰期</view>
  25. <view class="period-value">{{ periodData.peakDate }}</view>
  26. </view>
  27. <view class="period-item">
  28. <view class="period-label">终见期</view>
  29. <view class="period-value">{{ periodData.lastDate }}</view>
  30. </view>
  31. </view>
  32. <!-- 图表区域 -->
  33. <view class="chart-container">
  34. <!-- <canvas
  35. canvas-id="pestChart"
  36. id="pestChart"
  37. class="charts"
  38. :style="{'width':cWidth*pixelRatio+'px','height':cHeight*pixelRatio+'px', 'transform': 'scale('+(1/pixelRatio)+')','margin-left':-cWidth*(pixelRatio-1)/2+'px','margin-top':-cHeight*(pixelRatio-1)/2+'px'}"
  39. @touchstart="touchChart($event)"
  40. @touchmove="moveChart($event)"
  41. @touchend="touchEndChart($event)"
  42. disable-scroll=true
  43. ></canvas> -->
  44. <qiun-data-charts type="line" :chartData="chartData" :opts="opts" :canvas2d="true" :inScrollView="true" :ontouch="true" />
  45. </view>
  46. </view>
  47. </view>
  48. </template>
  49. <script>
  50. import uCharts from '../../../components/js_sdk/u-charts/u-charts/u-charts.js';
  51. let chartInstance = null;
  52. export default {
  53. name: 'PestEchart',
  54. props:{
  55. pest_order:{
  56. type: Object,
  57. default: () => ({})
  58. },
  59. endDate: {
  60. type: String,
  61. default: ''
  62. },
  63. d_id: {
  64. type: String | Number,
  65. default: ''
  66. },
  67. day:{
  68. type: Array,
  69. default: () => []
  70. },
  71. pest:{
  72. type: Array,
  73. default: () => []
  74. },
  75. },
  76. data() {
  77. return {
  78. tabs: [],
  79. currentPest:'',
  80. activeTab: 0,
  81. dayData:[],
  82. // 三个关键时期数据
  83. periodData: {
  84. firstDate: '-',
  85. peakDate: '-',
  86. lastDate: '-'
  87. },
  88. chartData: {},
  89. // canvas 尺寸配置
  90. cWidth: 650,
  91. cHeight: 400,
  92. pixelRatio: 1,
  93. opts: {
  94. type: 'line',
  95. xAxis: {
  96. disableGrid: true,
  97. itemCount: 3,
  98. scrollShow: true
  99. },
  100. yAxis: {
  101. disableGrid: false,
  102. gridType: 'dash',
  103. gridColor: '#E5E5E5',
  104. splitNumber: 5,
  105. min: 0,
  106. minInterval: 1,
  107. axisLine: true,
  108. data: [{
  109. min: 0,
  110. toFixed: 0
  111. }]
  112. },
  113. extra: {
  114. line: {
  115. type: 'curve'
  116. },
  117. tooltip: {
  118. format: {
  119. name: '',
  120. value: (val) => Math.round(val)
  121. }
  122. }
  123. },
  124. legend: {
  125. },
  126. enableScroll: true
  127. },
  128. };
  129. },
  130. watch:{
  131. pest_order:{
  132. handler(val){
  133. this.tabs = [];
  134. for(let key in val){
  135. this.tabs.push({
  136. name: key,
  137. })
  138. }
  139. const name = this.tabs[0]?.name;
  140. this.currentPest = name;
  141. if(this.currentPest){
  142. this.getPestNameDetail(name);
  143. this.setChartData();
  144. }
  145. },
  146. deep: true
  147. },
  148. d_id:{
  149. handler(val){
  150. val && this.setChartData();
  151. },
  152. deep: true
  153. },
  154. endDate:{
  155. handler(val){
  156. val && this.setChartData();
  157. },
  158. deep: true
  159. },
  160. day:{
  161. handler(){
  162. this.initChart();
  163. },
  164. deep: true,
  165. immediate: true
  166. },
  167. },
  168. mounted() {
  169. this.cWidth = uni.upx2px(650);
  170. this.cHeight = uni.upx2px(400);
  171. this.pixelRatio = uni.getSystemInfoSync().pixelRatio;
  172. },
  173. methods: {
  174. async getPestNameDetail(name){
  175. try{
  176. const res = await this.$myRequest({
  177. url: '/api/pest_name_detail',
  178. method: 'POST',
  179. data: {
  180. name
  181. },
  182. });
  183. this.deviceInfo = res
  184. this.$emit('getInfo',res)
  185. }catch(err){
  186. this.$emit('getInfo',{})
  187. }
  188. },
  189. async setChartData(){
  190. if(!this.currentPest){
  191. return;
  192. }
  193. if(!this.d_id || !this.endDate){
  194. return;
  195. }
  196. const res = await this.$myRequest({
  197. url: '/api/api_gateway?method=forecast.cbd_analysis.pest_predict_time',
  198. method: 'POST',
  199. data: {
  200. model:'B',
  201. d_id: this.d_id,
  202. year: this.endDate.split('-')[0],
  203. pest: this.currentPest,
  204. },
  205. });
  206. this.periodData = {
  207. firstDate: res[0][0],
  208. peakDate: res[1][0],
  209. lastDate: res[2][0],
  210. }
  211. },
  212. initChart() {
  213. this.$nextTick(() => {
  214. this.updateChartsData(0);
  215. });
  216. },
  217. drawChart(index) {
  218. const dayData = this.day || [];
  219. this.dayData = dayData;
  220. const pestData = this.pest[index];
  221. const ctx = uni.createCanvasContext('pestChart', this);
  222. chartInstance = new uCharts({
  223. context: ctx,
  224. type: 'line',
  225. fontSize: 11,
  226. legend: {
  227. show: false
  228. },
  229. background: '#FFFFFF',
  230. pixelRatio: this.pixelRatio,
  231. animation: true,
  232. dataLabel: false,
  233. categories: dayData,
  234. series: [{
  235. name: '',
  236. data: pestData
  237. }],
  238. color: ['#0085FF'],
  239. xAxis: {
  240. disableGrid: false,
  241. boundaryGap: 'justify',
  242. axisLine: true,
  243. lineColor: '#CCCCCC',
  244. fontColor: '#999999'
  245. },
  246. yAxis: {
  247. min: 0,
  248. minInterval: 1,
  249. splitNumber: 4,
  250. axisLine: true,
  251. lineColor: '#CCCCCC',
  252. fontColor: '#999999',
  253. gridType: 'dash',
  254. gridColor: '#E5E5E5'
  255. },
  256. width: this.cWidth * this.pixelRatio,
  257. height: this.cHeight * this.pixelRatio,
  258. extra: {
  259. line: {
  260. type: 'curve',
  261. width: 2,
  262. activeType: 'hollow'
  263. },
  264. tooltip: {
  265. showBox: true,
  266. bgOpacity: 0.7
  267. }
  268. }
  269. });
  270. },
  271. touchChart(e) {
  272. if (chartInstance) {
  273. chartInstance.scrollStart(e);
  274. }
  275. },
  276. moveChart(e) {
  277. if (chartInstance) {
  278. chartInstance.scroll(e);
  279. }
  280. },
  281. touchEndChart(e) {
  282. if (chartInstance) {
  283. chartInstance.scrollEnd(e);
  284. chartInstance.showToolTip(e, {
  285. format: function(item, category) {
  286. return category + ' ' + item.name + ':' + item.data
  287. }
  288. });
  289. }
  290. },
  291. switchTab(index) {
  292. this.activeTab = index;
  293. const name = this.tabs[index]?.name;
  294. this.currentPest = name
  295. this.getPestNameDetail(name);
  296. this.setChartData();
  297. this.$nextTick(() => {
  298. this.updateChartsData(index);
  299. });
  300. },
  301. updateChartsData(index){
  302. const dayData = this.day || [];
  303. this.dayData = dayData;
  304. const pestData = this.pest[index];
  305. const lineData = {
  306. categories: dayData,
  307. series: [
  308. {
  309. name: '',
  310. data: pestData
  311. }
  312. ]
  313. };
  314. this.chartData = lineData;
  315. }
  316. }
  317. };
  318. </script>
  319. <style lang="scss" scoped>
  320. .pest-echart {
  321. margin-top: 24rpx;
  322. &__header{
  323. margin-bottom: 24rpx;
  324. }
  325. }
  326. .tab-list {
  327. width: 100%;
  328. overflow-x: scroll;
  329. white-space: nowrap;
  330. overflow-y: hidden;
  331. box-sizing: border-box;
  332. -ms-overflow-style: none;
  333. scrollbar-width: none;
  334. }
  335. .tab-item {
  336. margin-right: 16rpx;
  337. font-size: 28rpx;
  338. font-family: 'Source Han Sans CN VF', sans-serif;
  339. font-weight: 500;
  340. color: #999999;
  341. display: inline-block;
  342. box-sizing: border-box;
  343. background: #ffffff;
  344. font-family: "Source Han Sans CN VF";
  345. font-size: 28rpx;
  346. padding: 10rpx 32rpx;
  347. border-radius: 8rpx;
  348. &:last-child {
  349. margin-right: 0;
  350. }
  351. &.active {
  352. color: #0bbc58;
  353. font-weight: 700;
  354. }
  355. &:first-child.active {
  356. color: #0bbc58;
  357. }
  358. }
  359. .pest-echart__content {
  360. background: #FFFFFF;
  361. border-radius: 16rpx;
  362. padding: 0 32rpx 32rpx;
  363. }
  364. .period-section {
  365. display: flex;
  366. justify-content: space-between;
  367. padding: 24rpx;
  368. background: #ffffff;
  369. border-radius: 12rpx;
  370. }
  371. .period-item {
  372. flex: 1;
  373. display: flex;
  374. flex-direction: column;
  375. align-items: center;
  376. }
  377. .period-label {
  378. font-size: 28rpx;
  379. color: #303133;
  380. font-family: 'Source Han Sans CN VF', sans-serif;
  381. font-weight: 700;
  382. margin-bottom: 8rpx;
  383. }
  384. .period-value {
  385. font-size: 24rpx;
  386. color: #999999;
  387. font-family: 'Source Han Sans CN VF', sans-serif;
  388. font-weight: 400;
  389. }
  390. .chart-container {
  391. position: relative;
  392. width: 100%;
  393. height: 400rpx;
  394. border-radius: 12rpx;
  395. }
  396. .charts {
  397. width: 100%;
  398. height: 100%;
  399. }
  400. </style>