analysis_map.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. <template>
  2. <div>
  3. <header_local />
  4. <el-scrollbar ref="scrollbar" class="analysis" @scroll="scroll">
  5. <div class="head">
  6. <div class="title">地域热点</div>
  7. <div class="searchRow">
  8. <div class="searchCol searchTitle">省:</div>
  9. <div
  10. :class="{
  11. searchCol: true,
  12. searchActive: searchActive.area === optionindex,
  13. }"
  14. v-for="(optionitem, optionindex) in areaification"
  15. :key="optionindex + 'option'"
  16. v-text="optionitem.name"
  17. @click="() => clickSelect('area', optionindex)"
  18. ></div>
  19. </div>
  20. <div
  21. class="searchRow"
  22. v-if="
  23. areaification[searchActive.area] &&
  24. areaification[searchActive.area].child
  25. "
  26. >
  27. <div class="searchCol searchTitle">市:</div>
  28. <div
  29. :class="{
  30. searchCol: true,
  31. searchActive: searchActive.areaSon === optionindex,
  32. }"
  33. v-for="(optionitem, optionindex) in areaification[searchActive.area]
  34. .child"
  35. :key="optionindex + 'optionSon'"
  36. v-text="optionitem.name"
  37. @click="() => clickSelect('areaSon', optionindex)"
  38. ></div>
  39. </div>
  40. <div class="searchRow">
  41. <div class="searchCol searchTitle">分类:</div>
  42. <div
  43. :class="{
  44. searchCol: true,
  45. searchActive: searchActive.classification === optionindex,
  46. }"
  47. v-for="(optionitem, optionindex) in classification"
  48. :key="optionindex + 'option'"
  49. v-text="optionitem.name"
  50. @click="() => clickSelect('classification', optionindex)"
  51. ></div>
  52. </div>
  53. <div class="searchRow">
  54. <div class="searchCol searchTitle">时间:</div>
  55. <div
  56. :class="{
  57. searchCol: true,
  58. searchActive: searchActive.time === optionindex,
  59. }"
  60. v-for="(optionitem, optionindex) in time"
  61. :key="optionindex + 'option'"
  62. v-text="optionitem.name"
  63. @click="() => clickSelect('time', optionindex)"
  64. ></div>
  65. <div
  66. :class="{
  67. searchCol: true,
  68. searchActive: searchActive.time === -1,
  69. }"
  70. @click="() => clickSelect('time', -1)"
  71. >
  72. 自定义
  73. </div>
  74. <div class="searchCol">
  75. <el-date-picker
  76. v-model="date"
  77. :disabled="searchActive.time !== -1"
  78. @change="change"
  79. :disabled-date="disDate"
  80. type="daterange"
  81. :clearable="false"
  82. value-format="YYYY-MM-DD"
  83. range-separator="-"
  84. start-placeholder="开始时间"
  85. end-placeholder="结束时间"
  86. />
  87. </div>
  88. </div>
  89. <div class="searchRow">
  90. <div class="searchCol searchTitle">搜索:</div>
  91. <div class="searchCol">
  92. <el-input v-model="searchText" placeholder="搜索文章">
  93. <template #suffix>
  94. <el-icon @click="search"><Search /></el-icon>
  95. </template>
  96. </el-input>
  97. </div>
  98. </div>
  99. </div>
  100. <div class="body">
  101. <analysisList ref="analysisListEle" />
  102. </div>
  103. <analysisHotList
  104. @changeSearch="hotList"
  105. :province="
  106. areaification[searchActive.area]
  107. ? areaification[searchActive.area].name
  108. : ''
  109. "
  110. />
  111. <el-icon :size="45" class="upload" v-show="showUpload" @click="upload"
  112. ><Upload
  113. /></el-icon>
  114. </el-scrollbar>
  115. </div>
  116. </template>
  117. <script setup>
  118. import header_local from './components/header.vue';
  119. import dayjs from 'dayjs';
  120. import { ref, onMounted } from 'vue';
  121. import { getEconomize, getClass } from '../../api/index';
  122. import analysisList from './components/analysis_list.vue';
  123. import analysisHotList from './components/analysis_hot_list.vue';
  124. const nowTime = Date.now();
  125. const scrollbar = ref();
  126. const analysisListEle = ref();
  127. const showUpload = ref(false);
  128. const searchActive = ref({
  129. classification: 0,
  130. time: 0,
  131. area: 0,
  132. areaSon: 0,
  133. });
  134. const defaultOption = {
  135. type: 'option',
  136. name: '全部',
  137. id: 0,
  138. };
  139. const classification = ref([defaultOption]);
  140. const areaification = ref([defaultOption]);
  141. const time = [
  142. {
  143. type: 'option',
  144. time: nowTime - 86400000,
  145. name: '24小时',
  146. id: 1,
  147. },
  148. {
  149. type: 'option',
  150. time: nowTime - 172800000,
  151. name: '48小时',
  152. id: 2,
  153. },
  154. {
  155. type: 'option',
  156. time: nowTime - 604800000,
  157. name: '近7天',
  158. id: 3,
  159. },
  160. {
  161. type: 'option',
  162. time: nowTime - 2592000000,
  163. name: '近30天',
  164. id: 4,
  165. },
  166. ];
  167. const searchText = ref('');
  168. const date = ref([]);
  169. const pageSize = 10;
  170. let page = 1;
  171. onMounted(() => {
  172. getList();
  173. });
  174. getEconomize({
  175. data: {
  176. // key: 'b264662362c25150a1e6612013a7b921',
  177. // keywords: '中国',
  178. // subdistrict: 2,
  179. },
  180. }).then(r => {
  181. const list = r || [];
  182. for (let i = 0; i < list.length; i++) {
  183. const v = list[i];
  184. const city = [
  185. {
  186. type: 'option',
  187. name: '全部',
  188. id: -1,
  189. },
  190. ...v.districts.map((item, index) => {
  191. return {
  192. type: 'option',
  193. name: item.alias,
  194. id: index,
  195. };
  196. }),
  197. ];
  198. areaification.value.push({
  199. type: 'option',
  200. name: v.alias,
  201. child: city,
  202. id: i,
  203. });
  204. }
  205. });
  206. getClass({}).then(res => {
  207. const li = res || [];
  208. const l = [];
  209. for (let i = 0; i < li.length; i++) {
  210. const v = li[i];
  211. l.push({
  212. type: 'option',
  213. name: v,
  214. });
  215. }
  216. classification.value.push(...l);
  217. });
  218. const getList = () => {
  219. const search = {
  220. category:
  221. classification.value[searchActive.value.classification].name || undefined,
  222. keywords: searchText.value,
  223. page: page++,
  224. pageSize,
  225. };
  226. const sheng = areaification.value[searchActive.value.area] || {};
  227. if (sheng.name && sheng.name !== '全部') {
  228. const city =
  229. sheng.child[searchActive.value.areaSon] &&
  230. sheng.child[searchActive.value.areaSon].name;
  231. const l = [sheng.name];
  232. if (city !== '全部') l.push(city || '');
  233. search.city = l.join(',');
  234. }
  235. search.category === '全部' ? (search.category = '') : '';
  236. search.city === '全部' ? (search.city = '') : '';
  237. // 时间区间
  238. if (searchActive.value['time'] === -1) {
  239. search.start = date.value[0];
  240. search.end = date.value[1];
  241. } else {
  242. search.start = dayjs(time[searchActive.value['time']].time).format(
  243. 'YYYY-MM-DD HH:mm:ss'
  244. );
  245. search.end = dayjs(nowTime).format('YYYY-MM-DD HH:mm:ss');
  246. }
  247. analysisListEle.value.getlist(search);
  248. };
  249. const clickSelect = (select, index) => {
  250. searchActive.value[select] = index;
  251. if (index === -1) return;
  252. page = 1;
  253. getList();
  254. };
  255. const change = () => {
  256. date.value = [date.value[0] + ' 00:00:00', date.value[1] + ' 23:59:59'];
  257. page = 1;
  258. getList();
  259. };
  260. const search = () => {
  261. page = 1;
  262. getList();
  263. };
  264. const hotList = searchTextHot => {
  265. if (!searchTextHot) return;
  266. page = 1;
  267. searchText.value = searchTextHot;
  268. getList();
  269. };
  270. const scroll = e => {
  271. const height =
  272. document.querySelector('.analysis .head').offsetHeight +
  273. document.querySelector('.analysis .body').offsetHeight -
  274. document.querySelector('.analysis').offsetHeight;
  275. const scrollNum = e.scrollTop.toFixed(2) - 0;
  276. if (!showUpload.value && scrollNum > 180) showUpload.value = true;
  277. else if (scrollNum <= 180) showUpload.value = false;
  278. if (height - scrollNum > 0) return;
  279. getList();
  280. };
  281. const upload = () => {
  282. scrollbar.value.setScrollTop(0);
  283. };
  284. const nowT = Date.now();
  285. const disDate = date => {
  286. return date.getTime() > nowT;
  287. };
  288. </script>
  289. <style scoped>
  290. .analysis {
  291. height: calc(100vh - 2em);
  292. /* min-width: 1305px; */
  293. position: relative;
  294. }
  295. .analysis .head,
  296. .analysis .body {
  297. margin: 0 1em;
  298. width: calc(100% - 400px);
  299. min-width: 855px;
  300. }
  301. .analysis .body {
  302. border: 1px solid #f3f3f3;
  303. margin: 1em;
  304. }
  305. .title {
  306. font-size: 16px;
  307. font-weight: 600;
  308. height: 49px;
  309. line-height: 49px;
  310. padding-left: 8px;
  311. border-bottom: 1px solid #f5f5f5;
  312. }
  313. .searchRow {
  314. margin: 0.5em 0;
  315. }
  316. .searchCol {
  317. display: inline-block;
  318. margin: 0 0.5em;
  319. padding: 0 0.5em;
  320. height: 35px;
  321. line-height: 35px;
  322. cursor: pointer;
  323. }
  324. .searchCol:hover {
  325. color: rgb(64, 158, 255);
  326. }
  327. .searchActive {
  328. font-weight: 600;
  329. color: rgb(64, 158, 255);
  330. border-radius: 5px;
  331. background-color: rgba(64, 158, 255, 0.1);
  332. border-bottom: none;
  333. }
  334. .searchRow .searchTitle {
  335. color: #b9c0d3;
  336. }
  337. .body .el-checkbox {
  338. margin-right: 15px;
  339. }
  340. .source {
  341. color: #22ac38;
  342. }
  343. .upload {
  344. position: absolute;
  345. right: 25px;
  346. bottom: 25px;
  347. background-color: #e9e9e990;
  348. border-radius: 50%;
  349. padding: 5px;
  350. cursor: pointer;
  351. }
  352. </style>