Răsfoiți Sursa

新增特征词下载页; 新增下载组件; 优化上传组件; 优化特征词Table; 修改element-plus导入方式避免页面依赖改变重复刷新

WanGxC 8 luni în urmă
părinte
comite
415b593b46

+ 2 - 2
.env.development

@@ -4,8 +4,8 @@ ENV='development'
 
 # 本地环境接口地址
 # VITE_API_URL = 'http://127.0.0.1:8000'
-VITE_API_URL='http://192.168.1.225/'
-# VITE_API_URL = 'http://192.168.1.25:8080/'
+#VITE_API_URL='http://192.168.1.225/'
+ VITE_API_URL='http://192.168.1.25:8080/'
 # VITE_API_URL = 'http://amzads.zositechc.cn'
 
 # 是否启用按钮权限

+ 7 - 0
components.d.ts

@@ -42,6 +42,7 @@ declare module 'vue' {
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElContainer: typeof import('element-plus/es')['ElContainer']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
@@ -68,6 +69,7 @@ declare module 'vue' {
     ElRadio: typeof import('element-plus/es')['ElRadio']
     ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
     ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+    ElRate: typeof import('element-plus/es')['ElRate']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
@@ -79,7 +81,12 @@ declare module 'vue' {
     ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTag: typeof import('element-plus/es')['ElTag']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
+    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']
+    FileDload: typeof import('./src/components/FileDload/index.vue')['default']
+    FileDowlander: typeof import('./src/components/FileDowlander/index.vue')['default']
+    FileDownload: typeof import('./src/components/FileDownload/index.vue')['default']
+    FileDownloader: typeof import('./src/components/FileDowlander/FileDownloader.vue')['default']
     FileUploader: typeof import('./src/components/FileUploader/index.vue')['default']
     ForeignKey: typeof import('./src/components/foreignKey/index.vue')['default']
     IconSelector: typeof import('./src/components/iconSelector/index.vue')['default']

+ 61 - 0
src/components/FileDowlander/index.vue

@@ -0,0 +1,61 @@
+<script lang="ts" setup>/**
+ * @Name: index.vue
+ * @Description: 文件下载组件
+ * @Author: Cheney
+ */
+
+import dayjs from 'dayjs';
+import { type ButtonProps, ElMessage } from 'element-plus';
+
+
+const props = defineProps<Partial<Omit<ButtonProps, 'loading'>>>();
+const attrs = useAttrs() as any;
+
+const loading = ref(false);
+
+async function handleDownload() {
+  loading.value = true;
+  try {
+    const response = await attrs.api(attrs.query);
+
+    const blob = new Blob([ response.data ], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+
+    // 创建一个临时 URL
+    const url = window.URL.createObjectURL(blob);
+
+    // 创建一个临时的 <a> 元素并触发下载
+    const link = document.createElement('a');
+    link.href = url;
+
+    // 设置文件名
+    const currentTime = dayjs().format('YYYY-MM-DD_HH_mm_ss');
+    const filename = `${ currentTime }.xlsx`;
+
+    link.setAttribute('download', filename);
+
+    // 添加到 body, 触发点击, 然后移除
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+
+    // 释放 URL 对象
+    window.URL.revokeObjectURL(url);
+    if (response.code === 2000) ElMessage.success('文件下载成功');
+  } catch (error) {
+    console.error('==Error==:', error);
+    ElMessage.error('文件下载失败,请重试');
+  } finally {
+    loading.value = false;
+  }
+}
+</script>
+
+<template>
+  <el-button :loading="loading" v-bind="props" @click="handleDownload">
+    <slot></slot>
+  </el-button>
+</template>
+
+<style scoped>
+
+</style>

+ 1 - 4
src/components/FileUploader/index.vue

@@ -1,13 +1,10 @@
 <script lang="ts" setup>
-import { ref, useAttrs } from 'vue';
 import { type ButtonProps, ElMessage, genFileId, UploadInstance, UploadRawFile } from 'element-plus';
-import { Upload } from '@element-plus/icons-vue';
 import { SUCCESS_CODE, WARNING_CODE } from '/@/utils/requestCode';
 
 
 const props = defineProps<Partial<Omit<ButtonProps, 'loading'>>>();
 const attrs = useAttrs() as any;
-
 const emit = defineEmits([ 'upload-success', 'upload-error' ]);
 
 const upload = ref<UploadInstance>();
@@ -63,7 +60,7 @@ function handleResponse(response: any) {
       action="#"
       v-bind="attrs">
     <template #trigger>
-      <el-button :icon="Upload" :loading="loading" plain round type="warning" v-bind="props">
+      <el-button :loading="loading" plain round type="warning" v-bind="props">
         <slot></slot>
       </el-button>
     </template>

+ 1 - 1
src/main.ts

@@ -7,7 +7,7 @@ import other from '/@/utils/other'
 import '/@/assets/style/tailwind.css' // 先引入tailwind css, 以免element-plus冲突
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
-import 'element-plus/es/components/menu/style/css'	// element-plus按需导入会导致菜单样式出现问题 单独导入
+// import 'element-plus/es/components/menu/style/css'	// element-plus按需导入会导致菜单样式出现问题 单独导入
 import '/@/theme/index.scss'
 import mitt from 'mitt'
 import VueGridLayout from 'vue-grid-layout'

+ 12 - 0
src/views/featureWord/featureWordDownload/api.ts

@@ -0,0 +1,12 @@
+import { request } from '/@/utils/service';
+
+const apiPrefix = '/api/searchterm/';
+
+
+export function wordDownload(query: any) {
+  return request({
+    url: apiPrefix + 'fetworddownload/',
+    method: 'GET',
+    params: query,
+  });
+}

+ 199 - 0
src/views/featureWord/featureWordDownload/index.vue

@@ -0,0 +1,199 @@
+<script lang="ts" setup>
+/**
+ * @Name: index.vue
+ * @Description: 特征词下载页
+ * @Author: Cheney
+ */
+
+import enLocale from 'element-plus/es/locale/lang/en';
+import dayjs from 'dayjs';
+import { usePagination } from '/@/utils/usePagination';
+import FileDownLoader from '/@/components/FileDowlander/index.vue';
+import * as api from './api';
+import { useElTableData } from '/@/utils/useElTableData';
+import { Download } from '@element-plus/icons-vue';
+
+
+const date = ref(calculateLastMonthFirstWeek());
+const dateRange = ref(date.value[0]);
+const loading = ref(false);
+const { tableData, total, currentPage, pageSize, handlePageChange } = usePagination(handleQuery);
+
+const filter = ref({
+  search_term: 'zosi',
+  marketplace_Ids: 'ATVPDKIKX0DER',
+  report_type: 'WEEKLY',
+  reportDate: date
+});
+
+onMounted(() => {
+  handleQuery();
+});
+
+/**
+ * 计算上个月第一周的日期
+ */
+function calculateLastMonthFirstWeek() {
+  const lastMonth = dayjs().subtract(1, 'month');
+  const firstDayOfLastMonth = lastMonth.startOf('month');
+  const firstSundayOfLastMonth = firstDayOfLastMonth.day(0); // 获取上个月第一个星期日
+  const firstSaturdayOfLastMonth = firstSundayOfLastMonth.add(6, 'day'); // 获取对应的星期六
+
+  return [
+    firstSundayOfLastMonth.format('YYYY-MM-DD'),
+    firstSaturdayOfLastMonth.format('YYYY-MM-DD')
+  ];
+}
+
+/**
+ * 判断当前日期类型 并 计算起始和结束日期
+ */
+function calculateDate() {
+  if (filter.value.report_type === 'WEEKLY') {
+    date.value[0] = dateRange.value;
+    date.value[1] = dayjs(dateRange.value).add(6, 'day').format('YYYY-MM-DD');
+  } else if (filter.value.report_type === 'MONTHLY') {
+    const selectedMonth = dayjs(dateRange.value);
+    date.value[0] = selectedMonth.startOf('month').format('YYYY-MM-DD');
+    date.value[1] = selectedMonth.endOf('month').format('YYYY-MM-DD');
+  }
+}
+
+async function handleQuery() {
+  const query = {
+    ...filter.value,
+    date_start: date.value[0],
+    date_end: date.value[1],
+    reportDate: undefined,
+    page: currentPage.value,
+    limit: pageSize.value,
+    display: 'yes'
+  };
+  await useElTableData(api.wordDownload, query, tableData, total, loading);
+}
+
+function handleDownload(row: any) {
+  console.log("(index.vue: 77)=> row", row);
+
+  const url = row.Url;
+  const fileName = url.split('/').pop();
+
+  const link = document.createElement('a');
+  link.href = url;
+  link.download = fileName;
+
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+}
+</script>
+
+<template>
+  <div class="py-2 px-2.5">
+    <el-card body-class="flex justify-between gap-3.5" shadow="hover" style="border: none; margin-bottom: 10px">
+      <div class="flex flex-wrap gap-7">
+        <div>
+          <span class="font-bold mr-2" style="color: #303133">关键词:</span>
+          <el-input v-model="filter.search_term" style="width: 180px"></el-input>
+        </div>
+        <div>
+          <span class="font-bold mr-2" style="color: #303133">市场ID:</span>
+          <el-input v-model="filter.marketplace_Ids" style="width: 180px"></el-input>
+        </div>
+        <div>
+          <span class="font-bold mr-2" style="color: #303133">报告类型:</span>
+          <el-select v-model="filter.report_type" style="width: 100px" @change="calculateDate">
+            <el-option label="月度" value="MONTHLY"></el-option>
+            <el-option label="周度" value="WEEKLY"></el-option>
+          </el-select>
+        </div>
+        <div>
+          <span class="font-bold mr-2" style="color: #303133">报告日期:</span>
+          <el-config-provider v-if="filter.report_type === 'WEEKLY'" :locale="enLocale">
+            <el-date-picker
+                v-model="dateRange"
+                :clearable="false"
+                :disabled-date="(time: Date) => time > new Date()"
+                :format="`${date[0]} To ${date[1]}`"
+                type="week"
+                value-format="YYYY-MM-DD"
+                @change="calculateDate"
+            />
+          </el-config-provider>
+          <el-date-picker
+              v-else
+              v-model="dateRange"
+              :clearable="false"
+              :disabled-date="(time: Date) => time > new Date()"
+              :format="`${date[0]} To ${date[1]}`"
+              type="month"
+              value-format="YYYY-MM-DD"
+              @change="calculateDate"
+          />
+        </div>
+      </div>
+      <div class="flex gap-3.5">
+        <FileDownLoader
+            :api="api.wordDownload" :query="{
+              ...filter,
+              date_start: date[0],
+              date_end: date[1],
+              reportDate: undefined
+            }"
+            plain
+            round
+            type="success">
+          文件下载
+        </FileDownLoader>
+      </div>
+    </el-card>
+    <el-card shadow="hover" style="border: none; margin-bottom: 10px">
+      <el-table v-loading="loading" :data="tableData" height="600" style="width: 100%">
+        <el-table-column align="center" type="index" width="60">
+          <template #header>
+            <span>序号</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="操作时间" prop="OperateTime">
+          <template #default="{ row }">
+            <span class="font-semibold">{{ row.OperateTime }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="关键词" prop="searchTerm">
+          <template #default="{ row }">
+            <span class="font-semibold">{{ row.searchTerm }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="日期范围" prop="daterange">
+          <template #default="{ row }">
+            <span class="font-semibold">{{ row.daterange }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="表名" prop="tableName">
+          <template #default="{ row }">
+            <span class="font-semibold">{{ row.tableName }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="状态" prop="State">
+          <template #default="{ row }">
+            <span class="font-semibold">{{ row.State }}</span>
+            <el-button :icon="Download" class="ml-2" link type="success" :disabled="row.State!='success'" @click="handleDownload(row)"></el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="mt-3.5 flex justify-end">
+        <el-pagination
+            v-model:current-page="currentPage"
+            v-model:page-size="pageSize"
+            :page-sizes="[10, 20, 30, 50, 100, 200]"
+            :total="total"
+            layout="sizes, prev, pager, next, total"
+            @change="handlePageChange"/>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<style scoped>
+
+</style>

+ 0 - 1
src/views/featureWord/queryPage/FeatureWordTable.vue

@@ -6,7 +6,6 @@
  */
 
 import { usePagination } from '/@/utils/usePagination';
-import { inject, onBeforeMount, onBeforeUnmount, ref, Ref } from 'vue';
 import { useElTableData } from '/@/utils/useElTableData';
 import * as api from '/@/views/featureWord/queryPage/api';
 import emitter from '/@/utils/emitter';

+ 8 - 3
src/views/featureWord/queryPage/WeightTable.vue

@@ -1,11 +1,16 @@
 <script lang="ts" setup>
-import { inject, onBeforeMount, onBeforeUnmount, Ref, ref } from 'vue';
+/**
+ * @Name: WeightTable.vue
+ * @Description: 特征词与权重表格
+ * @Author: Cheney
+ */
+
 import { usePagination } from '/@/utils/usePagination';
 import * as api from './api';
-import { uploadFile } from './api';
 import emitter from '/@/utils/emitter';
 import { useElTableData } from '/@/utils/useElTableData';
 import FileUploader from '/@/components/FileUploader/index.vue';
+import { Upload } from '@element-plus/icons-vue';
 
 
 const { tableData, total, currentPage, pageSize, handlePageChange } = usePagination(fetchTableData);
@@ -59,6 +64,7 @@ function handleUploadError() {
       <template #extra>
         <FileUploader
             :api="api.uploadFile"
+            :icon="Upload"
             plain
             round
             type="warning"
@@ -67,7 +73,6 @@ function handleUploadError() {
             @upload-error="handleUploadError"
         >文件上传
         </FileUploader>
-        <!--<Demo type="warning" :disabled="false" plain>上传</Demo>-->
       </template>
     </el-descriptions>
     <el-card shadow="never">

+ 3 - 4
src/views/featureWord/queryPage/index.vue

@@ -5,14 +5,13 @@
  * @Author: Cheney
  */
 
-import { Download, Search } from '@element-plus/icons-vue';
+import { Search, TopRight } from '@element-plus/icons-vue';
 import WeightTable from './WeightTable.vue';
 import emitter from '/@/utils/emitter';
-import { onMounted, provide, ref } from 'vue';
 import dayjs from 'dayjs';
 import _ from 'lodash';
 import enLocale from 'element-plus/es/locale/lang/en';
-import FeatureWordTable from '/@/views/featureWord/queryPage/FeatureWordTable.vue';
+import FeatureWordTable from './FeatureWordTable.vue';
 
 
 const date = ref(calculateLastMonthFirstWeek());
@@ -121,7 +120,7 @@ function handleDownload() {
       </div>
       <div class="flex gap-3.5">
         <el-button :icon="Search" plain type="primary" @click="handleQuery">查询</el-button>
-        <el-button :icon="Download" plain round type="success" @click="handleDownload">下载管理</el-button>
+        <el-button :icon="TopRight" plain type="primary" @click="handleDownload">下载管理</el-button>
       </div>
     </el-card>
     <WeightTable/>

+ 0 - 1
src/views/searchTerm/rootWordManage/components/root-word-manage-table.vue

@@ -5,7 +5,6 @@
  * @Author: Cheney
  */
 
-// import { nextTick, onMounted, reactive, ref } from 'vue';
 import { Plus, Search, Upload } from '@element-plus/icons-vue';
 import * as api from '../api';
 import type { UploadInstance, UploadRawFile } from 'element-plus';

+ 1 - 1
vite.config.ts

@@ -35,7 +35,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
         dts: 'src/auto-imports.d.ts', // 生成 TypeScript 声明文件,
       }),
       Components({
-        resolvers: [ElementPlusResolver()],
+        // resolvers: [ElementPlusResolver()],
       }),
       compression({
         algorithm: 'gzip', // 使用 gzip 压缩