pestEchart.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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: true,
  102. gridType: 'dash',
  103. splitNumber: 5,
  104. min: 0,
  105. format: (val) => {
  106. return Math.round(val)
  107. }
  108. },
  109. extra: {
  110. line: {
  111. type: 'curve'
  112. },
  113. tooltip: {
  114. format: {
  115. name: '',
  116. value: (val) => Math.round(val)
  117. }
  118. }
  119. },
  120. legend: {
  121. },
  122. enableScroll: true
  123. },
  124. };
  125. },
  126. watch:{
  127. pest_order:{
  128. handler(val){
  129. this.tabs = [];
  130. for(let key in val){
  131. this.tabs.push({
  132. name: key,
  133. })
  134. }
  135. const name = this.tabs[0]?.name;
  136. this.currentPest = name;
  137. if(this.currentPest){
  138. this.getPestNameDetail(name);
  139. this.setChartData();
  140. }
  141. },
  142. deep: true
  143. },
  144. d_id:{
  145. handler(val){
  146. val && this.setChartData();
  147. },
  148. deep: true
  149. },
  150. endDate:{
  151. handler(val){
  152. val && this.setChartData();
  153. },
  154. deep: true
  155. },
  156. day:{
  157. handler(){
  158. this.initChart();
  159. },
  160. deep: true,
  161. immediate: true
  162. },
  163. },
  164. mounted() {
  165. this.cWidth = uni.upx2px(650);
  166. this.cHeight = uni.upx2px(400);
  167. this.pixelRatio = uni.getSystemInfoSync().pixelRatio;
  168. },
  169. methods: {
  170. async getPestNameDetail(name){
  171. try{
  172. const res = await this.$myRequest({
  173. url: '/api/pest_name_detail',
  174. method: 'POST',
  175. data: {
  176. name
  177. },
  178. });
  179. this.deviceInfo = res
  180. this.$emit('getInfo',res)
  181. }catch(err){
  182. this.$emit('getInfo',{})
  183. }
  184. },
  185. async setChartData(){
  186. if(!this.currentPest){
  187. return;
  188. }
  189. if(!this.d_id || !this.endDate){
  190. return;
  191. }
  192. const res = await this.$myRequest({
  193. url: '/api/api_gateway?method=forecast.cbd_analysis.pest_predict_time',
  194. method: 'POST',
  195. data: {
  196. model:'B',
  197. d_id: this.d_id,
  198. year: this.endDate.split('-')[0],
  199. pest: this.currentPest,
  200. },
  201. });
  202. this.periodData = {
  203. firstDate: res[0][0],
  204. peakDate: res[1][0],
  205. lastDate: res[2][0],
  206. }
  207. },
  208. initChart() {
  209. this.$nextTick(() => {
  210. this.updateChartsData(0);
  211. });
  212. },
  213. drawChart(index) {
  214. const dayData = this.day || [];
  215. this.dayData = dayData;
  216. const pestData = this.pest[index];
  217. const ctx = uni.createCanvasContext('pestChart', this);
  218. chartInstance = new uCharts({
  219. context: ctx,
  220. type: 'line',
  221. fontSize: 11,
  222. legend: {
  223. show: false
  224. },
  225. background: '#FFFFFF',
  226. pixelRatio: this.pixelRatio,
  227. animation: true,
  228. dataLabel: false,
  229. categories: dayData,
  230. series: [{
  231. name: '',
  232. data: pestData
  233. }],
  234. color: ['#0085FF'],
  235. xAxis: {
  236. disableGrid: false,
  237. boundaryGap: 'justify',
  238. axisLine: true,
  239. lineColor: '#CCCCCC',
  240. fontColor: '#999999'
  241. },
  242. yAxis: {
  243. min: 0,
  244. minInterval: 1,
  245. splitNumber: 4,
  246. axisLine: true,
  247. lineColor: '#CCCCCC',
  248. fontColor: '#999999',
  249. gridType: 'dash',
  250. gridColor: '#E5E5E5'
  251. },
  252. width: this.cWidth * this.pixelRatio,
  253. height: this.cHeight * this.pixelRatio,
  254. extra: {
  255. line: {
  256. type: 'curve',
  257. width: 2,
  258. activeType: 'hollow'
  259. },
  260. tooltip: {
  261. showBox: true,
  262. bgOpacity: 0.7
  263. }
  264. }
  265. });
  266. },
  267. touchChart(e) {
  268. if (chartInstance) {
  269. chartInstance.scrollStart(e);
  270. }
  271. },
  272. moveChart(e) {
  273. if (chartInstance) {
  274. chartInstance.scroll(e);
  275. }
  276. },
  277. touchEndChart(e) {
  278. if (chartInstance) {
  279. chartInstance.scrollEnd(e);
  280. chartInstance.showToolTip(e, {
  281. format: function(item, category) {
  282. return category + ' ' + item.name + ':' + item.data
  283. }
  284. });
  285. }
  286. },
  287. switchTab(index) {
  288. this.activeTab = index;
  289. const name = this.tabs[index]?.name;
  290. this.currentPest = name
  291. this.getPestNameDetail(name);
  292. this.setChartData();
  293. this.$nextTick(() => {
  294. this.updateChartsData(index);
  295. });
  296. },
  297. updateChartsData(index){
  298. const dayData = this.day || [];
  299. this.dayData = dayData;
  300. const pestData = this.pest[index];
  301. const lineData = {
  302. categories: dayData,
  303. series: [
  304. {
  305. name: '',
  306. data: pestData
  307. }
  308. ]
  309. };
  310. this.chartData = lineData;
  311. }
  312. }
  313. };
  314. </script>
  315. <style lang="scss" scoped>
  316. .pest-echart {
  317. margin-top: 24rpx;
  318. &__header{
  319. margin-bottom: 24rpx;
  320. }
  321. }
  322. .tab-list {
  323. width: 100%;
  324. overflow-x: scroll;
  325. white-space: nowrap;
  326. overflow-y: hidden;
  327. box-sizing: border-box;
  328. -ms-overflow-style: none;
  329. scrollbar-width: none;
  330. }
  331. .tab-item {
  332. margin-right: 16rpx;
  333. font-size: 28rpx;
  334. font-family: 'Source Han Sans CN VF', sans-serif;
  335. font-weight: 500;
  336. color: #999999;
  337. display: inline-block;
  338. box-sizing: border-box;
  339. background: #ffffff;
  340. font-family: "Source Han Sans CN VF";
  341. font-size: 28rpx;
  342. padding: 10rpx 32rpx;
  343. border-radius: 8rpx;
  344. &:last-child {
  345. margin-right: 0;
  346. }
  347. &.active {
  348. color: #0BBC58;
  349. font-weight: 700;
  350. }
  351. &:first-child.active {
  352. color: #0BBC58;
  353. }
  354. }
  355. .pest-echart__content {
  356. background: #FFFFFF;
  357. border-radius: 16rpx;
  358. padding: 0 32rpx 32rpx;
  359. }
  360. .period-section {
  361. display: flex;
  362. justify-content: space-between;
  363. padding: 24rpx;
  364. background: #ffffff;
  365. border-radius: 12rpx;
  366. }
  367. .period-item {
  368. flex: 1;
  369. display: flex;
  370. flex-direction: column;
  371. align-items: center;
  372. }
  373. .period-label {
  374. font-size: 28rpx;
  375. color: #303133;
  376. font-family: 'Source Han Sans CN VF', sans-serif;
  377. font-weight: 700;
  378. margin-bottom: 8rpx;
  379. }
  380. .period-value {
  381. font-size: 24rpx;
  382. color: #999999;
  383. font-family: 'Source Han Sans CN VF', sans-serif;
  384. font-weight: 400;
  385. }
  386. .chart-container {
  387. position: relative;
  388. width: 100%;
  389. height: 400rpx;
  390. border-radius: 12rpx;
  391. }
  392. .charts {
  393. width: 100%;
  394. height: 100%;
  395. }
  396. </style>