|  | @@ -0,0 +1,310 @@
 | 
	
		
			
				|  |  | +<script lang="ts" setup>
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @Name: Table.vue
 | 
	
		
			
				|  |  | + * @Description: 竞品监控表格
 | 
	
		
			
				|  |  | + * @Author: Cheney
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import { Delete, Download, InfoFilled, Plus, Refresh, Upload } from '@element-plus/icons-vue';
 | 
	
		
			
				|  |  | +import * as api from '../api';
 | 
	
		
			
				|  |  | +import PermissionButton from '/src/components/PermissionButton/index.vue';
 | 
	
		
			
				|  |  | +import EditDrawer from './EditDrawer.vue';
 | 
	
		
			
				|  |  | +import ImportButton from '/src/components/ImportButton/index.vue';
 | 
	
		
			
				|  |  | +import VerticalDivider from '/src/components/VerticalDivider/index.vue';
 | 
	
		
			
				|  |  | +import { productColumns } from '../ColumnsTsx';
 | 
	
		
			
				|  |  | +import DataTableSlot from './DataTableSlot.vue';
 | 
	
		
			
				|  |  | +import CreateDialog from '/@/views/product-manage/product-monitor/component/createDialog.vue';
 | 
	
		
			
				|  |  | +import { ElMessage } from 'element-plus';
 | 
	
		
			
				|  |  | +import { batchDeleteRow } from '../api';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +interface Parameter {
 | 
	
		
			
				|  |  | +  country: string,
 | 
	
		
			
				|  |  | +  brand: string,
 | 
	
		
			
				|  |  | +  group: string,
 | 
	
		
			
				|  |  | +  status: string,
 | 
	
		
			
				|  |  | +  shop: string
 | 
	
		
			
				|  |  | +  asin: string,
 | 
	
		
			
				|  |  | +  sku: string,
 | 
	
		
			
				|  |  | +  platformId: string,
 | 
	
		
			
				|  |  | +  scoreNumber: string,
 | 
	
		
			
				|  |  | +  commentNumber: string,
 | 
	
		
			
				|  |  | +  displayScore: string,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const queryParameter: Parameter | undefined = inject('query-parameter');
 | 
	
		
			
				|  |  | +const { tableOptions, handlePageChange } = usePagination(fetchList);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const gridRef = ref();
 | 
	
		
			
				|  |  | +const gridOptions: any = reactive({
 | 
	
		
			
				|  |  | +  size: 'mini',
 | 
	
		
			
				|  |  | +  border: false,
 | 
	
		
			
				|  |  | +  round: true,
 | 
	
		
			
				|  |  | +  stripe: true,
 | 
	
		
			
				|  |  | +  showHeader: true,
 | 
	
		
			
				|  |  | +  currentRowHighLight: true,
 | 
	
		
			
				|  |  | +  height: '100%',
 | 
	
		
			
				|  |  | +  toolbarConfig: {
 | 
	
		
			
				|  |  | +    size: 'large',
 | 
	
		
			
				|  |  | +    custom: true,
 | 
	
		
			
				|  |  | +    slots: {
 | 
	
		
			
				|  |  | +      buttons: 'toolbar_buttons',
 | 
	
		
			
				|  |  | +      tools: 'toolbar_tools'
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  rowConfig: {
 | 
	
		
			
				|  |  | +    isHover: true
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  columnConfig: {
 | 
	
		
			
				|  |  | +    resizable: true
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  pagerConfig: {
 | 
	
		
			
				|  |  | +    total: tableOptions.value.total,
 | 
	
		
			
				|  |  | +    page: tableOptions.value.page,
 | 
	
		
			
				|  |  | +    limit: tableOptions.value.limit
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  loading: false,
 | 
	
		
			
				|  |  | +  loadingConfig: {
 | 
	
		
			
				|  |  | +    icon: 'vxe-icon-indicator roll',
 | 
	
		
			
				|  |  | +    text: '正在拼命加载中...'
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  columns: '',
 | 
	
		
			
				|  |  | +  data: ''
 | 
	
		
			
				|  |  | +});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const checkedList = ref<Set<number>>(new Set());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const editOpen = ref(false);
 | 
	
		
			
				|  |  | +const createOpen = ref(false);
 | 
	
		
			
				|  |  | +const rowData = ref({});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const dialogVisible = ref(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const templateType = ref();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +onMounted(() => {
 | 
	
		
			
				|  |  | +  fetchList();
 | 
	
		
			
				|  |  | +});
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// TODO: 删除goods
 | 
	
		
			
				|  |  | +async function fetchList() {
 | 
	
		
			
				|  |  | +  gridOptions.data = [];
 | 
	
		
			
				|  |  | +  gridOptions.columns = [];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const query = {
 | 
	
		
			
				|  |  | +    country_code: queryParameter?.country,
 | 
	
		
			
				|  |  | +    goods__brand: queryParameter?.brand,
 | 
	
		
			
				|  |  | +    goods__tag: queryParameter?.group,
 | 
	
		
			
				|  |  | +    status: queryParameter?.status,
 | 
	
		
			
				|  |  | +    shop_id: queryParameter?.shop,
 | 
	
		
			
				|  |  | +    asin: queryParameter?.asin,
 | 
	
		
			
				|  |  | +    goods__sku: queryParameter?.sku,
 | 
	
		
			
				|  |  | +    platform_number: queryParameter?.platformId,
 | 
	
		
			
				|  |  | +    goods__all_ratings: queryParameter?.scoreNumber,
 | 
	
		
			
				|  |  | +    goods__all_reviews: queryParameter?.commentNumber,
 | 
	
		
			
				|  |  | +    goods__all_score: queryParameter?.displayScore
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  await useTableData(api.getTableData, query, gridOptions);
 | 
	
		
			
				|  |  | +  await gridRef.value.loadColumn(productColumns);
 | 
	
		
			
				|  |  | +  gridOptions.showHeader = Boolean(gridOptions.data?.length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleRefresh() {
 | 
	
		
			
				|  |  | +  fetchList();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +async function handleDownload() {
 | 
	
		
			
				|  |  | +  const confirmed = await ElMessageBox.confirm('是否确认导出当前时间内所有数据项?', '警告', {
 | 
	
		
			
				|  |  | +    confirmButtonText: '确定',
 | 
	
		
			
				|  |  | +    cancelButtonText: '取消',
 | 
	
		
			
				|  |  | +    type: 'warning'
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (confirmed) {
 | 
	
		
			
				|  |  | +    gridOptions.loading = true;
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      const query = {
 | 
	
		
			
				|  |  | +        country_code: queryParameter?.country,
 | 
	
		
			
				|  |  | +        goods__brand: queryParameter?.brand,
 | 
	
		
			
				|  |  | +        goods__tag: queryParameter?.group,
 | 
	
		
			
				|  |  | +        status: queryParameter?.status,
 | 
	
		
			
				|  |  | +        shop_id: queryParameter?.shop,
 | 
	
		
			
				|  |  | +        asin: queryParameter?.asin,
 | 
	
		
			
				|  |  | +        goods__sku: queryParameter?.sku,
 | 
	
		
			
				|  |  | +        platform_number: queryParameter?.platformId,
 | 
	
		
			
				|  |  | +        goods__all_ratings: queryParameter?.scoreNumber,
 | 
	
		
			
				|  |  | +        goods__all_reviews: queryParameter?.commentNumber,
 | 
	
		
			
				|  |  | +        goods__all_score: queryParameter?.displayScore
 | 
	
		
			
				|  |  | +      };
 | 
	
		
			
				|  |  | +      const response = await api.exportData(query);
 | 
	
		
			
				|  |  | +      const url = window.URL.createObjectURL(new Blob([ response.data ]));
 | 
	
		
			
				|  |  | +      const link = document.createElement('a');
 | 
	
		
			
				|  |  | +      link.href = url;
 | 
	
		
			
				|  |  | +      link.setAttribute('download', '商品监控数据.xlsx');
 | 
	
		
			
				|  |  | +      document.body.appendChild(link);
 | 
	
		
			
				|  |  | +      link.click();
 | 
	
		
			
				|  |  | +      ElMessage.success('数据导出成功!');
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      ElMessage.error('数据导出失败,请重试!');
 | 
	
		
			
				|  |  | +      console.error(error);
 | 
	
		
			
				|  |  | +    } finally {
 | 
	
		
			
				|  |  | +      gridOptions.loading = false; // 结束加载状态
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +async function batchDelete() {
 | 
	
		
			
				|  |  | +  const ids = Array.from(checkedList.value);
 | 
	
		
			
				|  |  | +  const res = await useResponse(api.batchDeleteRow, { keys: ids });
 | 
	
		
			
				|  |  | +  checkedList.value.clear();
 | 
	
		
			
				|  |  | +  if (res.code === 2000) {
 | 
	
		
			
				|  |  | +    ElMessage.success({ message: '删除成功', plain: true });
 | 
	
		
			
				|  |  | +    handleRefresh();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function selectChangeEvent({ checked, row }: any) {
 | 
	
		
			
				|  |  | +  if (checked) {
 | 
	
		
			
				|  |  | +    checkedList.value.add(row.id); // 获取单个数据
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    checkedList.value.delete(row.id);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function selectAllChangeEvent({ checked }: any) {
 | 
	
		
			
				|  |  | +  const $grid = gridRef.value;
 | 
	
		
			
				|  |  | +  if ($grid) {
 | 
	
		
			
				|  |  | +    const records = $grid.getData(); // 获取所有数据
 | 
	
		
			
				|  |  | +    if (checked) {
 | 
	
		
			
				|  |  | +      records.forEach((item: any) => {
 | 
	
		
			
				|  |  | +        checkedList.value.add(item.id);
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      checkedList.value.clear();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleEdit(row: any) {
 | 
	
		
			
				|  |  | +  editOpen.value = true;
 | 
	
		
			
				|  |  | +  rowData.value = row;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +async function singleDelete(row: any) {
 | 
	
		
			
				|  |  | +  const res = await useResponse(api.deleteRow, row);
 | 
	
		
			
				|  |  | +  if (res.code === 2000) {
 | 
	
		
			
				|  |  | +    ElMessage.success({ message: '删除成功', plain: true });
 | 
	
		
			
				|  |  | +    handleRefresh();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleCreate() {
 | 
	
		
			
				|  |  | +  createOpen.value = true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function downloadTemplate() {
 | 
	
		
			
				|  |  | +  // console.log('111=> ');
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +defineExpose({ fetchList });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <vxe-grid ref="gridRef" v-bind="gridOptions"
 | 
	
		
			
				|  |  | +            @checkbox-change="selectChangeEvent"
 | 
	
		
			
				|  |  | +            @checkbox-all="selectAllChangeEvent">
 | 
	
		
			
				|  |  | +    <template #toolbar_buttons>
 | 
	
		
			
				|  |  | +      <div class="flex gap-2">
 | 
	
		
			
				|  |  | +        <el-popconfirm
 | 
	
		
			
				|  |  | +            :icon="InfoFilled"
 | 
	
		
			
				|  |  | +            icon-color="#626AEF"
 | 
	
		
			
				|  |  | +            title="你确定要删除此项吗?"
 | 
	
		
			
				|  |  | +            width="220"
 | 
	
		
			
				|  |  | +            @confirm="batchDelete"
 | 
	
		
			
				|  |  | +        >
 | 
	
		
			
				|  |  | +          <template #reference>
 | 
	
		
			
				|  |  | +            <PermissionButton :disabled="!checkedList.size" :icon="Delete" plain round type="danger">
 | 
	
		
			
				|  |  | +              批量删除
 | 
	
		
			
				|  |  | +            </PermissionButton>
 | 
	
		
			
				|  |  | +          </template>
 | 
	
		
			
				|  |  | +          <template #actions="{ confirm, cancel }">
 | 
	
		
			
				|  |  | +            <el-button size="small" @click="cancel">No!</el-button>
 | 
	
		
			
				|  |  | +            <el-button
 | 
	
		
			
				|  |  | +                size="small"
 | 
	
		
			
				|  |  | +                type="danger"
 | 
	
		
			
				|  |  | +                @click="confirm"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              Yes?
 | 
	
		
			
				|  |  | +            </el-button>
 | 
	
		
			
				|  |  | +          </template>
 | 
	
		
			
				|  |  | +        </el-popconfirm>
 | 
	
		
			
				|  |  | +        <PermissionButton :icon="Plus" plain round type="primary" @click="handleCreate">
 | 
	
		
			
				|  |  | +          新 增
 | 
	
		
			
				|  |  | +        </PermissionButton>
 | 
	
		
			
				|  |  | +        <div class="custom-el-input">
 | 
	
		
			
				|  |  | +          <el-select v-model="templateType" placeholder="Select" style="width: 190px">
 | 
	
		
			
				|  |  | +            <template #prefix>
 | 
	
		
			
				|  |  | +              <div class="flex items-center">
 | 
	
		
			
				|  |  | +                <el-button bg size="small" style="margin-left: -7px; font-size: 14px; border-radius: 29px;" text
 | 
	
		
			
				|  |  | +                           type="success"
 | 
	
		
			
				|  |  | +                           @click.stop="downloadTemplate">下载
 | 
	
		
			
				|  |  | +                </el-button>
 | 
	
		
			
				|  |  | +                <VerticalDivider style="margin-left: 7px" />
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +            <el-option label="商品通知模板" value="item1" />
 | 
	
		
			
				|  |  | +            <el-option label="商品模板" value="item2" />
 | 
	
		
			
				|  |  | +            <el-option label="指导价格模板" value="item3" />
 | 
	
		
			
				|  |  | +          </el-select>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <VerticalDivider class="px-1" style="margin-left: 7px;" />
 | 
	
		
			
				|  |  | +        <ImportButton :icon="Upload" :uploadFunction="api.upload" bg text>导 入</ImportButton>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </template>
 | 
	
		
			
				|  |  | +    <template #toolbar_tools>
 | 
	
		
			
				|  |  | +      <el-button circle class="toolbar-btn" @click="handleRefresh">
 | 
	
		
			
				|  |  | +        <el-icon>
 | 
	
		
			
				|  |  | +          <Refresh />
 | 
	
		
			
				|  |  | +        </el-icon>
 | 
	
		
			
				|  |  | +      </el-button>
 | 
	
		
			
				|  |  | +      <el-button circle class="mr-3 toolbar-btn" @click="handleDownload">
 | 
	
		
			
				|  |  | +        <el-icon>
 | 
	
		
			
				|  |  | +          <Download />
 | 
	
		
			
				|  |  | +        </el-icon>
 | 
	
		
			
				|  |  | +      </el-button>
 | 
	
		
			
				|  |  | +    </template>
 | 
	
		
			
				|  |  | +    <template #top>
 | 
	
		
			
				|  |  | +      <div class="mb-2"></div>
 | 
	
		
			
				|  |  | +    </template>
 | 
	
		
			
				|  |  | +    <template #pager>
 | 
	
		
			
				|  |  | +      <vxe-pager
 | 
	
		
			
				|  |  | +          v-model:currentPage="gridOptions.pagerConfig.page"
 | 
	
		
			
				|  |  | +          v-model:pageSize="gridOptions.pagerConfig.limit"
 | 
	
		
			
				|  |  | +          :total="gridOptions.pagerConfig.total"
 | 
	
		
			
				|  |  | +          class="mt-1.5"
 | 
	
		
			
				|  |  | +          @page-change="handlePageChange"
 | 
	
		
			
				|  |  | +      />
 | 
	
		
			
				|  |  | +    </template>
 | 
	
		
			
				|  |  | +    <!-- 自定义列插槽 -->
 | 
	
		
			
				|  |  | +    <template v-for="col in productColumns" #[`${col.field}`]="{ row }">
 | 
	
		
			
				|  |  | +      <DataTableSlot :key="row.id" :field="col.field" :row="row" @edit-row="handleEdit" @handle-delete="singleDelete" />
 | 
	
		
			
				|  |  | +    </template>
 | 
	
		
			
				|  |  | +  </vxe-grid>
 | 
	
		
			
				|  |  | +  <EditDrawer v-if="editOpen" v-model="editOpen" :row-data="rowData" @refresh="handleRefresh" />
 | 
	
		
			
				|  |  | +  <CreateDialog v-if="createOpen" v-model="createOpen" @refresh="fetchList" />
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style scoped>
 | 
	
		
			
				|  |  | +.toolbar-btn {
 | 
	
		
			
				|  |  | +  width: 34px;
 | 
	
		
			
				|  |  | +  height: 34px;
 | 
	
		
			
				|  |  | +  font-size: 18px
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +:deep(.custom-el-input .el-select__wrapper) {
 | 
	
		
			
				|  |  | +  border-radius: 20px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</style>
 |