index.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <script setup lang="ts">
  2. /**
  3. * @Name: index.vue
  4. * @Description: Targeting-SearchTerm 跳转页面
  5. * @Author: Cheney
  6. */
  7. import { useRoute } from 'vue-router';
  8. import { targetingColumns, searchTermColumns } from './useColumns';
  9. import { reactive, ref, onBeforeMount } from 'vue';
  10. import { storeToRefs } from 'pinia';
  11. import { usePublicData } from '/@/stores/publicData';
  12. import * as api from './api';
  13. import { debounce } from 'lodash';
  14. const publicData = usePublicData();
  15. const { dateRange } = storeToRefs(publicData);
  16. const route = useRoute();
  17. const { searchRoot } = route.query;
  18. const date = ref([dateRange.value[0], dateRange.value[1]]);
  19. const searchType = ref('BROAD');
  20. const targetingSearchRoot = ref('');
  21. const searchTermSearchRoot = ref('');
  22. const TargetingLoading = ref(false);
  23. const searchTermLoading = ref(false);
  24. const targetingOptions: any = reactive({
  25. height: 'auto',
  26. border: false,
  27. round: true,
  28. columnConfig: {
  29. resizable: true,
  30. },
  31. toolbarConfig: {
  32. custom: true,
  33. slots: {
  34. buttons: 'toolbar_buttons',
  35. },
  36. },
  37. columns: targetingColumns,
  38. data: [],
  39. });
  40. const targetingPage = reactive({
  41. total: 0,
  42. currentPage: 1,
  43. pageSize: 15,
  44. });
  45. const searchTermOptions: any = reactive({
  46. height: 'auto',
  47. border: false,
  48. round: true,
  49. columnConfig: {
  50. resizable: true,
  51. },
  52. toolbarConfig: {
  53. custom: true,
  54. slots: {
  55. buttons: 'toolbar_buttons',
  56. },
  57. },
  58. columns: searchTermColumns,
  59. data: [],
  60. });
  61. const searchTermPage = reactive({
  62. total: 0,
  63. currentPage: 1,
  64. pageSize: 15,
  65. });
  66. onBeforeMount(() => {
  67. fetchTableData();
  68. });
  69. function targetingPageChange({ currentPage, pageSize }) {
  70. targetingPage.currentPage = currentPage;
  71. targetingPage.pageSize = pageSize;
  72. fetchTargetingData();
  73. }
  74. function searchTermPageChange({ currentPage, pageSize }) {
  75. searchTermPage.currentPage = currentPage;
  76. searchTermPage.pageSize = pageSize;
  77. fetchSearchTermData();
  78. }
  79. const fetchTableData = debounce(
  80. () => {
  81. targetingPage.currentPage = 1;
  82. targetingPage.pageSize = 15;
  83. searchTermPage.currentPage = 1;
  84. searchTermPage.pageSize = 15;
  85. fetchTargetingData();
  86. fetchSearchTermData();
  87. },
  88. 500,
  89. { leading: true, trailing: false }
  90. ); // 首次调用立即执行,500毫秒内的后续调用不生效
  91. async function fetchTargetingData() {
  92. TargetingLoading.value = true;
  93. const query = {
  94. date_start: date.value[0],
  95. date_end: date.value[1],
  96. page: targetingPage.currentPage,
  97. limit: targetingPage.pageSize,
  98. search_root: targetingSearchRoot.value ? targetingSearchRoot.value : searchRoot,
  99. search_type: searchType.value, // BROAD, PHRASE, EXACT, AUTO
  100. term_type: 'TARGETING', // TARGETING, SEARCHTERM
  101. };
  102. try {
  103. const response = await api.getTargetingData(query);
  104. targetingOptions.data = response.data;
  105. targetingPage.total = response.total;
  106. } catch (error) {
  107. console.log('error=>', error);
  108. } finally {
  109. TargetingLoading.value = false;
  110. }
  111. }
  112. async function fetchSearchTermData() {
  113. searchTermLoading.value = true;
  114. const query = {
  115. date_start: date.value[0],
  116. date_end: date.value[1],
  117. page: targetingPage.currentPage,
  118. limit: targetingPage.pageSize,
  119. search_root: searchTermSearchRoot.value ? searchTermSearchRoot.value : searchRoot,
  120. search_type: searchType.value,
  121. term_type: 'SEARCHTERM',
  122. };
  123. try {
  124. const response = await api.getTargetingData(query);
  125. searchTermOptions.data = response.data;
  126. searchTermPage.total = response.total;
  127. } catch (error) {
  128. console.log('error=>', error);
  129. } finally {
  130. searchTermLoading.value = false;
  131. }
  132. }
  133. </script>
  134. <template>
  135. <div class="mx-3">
  136. <el-divider>
  137. <div class="font-bold text-xl">
  138. <!--<el-icon style="top: 3px">-->
  139. <!-- <DataAnalysis />-->
  140. <!--</el-icon>-->
  141. {{ searchRoot }}
  142. </div>
  143. </el-divider>
  144. </div>
  145. <div class="py-2 px-2.5">
  146. <el-card shadow="hover" style="border: none" body-class="flex justify-between">
  147. <div class="flex flex-wrap gap-7">
  148. <div>
  149. <span class="font-medium mr-0.5">搜索词类型 </span>
  150. <el-select v-model="searchType" placeholder="请选择" style="width: 130px">
  151. <el-option label="自动匹配" value="AUTO"></el-option>
  152. <el-option label="宽泛匹配" value="BROAD"></el-option>
  153. <el-option label="短语匹配" value="PHRASE"></el-option>
  154. <el-option label="精准匹配" value="EXACT"></el-option>
  155. </el-select>
  156. </div>
  157. <div>
  158. <span class="font-medium mr-0.5">日期 </span>
  159. <el-date-picker
  160. v-model="date"
  161. type="daterange"
  162. value-format="YYYY-MM-DD"
  163. range-separator="To"
  164. :disabled-date="(time: Date) => time > new Date()"
  165. :popper-options="{ placement: 'bottom-end' }"
  166. :clearable="false" />
  167. </div>
  168. </div>
  169. <el-button type="primary" plain @click="fetchTableData" icon="search">查询</el-button>
  170. </el-card>
  171. <el-card shadow="hover" class="mt-3" style="border: none" body-style="padding-top: 10px">
  172. <div class="w-full overflow-hidden" style="height: 950px" v-loading="TargetingLoading">
  173. <vxe-grid v-bind="targetingOptions">
  174. <template #toolbar_buttons>
  175. <span class="font-medium text-xl" style="color: #000000"> Targeting-关联关键词 </span>
  176. <el-input v-model="targetingSearchRoot" placeholder="请输入关键词回车搜索" @change="fetchTargetingData" class="ml-5" style="width: 200px;"></el-input>
  177. </template>
  178. <template v-for="col in targetingColumns" #[`${col.field}_default`]="{ row }">
  179. <div v-if="col.field === 'targeting'">
  180. <el-tooltip effect="dark" :content="row.targeting" placement="top" :show-after="300">
  181. <div class="font-medium overflow-hidden whitespace-nowrap text-ellipsis">
  182. {{ row.targeting }}
  183. </div>
  184. </el-tooltip>
  185. </div>
  186. <div v-else-if="col.field === 'ctr_1d'">
  187. <span class="font-medium"> {{ row.ctr_1d }}% </span>
  188. </div>
  189. <div v-else-if="col.field === 'cr_1d'">
  190. <span class="font-medium"> {{ row.cr_1d }}% </span>
  191. </div>
  192. <div v-else class="font-medium">
  193. {{ row[col.field] ? row[col.field] : '--' }}
  194. </div>
  195. </template>
  196. <template #pager>
  197. <vxe-pager
  198. :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
  199. v-model:current-page="targetingPage.currentPage"
  200. v-model:page-size="targetingPage.pageSize"
  201. :total="targetingPage.total"
  202. @page-change="targetingPageChange">
  203. </vxe-pager>
  204. </template>
  205. </vxe-grid>
  206. </div>
  207. </el-card>
  208. <el-card shadow="hover" class="mt-3" style="border: none" body-style="padding-top: 10px">
  209. <div class="w-full overflow-hidden" style="height: 950px" v-loading="searchTermLoading">
  210. <vxe-grid v-bind="searchTermOptions">
  211. <template #toolbar_buttons>
  212. <span class="font-medium text-xl" style="color: #000000"> SearchTerm-相关搜索结果 </span>
  213. <el-input v-model="searchTermSearchRoot" placeholder="请输入搜索词回车搜索" @change="fetchTargetingData" class="ml-5" style="width: 200px;"></el-input>
  214. </template>
  215. <template v-for="col in searchTermColumns" #[`${col.field}_default`]="{ row }">
  216. <div v-if="col.field === 'searchTerm'">
  217. <el-tooltip effect="dark" :content="row.searchTerm" placement="top" :show-after="300">
  218. <div class="font-medium overflow-hidden whitespace-nowrap text-ellipsis">
  219. {{ row.searchTerm }}
  220. </div>
  221. </el-tooltip>
  222. </div>
  223. <div v-else-if="col.field === 'ctr_1d'">
  224. <span class="font-medium"> {{ row.ctr_1d }}% </span>
  225. </div>
  226. <div v-else-if="col.field === 'cr_1d'">
  227. <span class="font-medium"> {{ row.cr_1d }}% </span>
  228. </div>
  229. <div v-else class="font-medium">
  230. {{ row[col.field] ? row[col.field] : '--' }}
  231. </div>
  232. </template>
  233. <template #pager>
  234. <vxe-pager
  235. :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
  236. v-model:current-page="searchTermPage.currentPage"
  237. v-model:page-size="searchTermPage.pageSize"
  238. :total="searchTermPage.total"
  239. @page-change="searchTermPageChange">
  240. </vxe-pager>
  241. </template>
  242. </vxe-grid>
  243. </div>
  244. </el-card>
  245. </div>
  246. </template>
  247. <style scoped>
  248. /* 修改 el-divider 的背景颜色 */
  249. :deep(.el-divider__text.is-center.el-divider__text) {
  250. background-color: #f8f8f8;
  251. }
  252. </style>