pestEchart.vue 8.7 KB

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