xypesthistoryile.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. <template>
  2. <view>
  3. <view class="status_bar"></view>
  4. <view class="" style="position: relative;top: 40px;">
  5. <view style="position: fixed;z-index: 100;top: 40px;">
  6. <uni-nav-bar @clickLeft="clickLeft" left-icon="back" title="害虫分析"></uni-nav-bar>
  7. </view>
  8. <view class="shuju_one">
  9. <view class="shuju_one_title">
  10. <view
  11. class="select-date"
  12. style="border-radius: 40rpx;"
  13. @click="showCalendar"
  14. >
  15. <text>{{ timeText }}</text>
  16. </view>
  17. </view>
  18. <view class="time-change-range">
  19. <text>选择对比年份:</text>
  20. <text class="years-text" @click="changeindex">{{ yearsText }}</text>
  21. </view>
  22. <!-- 折线图:md_lst 为 x 轴,pest_data[i] 对应 years_lst[i] 年份数据 -->
  23. <view v-if="dataloadingtf" class="canvastishi"><text class="dataloading">加载中</text></view>
  24. <view v-else-if="!canvastishiTF" class="canvastishi">暂无数据</view>
  25. <view v-else class="chart-container">
  26. <qiun-data-charts
  27. type="line"
  28. :chartData="chartData"
  29. :opts="opts"
  30. :canvas2d="true"
  31. :ontouch="true"
  32. />
  33. </view>
  34. </view>
  35. </view>
  36. <!-- 对比年份多选弹窗 -->
  37. <u-popup v-model="show1" mode="bottom" border-radius="16">
  38. <view class="year-popup">
  39. <view class="year-popup__header">
  40. <text class="year-popup__cancel" @click="show1 = false">取消</text>
  41. <text class="year-popup__title">选择对比年份</text>
  42. <text class="year-popup__confirm" @click="confirmYears">确定</text>
  43. </view>
  44. <scroll-view scroll-y class="year-popup__list">
  45. <view
  46. v-for="item in list"
  47. :key="item.value"
  48. class="year-popup__item"
  49. :class="{ active: tempYears.indexOf(item.value) > -1 }"
  50. @click="toggleYear(item.value)"
  51. >
  52. <text>{{ item.label }}</text>
  53. <u-icon
  54. v-if="tempYears.indexOf(item.value) > -1"
  55. name="checkbox-mark"
  56. color="#28AE4F"
  57. size="32"
  58. ></u-icon>
  59. </view>
  60. </scroll-view>
  61. </view>
  62. </u-popup>
  63. <u-calendar v-model="show" :mode="mode" @change="changeDate"></u-calendar>
  64. </view>
  65. </template>
  66. <script>
  67. export default {
  68. data() {
  69. return {
  70. time: '请选择时间范围',
  71. show: false,
  72. show1: false,
  73. mode: 'range',
  74. canvastishiTF: false,//暂无数据提示
  75. dataloadingtf:true,//加载中提示
  76. d_id: '',
  77. titletext: ["24小时", "近一个月", "近半年", "近一年"],
  78. page: 1,
  79. forbidden: false,
  80. pagesum: 1,
  81. years: new Date().getFullYear() - 1,
  82. selectedYears: [],//多选的对比年份(已确认)
  83. tempYears: [],//弹窗内勾选的临时年份,点确定才生效
  84. list: [],
  85. start_time: Math.floor(Date.now() / 1000) - 7*24 * 60 * 60,//开始时间 默认前7天 秒级时间戳
  86. end_time: Math.floor(Date.now() / 1000),//结束时间 默认当前时间 秒级时间戳
  87. device_type_id: '',
  88. chartData: {},
  89. // 折线图配置:每年一条曲线
  90. opts: {
  91. color: ['#0085FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'],
  92. dataLabel: false,
  93. animation: true,
  94. enableScroll: true,
  95. legend: {
  96. show: true,
  97. position: 'top',
  98. fontSize: 10,
  99. fontColor: '#666666'
  100. },
  101. xAxis: {
  102. disableGrid: true,
  103. fontSize: 9,
  104. fontColor: '#999999',
  105. itemCount: 8,
  106. scrollShow: true
  107. },
  108. yAxis: {
  109. gridType: 'dash',
  110. gridColor: '#E5E5E5',
  111. fontColor: '#999999',
  112. splitNumber: 4,
  113. min: 0,
  114. tofix: 0
  115. },
  116. extra: {
  117. line: { type: 'curve', width: 2 },
  118. tooltip: { showBox: true }
  119. }
  120. },
  121. }
  122. },
  123. computed: {
  124. // 选中年份的显示文本
  125. yearsText() {
  126. return this.selectedYears.length ? this.selectedYears.join('、') : '请选择';
  127. },
  128. // 时间范围显示文本
  129. timeText() {
  130. if (this.time !== '请选择时间范围') {
  131. return this.time;
  132. }
  133. return this.formatTs(this.start_time) + ' 至 ' + this.formatTs(this.end_time);
  134. }
  135. },
  136. methods: {
  137. showCalendar() {
  138. this.show = true
  139. },
  140. // 秒级时间戳转 YYYY-MM-DD
  141. formatTs(ts) {
  142. const d = new Date(ts * 1000);
  143. const p = n => (n < 10 ? '0' + n : '' + n);
  144. return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate());
  145. },
  146. changeDate(e){
  147. this.start_time = Math.floor(new Date(e.startDate + ' 00:00:00').getTime() / 1000)
  148. this.end_time = Math.floor(new Date(e.endDate + ' 23:59:59').getTime() / 1000)
  149. this.time = e.startDate + '至' + e.endDate
  150. this.show = false
  151. this.getChartNew()
  152. },
  153. async getChartNew(){
  154. this.dataloadingtf = true;
  155. try {
  156. const res = await this.$myRequest({
  157. url: '/api/api_gateway?method=forecast.worm_lamp.xycb_pest_chart_new',
  158. method: 'POST',
  159. data: {
  160. device_type_id: this.deviceInfo.device_type,
  161. d_id: this.deviceInfo.d_id,
  162. start_time: this.start_time,
  163. end_time: this.end_time,
  164. years: this.selectedYears.join(','),
  165. },
  166. });
  167. // $myRequest 已把响应体里的 data 字段解出来,res 即 {total_num, years_lst, pest_data, md_lst}
  168. const mdLst = res?.md_lst || [];
  169. const yearsLst = res?.years_lst || [];
  170. const pestData = res?.pest_data || [];
  171. if (mdLst.length && yearsLst.length) {
  172. this.chartData = {
  173. categories: mdLst,
  174. series: yearsLst.map((year, index) => ({
  175. name: String(year),
  176. data: pestData[index] || []
  177. }))
  178. };
  179. this.canvastishiTF = true;
  180. } else {
  181. this.chartData = {};
  182. this.canvastishiTF = false;
  183. }
  184. } catch(e) {
  185. this.chartData = {};
  186. this.canvastishiTF = false;
  187. } finally {
  188. this.dataloadingtf = false;
  189. }
  190. },
  191. changeindex() {
  192. // 打开弹窗前备份已确认的年份,取消时直接丢弃临时勾选
  193. this.tempYears = [...this.selectedYears];
  194. this.show1 = true;
  195. },
  196. // 年份多选(只改临时数组)
  197. toggleYear(value) {
  198. const index = this.tempYears.indexOf(value);
  199. if (index > -1) {
  200. this.tempYears.splice(index, 1);
  201. } else {
  202. this.tempYears.push(value);
  203. }
  204. },
  205. confirmYears() {
  206. if (!this.tempYears.length) {
  207. uni.showToast({ title: '请至少选择一个年份', icon: 'none' });
  208. return;
  209. }
  210. this.selectedYears = [...this.tempYears];
  211. this.show1 = false;
  212. this.getChartNew();
  213. },
  214. clickLeft() {
  215. uni.navigateBack({
  216. delta: 1
  217. })
  218. },
  219. },
  220. onLoad(option) {
  221. console.log(option,'optionoptionoptionoption')
  222. // this.list 前10年的时间范围(先清空,避免每次 onShow 重复追加)
  223. var now = new Date()
  224. this.list = []
  225. for (var i = 0; i < 10; i++) {
  226. this.list.push({
  227. label: now.getFullYear() - i,
  228. value: now.getFullYear() - i,
  229. })
  230. }
  231. // 默认选中当前年
  232. this.selectedYears = [this.list[0].value]
  233. this.end_time = Math.floor(+new Date() / 1000) + 1
  234. this.start_time = this.end_time - 7 * 24 * 60 * 60
  235. this.deviceInfo = option
  236. this.d_id = option.d_id
  237. this.device_id = option.device_id
  238. this.device_type_id = option.device_type
  239. this.getChartNew()
  240. },
  241. }
  242. </script>
  243. <style lang="scss">
  244. ::v-deep .u-calendar__action{
  245. display:flex;
  246. }
  247. ::v-deep .u-calendar__action__text{
  248. width:80%;
  249. text-align: center;
  250. }
  251. .time-change-range{
  252. width: 90%;
  253. margin: 10rpx auto;
  254. display: flex;
  255. align-items: center;
  256. text-align: center;
  257. > text:first-child{
  258. flex-shrink: 0;
  259. }
  260. .years-text{
  261. flex: 1;
  262. min-width: 0;
  263. overflow: hidden;
  264. white-space: nowrap;
  265. text-overflow: ellipsis;
  266. text-align: left;
  267. color: #28AE4F;
  268. font-weight: 700;
  269. }
  270. }
  271. // 年份多选弹窗
  272. .year-popup{
  273. padding: 24rpx 32rpx 48rpx;
  274. .year-popup__header{
  275. display: flex;
  276. align-items: center;
  277. justify-content: space-between;
  278. padding: 16rpx 0 24rpx;
  279. .year-popup__title{
  280. font-size: 32rpx;
  281. font-weight: 700;
  282. color: #333333;
  283. }
  284. .year-popup__cancel{
  285. font-size: 28rpx;
  286. color: #999999;
  287. }
  288. .year-popup__confirm{
  289. font-size: 28rpx;
  290. color: #28AE4F;
  291. font-weight: 700;
  292. }
  293. }
  294. .year-popup__list{
  295. max-height: 560rpx;
  296. .year-popup__item{
  297. display: flex;
  298. align-items: center;
  299. justify-content: space-between;
  300. padding: 24rpx 8rpx;
  301. font-size: 28rpx;
  302. color: #333333;
  303. border-bottom: 1rpx solid #F1F4F8;
  304. &.active{
  305. color: #28AE4F;
  306. font-weight: 700;
  307. }
  308. }
  309. }
  310. }
  311. .date-range{
  312. display: flex;
  313. text-align: center;
  314. }
  315. .chart-container{
  316. width: 100%;
  317. height: 420rpx;
  318. margin-top: 16rpx;
  319. }
  320. .shuju_one,
  321. .shuju_two {
  322. position: absolute;
  323. top: 54px;
  324. width: 90%;
  325. left: 5%;
  326. box-shadow: 0 0 10rpx #bcb9ca;
  327. padding-top: 20rpx;
  328. height: 550rpx;
  329. .canvastishi {
  330. font-size: 32rpx;
  331. position: absolute;
  332. top: 50%;
  333. left: 50%;
  334. margin-left: -64rpx;
  335. margin-top: -21rpx;
  336. .dataloading:after {
  337. overflow: hidden;
  338. display: inline-block;
  339. vertical-align: bottom;
  340. animation: ellipsis 2s infinite;
  341. content: "\2026";
  342. }
  343. @keyframes ellipsis {
  344. from {
  345. width: 2px;
  346. }
  347. to {
  348. width: 15px;
  349. }
  350. }
  351. }
  352. .shuju_one_title {
  353. width: 90%;
  354. margin: 0 auto;
  355. display: flex;
  356. .select-date{
  357. border-radius: 30rpx;
  358. border:2rpx solid #B2B2B2;
  359. width: 100%;
  360. padding: 16rpx 20rpx;
  361. color:#B2B2B2;
  362. }
  363. .tltle_text {
  364. width: 25%;
  365. border: 2rpx solid #B2B2B2;
  366. color: #B2B2B2;
  367. text-align: center;
  368. font-size: 24rpx;
  369. height: 50rpx;
  370. line-height: 50rpx;
  371. }
  372. .title_text_color {
  373. width: 25%;
  374. border: 2rpx solid #28AE4F;
  375. color: #28AE4F;
  376. text-align: center;
  377. font-size: 24rpx;
  378. height: 50rpx;
  379. line-height: 50rpx;
  380. }
  381. }
  382. }
  383. </style>