index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <script setup lang="ts">
  2. /**
  3. * @Name: index.vue
  4. * @Description: asinView
  5. * @Author: Cheney
  6. */
  7. import { Refresh, Search } from '@element-plus/icons-vue';
  8. import { reactive, ref, watch, onBeforeMount } from 'vue';
  9. import dayjs from 'dayjs';
  10. import { getTableData } from './api';
  11. import { ElMessage } from 'element-plus';
  12. import { asinColumns } from './useColumns';
  13. import WeekRangePicker from '/@/components/WeekRangePicker/index.vue';
  14. import MonthRangePicker from '/@/components/MonthRangePicker/index.vue';
  15. const weekDate = ref([
  16. dayjs().subtract(2, 'week').day(0).format('YYYY-MM-DD'),
  17. dayjs().subtract(1, 'week').day(6).format('YYYY-MM-DD'),
  18. ]);
  19. const monthDate = ref([
  20. dayjs().subtract(2, 'month').startOf('month').format('YYYY-MM-DD'),
  21. dayjs().subtract(0, 'month').startOf('month').format('YYYY-MM-DD'),
  22. ]);
  23. const reportTypeSelect = ref('weekly');
  24. const searchTermInp = ref('');
  25. const asinInp = ref('B0');
  26. const tableLoading = ref(false);
  27. const gridOptions: any = reactive({
  28. height: 'auto',
  29. border: false,
  30. round: true,
  31. columnConfig: {
  32. resizable: true,
  33. },
  34. toolbarConfig: {
  35. custom: true,
  36. slots: {
  37. buttons: 'toolbar_buttons',
  38. },
  39. },
  40. columns: asinColumns,
  41. data: [],
  42. });
  43. const tablePage = reactive({
  44. total: 0,
  45. currentPage: 1,
  46. pageSize: 20,
  47. });
  48. onBeforeMount(() => {
  49. fetchTableData();
  50. });
  51. watch([weekDate, monthDate], () => {
  52. fetchTableData();
  53. });
  54. async function handlePageChange({ currentPage, pageSize }) {
  55. tablePage.currentPage = currentPage;
  56. tablePage.pageSize = pageSize;
  57. await fetchTableData();
  58. }
  59. async function handleSelectChange() {
  60. if (!asinInp.value) {
  61. ElMessage.warning({ message: '请输入ASIN', plain: true });
  62. return;
  63. } else {
  64. await fetchTableData();
  65. }
  66. }
  67. async function refreshTable() {
  68. tablePage.currentPage = 1;
  69. tablePage.pageSize = 20;
  70. asinInp.value = '';
  71. searchTermInp.value = '';
  72. reportTypeSelect.value = 'weekly';
  73. // marketplaceSelect.value = marketplaceIdEnum[0].value;
  74. await fetchTableData();
  75. }
  76. async function fetchTableData() {
  77. tableLoading.value = true;
  78. const query = {
  79. page: tablePage.currentPage,
  80. limit: tablePage.pageSize,
  81. asin: asinInp.value,
  82. search_term: searchTermInp.value,
  83. report_type: reportTypeSelect.value,
  84. // marketplace_Ids: marketplaceSelect.value,
  85. date_start: reportTypeSelect.value == 'weekly' ? weekDate.value[0] : monthDate.value[0],
  86. date_end: reportTypeSelect.value == 'weekly' ? weekDate.value[1] : monthDate.value[1],
  87. };
  88. try {
  89. const response = await getTableData(query);
  90. tablePage.total = response.total;
  91. gridOptions.data = response.data;
  92. } catch (error) {
  93. console.error('==Error==:', error);
  94. } finally {
  95. tableLoading.value = false;
  96. }
  97. }
  98. /**
  99. * 输入框按下回车后触发
  100. */
  101. async function handleQueryChange() {
  102. if (!validateSearchTermInput(searchTermInp.value)) {
  103. if (searchTermInp.value.length == 0) {
  104. return;
  105. } else {
  106. ElMessage.warning({ message: '搜索词只能输入数字和英文字母', plain: true });
  107. return;
  108. }
  109. }
  110. if (asinInp.value.length > 0 && !validateAsinInput(asinInp.value)) {
  111. ElMessage.warning({ message: '不符合匹配规范', plain: true });
  112. return;
  113. }
  114. await fetchTableData();
  115. }
  116. /**
  117. * 校验SearchTerm输入是否合法
  118. * @param input 输入的字符串
  119. */
  120. function validateSearchTermInput(input: string) {
  121. const regex = /^[a-zA-Z0-9\s]*$/;
  122. return regex.test(input);
  123. }
  124. /**
  125. * 校验Asin输入是否合法
  126. * @param input 输入的字符串
  127. */
  128. function validateAsinInput(input: string) {
  129. const regex = /^[Bb]0[A-Za-z0-9\s]*$/i;
  130. return regex.test(input);
  131. }
  132. </script>
  133. <template>
  134. <div class="py-2 px-2.5" style="background-color: #f7f7f7">
  135. <el-card shadow="hover" class="mb-2.5" style="border: none; margin-bottom: 10px">
  136. <div class="flex justify-between">
  137. <div class="flex gap-5 flex-wrap">
  138. <div>
  139. <span class="font-medium mr-0.5">报告类型 </span>
  140. <el-select v-model="reportTypeSelect" @change="handleSelectChange" style="width: 90px">
  141. <el-option label="周度" value="weekly" />
  142. <el-option label="月度" value="monthly" />
  143. </el-select>
  144. </div>
  145. <div>
  146. <span class="font-medium mr-0.5">搜索词 </span>
  147. <el-input
  148. v-model="searchTermInp"
  149. @keyup.enter="handleQueryChange"
  150. :prefix-icon="Search"
  151. placeholder="输入后回车查询"
  152. clearable
  153. @clear="handleSelectChange"
  154. style="width: 240px" />
  155. </div>
  156. <div>
  157. <span class="font-medium mr-0.5">ASIN </span>
  158. <el-input
  159. v-model="asinInp"
  160. @keyup.enter="handleQueryChange"
  161. :prefix-icon="Search"
  162. placeholder="输入后回车查询"
  163. clearable
  164. @clear="handleSelectChange"
  165. style="width: 180px" />
  166. </div>
  167. <div>
  168. <span class="font-medium mr-0.5">报告日期 </span>
  169. <MonthRangePicker v-model="monthDate" v-if="reportTypeSelect === 'monthly'" />
  170. <WeekRangePicker v-model="weekDate" v-else />
  171. </div>
  172. </div>
  173. <div class="flex">
  174. <el-button @click="refreshTable" :icon="Refresh" circle></el-button>
  175. </div>
  176. </div>
  177. </el-card>
  178. <el-card shadow="hover" style="border: none">
  179. <div style="overflow: hidden; width: 100%; height: 950px" v-loading="tableLoading">
  180. <vxe-grid v-bind="gridOptions">
  181. <template #toolbar_buttons></template>
  182. <template v-for="col in asinColumns" #[`${col.field}_default`]="{ row }">
  183. <div v-if="col.field === 'clickedItemName'">
  184. <el-tooltip effect="dark" :content="row.clickedItemName" placement="top" :show-after="300">
  185. <div class="line-text font-medium">
  186. {{ row.clickedItemName }}
  187. </div>
  188. </el-tooltip>
  189. </div>
  190. <div v-else class="font-medium">
  191. {{ row[col.field] ? row[col.field] : '-' }}
  192. </div>
  193. </template>
  194. <template #pager>
  195. <vxe-pager
  196. :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
  197. v-model:current-page="tablePage.currentPage"
  198. v-model:page-size="tablePage.pageSize"
  199. :total="tablePage.total"
  200. @page-change="handlePageChange">
  201. </vxe-pager>
  202. </template>
  203. </vxe-grid>
  204. </div>
  205. </el-card>
  206. </div>
  207. </template>
  208. <style scoped>
  209. .line-text {
  210. white-space: nowrap;
  211. overflow: hidden;
  212. text-overflow: ellipsis;
  213. }
  214. </style>