Просмотр исходного кода

新增广告位页面;页面优化;

WanGxC 1 год назад
Родитель
Сommit
29e9f4ef29

+ 1 - 1
src/views/adManage/sb/campaigns/index.vue

@@ -25,7 +25,7 @@
 				<el-progress :percentage="scope.row.percentTimeInBudget > 0 ? scope.row.percentTimeInBudget * 100 : 0" />
 			</template>
       <template #cell_campaignName="scope">
-        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+        <el-tooltip effect="dark" :content="scope.row.campaignName" placement="top">
           <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
             <div class="en-text">{{ scope.row.campaignName }}</div>
           </el-link>

+ 6 - 6
src/views/adManage/sb/index.vue

@@ -34,10 +34,10 @@ import DateRangePicker from '/@/components/DateRangePicker/index.vue'
 import Campaigns from '/@/views/adManage/sb/campaigns/index.vue'
 import Keywords from '/@/views/adManage/sb/keywords/index.vue'
 import Targets from '/@/views/adManage/sb/targets/index.vue'
-import SearchTerm from './searchTerm/index.vue'
+import SearchTerm from '/@/views/adManage/sb/searchTerm/index.vue'
 import AdvertisedProducts from './advertisedProducts/index.vue'
 import PurchasedOtherProducts from './purchasedOtherProducts/index.vue'
-import Placement from './placement/index.vue'
+import Placement from '/@/views/adManage/sb/placement/index.vue'
 
 // const shopInfo = useShopInfo()
 const publicData = usePublicData()
@@ -51,8 +51,8 @@ const tabs = [
   { label: '商品投放', name: 'Targets' },
   // { label: '推广商品', name: 'AdvertisedProducts' },
   // { label: '购买的其他商品', name: 'PurchasedOtherProducts' },
-  // { label: '搜索词', name: 'SearchTerm' },
-  // { label: '广告位', name: 'Placement' }
+  { label: '搜索词', name: 'SearchTerm' },
+  { label: '广告位', name: 'Placement' }
 ]
 const tabsComponents: any = {
   Campaigns,
@@ -60,8 +60,8 @@ const tabsComponents: any = {
   Targets,
   // AdvertisedProducts,
   // PurchasedOtherProducts,
-  // SearchTerm,
-  // Placement
+  SearchTerm,
+  Placement
 }
 
 provide('dateRange', dateRange)

+ 1 - 1
src/views/adManage/sb/keywords/crud.ts

@@ -44,7 +44,7 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         fixedHeight: false
       },
       actionbar: {
-        show: true,
+        show: false,
         buttons: {
           add: {
             show: false

+ 51 - 0
src/views/adManage/sb/placement/api.ts

@@ -0,0 +1,51 @@
+import {request} from '/@/utils/service'
+import {AddReq, DelReq, EditReq, UserPageQuery} from '@fast-crud/fast-crud'
+
+export const apiPrefix = '/api/ad_manage/sbplacement/'
+
+export function GetList(query: UserPageQuery) {
+  return request({
+    url: apiPrefix + 'list/',
+    method: 'get',
+    params: query,
+  })
+}
+
+export function GetObj(id: any) {
+  return request({
+    url: apiPrefix + id + '/',
+    method: 'get',
+  })
+}
+
+export function AddObj(obj: AddReq) {
+  return request({
+    url: apiPrefix,
+    method: 'post',
+    data: obj,
+  })
+}
+
+export function UpdateObj(obj: EditReq) {
+  return request({
+    url: apiPrefix + obj.id + '/',
+    method: 'put',
+    data: obj,
+  })
+}
+
+export function DelObj(id: DelReq) {
+  return request({
+    url: apiPrefix + id + '/',
+    method: 'delete',
+    data: {id},
+  })
+}
+
+export function getAdStructureData(query: UserPageQuery) {
+  return request({
+    url: apiPrefix + 'structure/',
+    method: 'GET',
+    params: query
+  })
+}

+ 399 - 0
src/views/adManage/sb/placement/chartComponents/adStruct.vue

@@ -0,0 +1,399 @@
+<template>
+  <div v-loading="loading">
+    <el-row :gutter="5">
+      <el-col :span="24">
+        <div style="margin-left: 45%">
+          <span style="background: #3a83f7; width: 18px; height: 10px; margin-top: 8px; display: inline-block; border-radius: 3px;"></span>
+          <TextSelector v-model="barModelValue1" :options="computedBarOptions1" @change="changeBarOne" style="margin-top: 5px; margin-left: 8px;"/>
+          <span
+              style="background: #f19a37; width: 18px; height: 10px; margin-top: 8px; margin-left: 20px; display: inline-block; border-radius: 3px;"></span>
+          <TextSelector v-model="barModelValue2" :options="computedBarOptions2" @change="changeBarTwo" style="margin-top: 5px; margin-left: 8px;"/>
+        </div>
+        <div ref="bar" style="height: 400px;"></div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, inject, computed, watch } from "vue"
+import * as echarts from "echarts"
+import TextSelector from '/@/components/TextSelector/index.vue'
+import { getAdStructureData } from "/@/views/adManage/sp/placement/api"
+import { createDisabledOptions } from '../../../utils/dropdowndisable'
+import { barOptionsMap } from "/@/views/adManage/utils/enum"
+import { useShopInfo } from '/@/stores/shopInfo'
+import { usePublicData } from "/@/stores/publicData"
+import { storeToRefs } from 'pinia'
+
+const shopInfo = useShopInfo()
+const publicData = usePublicData()
+const { dateRange } = storeToRefs(publicData)
+const { profile } = storeToRefs(shopInfo)
+let barChart = ref()
+const pie = ref()
+const bar = ref()
+const loading = ref(true)
+
+// 下拉框相关
+const barOptions1 = [
+  {
+    value: 'ACOS',
+    label: 'ACOS',
+  },
+  {
+    value: 'ROAS',
+    label: 'ROAS',
+  },
+  {
+    value: 'Spend',
+    label: '花费',
+    units: '$',
+  },
+  {
+    value: 'TotalSales',
+    label: '销售额',
+  },
+  {
+    value: 'TotalPurchases',
+    label: '订单数',
+  },
+  {
+    value: 'TotalUnitOrdered',
+    label: '销量',
+  },
+  {
+    value: 'CPC',
+    label: '点击成本'
+  },
+  {
+    value: 'CPA',
+    label: '订单成本'
+  },
+  {
+    value: 'Impression',
+    label: '曝光量',
+  },
+  {
+    value: 'Click',
+    label: '点击量',
+  },
+  {
+    value: 'qwe',
+    label: '点击率'
+  },
+  {
+    value: '转化率',
+    label: '转化率'
+  },
+  {
+    value: 'TotalSalesSameSKU',
+    label: '推广商品销售额'
+  },
+  {
+    value: 'TotalSalesOtherSKU',
+    label: '其他商品销售额'
+  },
+  {
+    value: 'TotalPurchasesSameSKU',
+    label: '推广商品订单数'
+  },
+  {
+    value: 'TotalPurchasesOtherSKU',
+    label: '其他商品订单数'
+  },
+  {
+    value: 'TotalUnitOrderedSameSKU',
+    label: '推广商品销量'
+  },
+  {
+    value: 'TotalUnitOrderedOtherSKU',
+    label: '其他商品销量'
+  },
+  {
+    value: 'TopOfSearchImpressionShare',
+    label: '搜索结果顶部展示份额'
+  },
+]
+let barModelValue1 = ref(barOptions1[0].value)
+
+const barOptions2 = [
+  {
+    value: 'ACOS',
+    label: 'ACOS',
+  },
+  {
+    value: 'ROAS',
+    label: 'ROAS',
+  },
+  {
+    value: 'Spend',
+    label: '花费',
+    units: '$',
+  },
+  {
+    value: 'TotalSales',
+    label: '销售额',
+  },
+  {
+    value: 'TotalPurchases',
+    label: '订单数',
+  },
+  {
+    value: 'TotalUnitOrdered',
+    label: '销量',
+  },
+  {
+    value: 'CPC',
+    label: '点击成本'
+  },
+  {
+    value: 'CPA',
+    label: '订单成本'
+  },
+  {
+    value: 'Impression',
+    label: '曝光量',
+  },
+  {
+    value: 'Click',
+    label: '点击量',
+  },
+  {
+    value: 'qwe',
+    label: '点击率'
+  },
+  {
+    value: '转化率',
+    label: '转化率'
+  },
+  {
+    value: 'TotalSalesSameSKU',
+    label: '推广商品销售额'
+  },
+  {
+    value: 'TotalSalesOtherSKU',
+    label: '其他商品销售额'
+  },
+  {
+    value: 'TotalPurchasesSameSKU',
+    label: '推广商品订单数'
+  },
+  {
+    value: 'TotalPurchasesOtherSKU',
+    label: '其他商品订单数'
+  },
+  {
+    value: 'TotalUnitOrderedSameSKU',
+    label: '推广商品销量'
+  },
+  {
+    value: 'TotalUnitOrderedOtherSKU',
+    label: '其他商品销量'
+  },
+  {
+    value: 'TopOfSearchImpressionShare',
+    label: '搜索结果顶部展示份额'
+  },
+]
+let barModelValue2 = ref(barOptions2[2].value)
+
+onMounted(async () => {
+  barChart = echarts.init(bar.value)
+
+  window.addEventListener('resize', resizeChart)  // 监听窗口大小变化,调整图表大小
+  setTimeout(() => {
+    resizeChart()
+  }, 0)
+
+  await initBarData()
+  initChart()
+})
+
+// 获取总数据
+let allData = null
+
+async function setAdStructureData() {
+  allData = await getAdStructureData({ startDate: dateRange.value[0], endDate: dateRange.value[1], profileId: shopInfo.profile.profile_id })
+  return allData.data
+}
+
+// 柱状图总数据
+let barData = null
+let responseData = null
+// 柱状图初始数据
+let ACOSList
+let SpendList
+let xAxisList
+let xAxisMapList
+
+async function initBarData() {
+  responseData = await setAdStructureData()
+  barData = responseData
+  // 柱状图初始化数据
+  ACOSList = barData.map(item => item.ACOS)
+  SpendList = barData.map(item => item.Spend)
+  // 将x轴映射为中文
+  xAxisList = barData.map(item => item.placement)
+  const classificationMap = {
+    'BROAD': '关键词-广泛',
+    'category': '品类',
+    'EXACT': '关键词-精准',
+    'asin': '商品',
+    'PHRASE': '关键词-词组',
+    'close-match': '紧密匹配',
+    'loose-match': '广泛匹配',
+    'substitutes': '同类商品',
+    'complements': '关联商品',
+    'top': '搜索结果顶部(首页)',
+    'rest_of_search': '搜索结果的其余位置',
+    'product_page': '商品页面'
+  }
+  xAxisMapList = xAxisList.map(item => classificationMap[item])
+  loading.value = false
+}
+
+// 重置图像
+let flag = ref()
+let option
+let option2
+
+// 点击下拉框后重新渲染柱状图
+function changeBarOne(newValue) {
+  barModelValue1.value = newValue
+  updateBarChart()
+}
+
+function changeBarTwo(newValue) {
+  barModelValue2.value = newValue
+  updateBarChart()
+}
+
+function updateBarChart() {
+  const barValues1 = barData.map(item => item[barModelValue1.value])
+  const barValues2 = barData.map(item => item[barModelValue2.value])
+
+  option.series[0].data = barValues1
+  option.series[1].data = barValues2
+  barChart.setOption(option)
+}
+
+// 监听时间变化重新渲染表格
+watch(dateRange, async () => {
+  if (dateRange.value) {
+    loading.value = true
+    const resp = await setAdStructureData()
+    updateBarChartData(resp)
+    loading.value = false
+  }
+})
+
+// 根据新数据和当前下拉框选择更新 柱状图数据
+function updateBarChartData(resp) {
+  const barValues1 = resp.map(item => item[barModelValue1.value])
+  const barValues2 = resp.map(item => item[barModelValue2.value])
+
+  option.series[0].data = barValues1
+  option.series[1].data = barValues2
+  barChart.setOption(option)
+}
+
+const computedBarOptions1 = computed(() => createDisabledOptions(barOptions1, barModelValue2.value, barModelValue1.value))
+const computedBarOptions2 = computed(() => createDisabledOptions(barOptions2, barModelValue1.value, barModelValue2.value))
+
+// 初始化图表
+function initChart() {
+  // 柱状图配置
+  option = {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow',
+        label: {
+          backgroundColor: '#6a7985'
+        }
+      }
+    },
+    // legend: {data: ['数据1', '数据2'],},
+    toolbox: {
+      feature: {
+        saveAsImage: { yAxisIndex: 'none' }
+      }
+    },
+    grid: { top: 50, right: 60, bottom: 50, left: 60 },
+    xAxis: [
+      {
+        type: 'category',
+        boundaryGap: true,
+        data: xAxisMapList,
+      },
+    ],
+    yAxis: [
+      {
+        type: 'value',
+        axisLine: {
+          show: true,
+          lineStyle: {
+            color: '#3a83f7' // 第一个 Y 轴的颜色
+          }
+        }
+      },
+      {
+        type: 'value',
+        splitLine: {
+          show: false
+        },
+        axisLine: {
+          show: true,
+          lineStyle: {
+            color: '#f19a37' // 第一个 Y 轴的颜色
+          }
+        }
+      }
+    ],
+    series: [
+      {
+        name: barOptionsMap[barModelValue1.value],
+        type: 'bar',
+        barWidth: '3%',
+        data: ACOSList,
+        yAxisIndex: 0,
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: '#3a83f7' },
+            { offset: 1, color: 'rgb(111, 209, 206)' },
+          ]),
+          // 柱状图圆角
+          borderRadius: [6, 6, 6, 6],
+        },
+      },
+      {
+        name: barOptionsMap[barModelValue2.value],
+        type: 'bar',
+        barWidth: '3%',
+        data: SpendList,
+        yAxisIndex: 1,
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: '#f19a37' },
+            { offset: 1, color: 'rgb(234,207,135)' },
+          ]),
+          // 柱状图圆角
+          borderRadius: [6, 6, 6, 6],
+        },
+      },
+    ],
+  }
+  barChart.setOption(option)
+  resizeChart()
+}
+
+function resizeChart() {
+  barChart.resize()
+}
+
+</script>
+
+<style scoped>
+
+</style>

+ 184 - 0
src/views/adManage/sb/placement/crud.tsx

@@ -0,0 +1,184 @@
+import * as api from './api'
+import {AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery} from '@fast-crud/fast-crud'
+import {inject} from 'vue'
+import {BaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
+import {parseQueryParams} from '/@/views/adManage/utils/tools'
+import XEUtils from 'xe-utils'
+
+export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  const pageRequest = async (query: UserPageQuery) => {
+    const params = parseQueryParams(context.value)
+    XEUtils.assign(query, params)
+    return await api.GetList(query)
+  }
+  const editRequest = async ({form, row}: EditReq) => {
+    form.id = row.id
+    return await api.UpdateObj(form)
+  }
+  const delRequest = async ({row}: DelReq) => {
+    return await api.DelObj(row.id)
+  }
+  const addRequest = async ({form}: AddReq) => {
+    return await api.AddObj(form)
+  }
+
+  //权限判定
+  const hasPermissions = inject('$hasPermissions')
+
+  return {
+    crudOptions: {
+      table: {
+        height: 800,
+        headerCellStyle: {
+          backgroundColor: '#f6f7fa', // 直接设置背景颜色
+          height: '20px',
+          // border: '0.5px solid #ddd',
+        },
+        cellStyle: {
+          border: 'none',
+          borderBottom: '0.5px solid #ddd',
+        },
+        showSummary: true,
+      },
+      container: {
+        fixedHeight: false
+      },
+      actionbar: {
+        show: false,
+        buttons: {
+          add: {
+            show: false
+          },
+        }
+      },
+      search: {
+        show: false
+      },
+      toolbar: {
+        buttons: {
+          search: {
+            show: true
+          },
+          compact: {
+            show: false
+          }
+        }
+      },
+      request: {
+        pageRequest,
+        addRequest,
+        editRequest,
+        delRequest,
+      },
+      rowHandle: {
+        fixed: 'right',
+        width: 80,
+        buttons: {
+          view: {
+            show: false,
+          },
+          edit: {
+            iconRight: 'Edit',
+            type: 'text',
+            text: null
+            // show: hasPermissions('dictionary:Update'),
+          },
+          remove: {
+            iconRight: 'Delete',
+            type: 'text',
+            text: null
+            // show: hasPermissions('dictionary:Delete'),
+          },
+        },
+      },
+      columns: {
+        id: {
+          title: 'ID',
+          column: {
+            show: false
+          },
+          form: {
+            show: false
+          }
+        },
+        campaignName: {
+          title: '广告活动名称',
+          column: {
+            width: '210px',
+            fixed: 'left',
+            align: 'left',
+          },
+          search: {
+            show: true,
+            component: {
+              props: {
+                clearable: true
+              }
+            }
+          },
+          form: {
+            rules: [{required: true, message: '必填项'}]
+          }
+        },
+        placement: {
+          title: '广告位',
+          column: {
+            align: 'left',
+            width: '160px',
+            fixed: 'left',
+            formatter: (row) => {
+              switch (row.value) {
+                case 'Other on-Amazon':
+                  return '其他页面'
+                case 'Product pages':
+                  return '产品页面'
+                case 'Top of search (first page)':
+                  return '首页'
+                case 'Detail Page on-Amazon':
+                  return '详细信息首页'
+                case 'Other Placements':
+                  return '其他位置'
+                default:
+                  return '--'
+              }
+            }
+          }
+        },
+        bidOptimization: {
+          title: '竞价策略',
+          column: {
+            align: 'center',
+            width: '160px',
+            formatter: (row) => {
+              switch (row.value) {
+                case 1:
+                  return '自动竞价'
+                case 0:
+                  return '自定义竞价'
+                default:
+                  return '--'
+              }
+            }
+          }
+        },
+        bidAdjustment: {
+          title: '竞价调整',
+          column: {
+            align: 'right',
+            width: '100px',
+            formatter: (row) => {
+              console.log(row.value)
+              if (row.value != null) {
+                return row.value
+              } else {
+                return '--'
+              }
+            }
+          }
+        },
+
+        ...BaseColumn
+      }
+    }
+  }
+}

+ 143 - 0
src/views/adManage/sb/placement/index.vue

@@ -0,0 +1,143 @@
+<template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <template #header-middle>
+        <el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card">
+          <el-tab-pane label="数据趋势" name="dataTendency">
+            <DataTendencyChart
+                v-if="tabActiveName === 'dataTendency'"
+                :query="queryParams"
+                :fetchCard="getCardData"
+                :fetch-line-month="getLineMonthData"
+                :fetch-line-week="getLineWeekData"
+                :fetchLine="getLineData">
+            </DataTendencyChart>
+          </el-tab-pane>
+          <el-tab-pane label="广告结构" name="adStruct" :lazy="true">
+            <AdStructChart ref="adStructChartRef"/>
+          </el-tab-pane>
+          <el-tab-pane label="散点视图" name="scatterView" :lazy="true"></el-tab-pane>
+        </el-tabs>
+      </template>
+      <template #cell_campaignName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_MissedImpressions="scope">
+        {{ scope.row.MissedImpressionsLower ?? '0' }} ~ {{ scope.row.MissedImpressionsUpper ?? '0' }}
+      </template>
+      <template #cell_MissedClicks="scope">
+        {{ scope.row.MissedClicksLower ?? '0' }} ~ {{ scope.row.MissedClicksUpper ?? '0' }}
+      </template>
+      <template #cell_MissedSales="scope">
+        {{ scope.row.MissedSalesLower ?? '0' }} ~ {{ scope.row.MissedSalesUpper ?? '0' }}
+      </template>
+
+      <template v-for="field of Object.keys(SbBaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+            :field="field"
+            :value="scope.row[field]"
+            :prev-val="scope.row[`prev${field}`]"
+            :gap-val="scope.row[`gap${field}`]"
+            :date-range="dateRange"
+            :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
+    </fs-crud>
+  </fs-page>
+</template>
+
+<script lang="ts" setup>
+import {nextTick, onMounted, ref, watch} from 'vue'
+import {FsPage, useFs} from '@fast-crud/fast-crud'
+import {createCrudOptions} from './crud'
+import {useRoute, useRouter} from 'vue-router'
+import DataTendencyChart from '/@/views/adManage/sb/chartComponents/dataTendency.vue'
+import {useShopInfo} from '/@/stores/shopInfo'
+import AdStructChart from './chartComponents/adStruct.vue'
+import { getCardData, getLineData, getLineMonthData, getLineWeekData } from '../campaigns/api'
+import {usePublicData} from '/@/stores/publicData'
+import {storeToRefs} from 'pinia'
+import {SbBaseColumn} from '/@/views/adManage/utils/commonTabColumn'
+import DataCompare from '/@/components/dataCompare/index.vue'
+
+
+const tabActiveName = ref('dataTendency')
+const shopInfo = useShopInfo()
+const publicData = usePublicData()
+const {dateRange} = storeToRefs(publicData)
+const {profile} = storeToRefs(shopInfo)
+const queryParams = ref({
+  profileId: profile.value.profile_id,
+  dateRange
+})
+const {crudBinding, crudRef, crudExpose} =  useFs({createCrudOptions, context: queryParams})
+const router = useRouter()
+const showCompare = ref(false)
+const jumpGroup = (row: any) => {
+  router.push({
+    name: 'CampaignDetail',
+    query: {id: row.id, campaignId: row.campaignId, tagsViewName: row.campaignName},
+  })
+}
+
+onMounted(() => {
+  crudExpose.doRefresh()
+})
+
+
+
+
+watch(queryParams, async () => {
+  crudExpose.doRefresh()
+}, { deep: true })
+
+</script>
+
+<style lang="scss" scoped>
+.chart-tabs {
+  margin: 5px 0;
+
+  .el-tabs__nav {
+    padding-left: 0 !important;
+  }
+}
+.campare-switch {
+  flex: none;
+}
+
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+2):nth-child(-n+4) .cell) {
+  display: none;
+}
+
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper) {
+  border: 0;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
+
+.text-range {
+  color: #808184;
+}
+</style>

+ 46 - 0
src/views/adManage/sb/searchTerm/api.ts

@@ -0,0 +1,46 @@
+import { request } from '/@/utils/service'
+import { UserPageQuery } from '@fast-crud/fast-crud'
+
+export const apiPrefix = '/api/ad_manage/sbsearchterms/'
+export function GetList(query: UserPageQuery) {
+	return request({
+		url: apiPrefix + 'list',
+		method: 'get',
+		params: query,
+	})
+}
+
+export function getCardData(query: UserPageQuery) {
+  return request({
+      url: apiPrefix + "total/",
+      method: 'GET',
+      params: query
+  })
+}
+
+export function getLineData(query: UserPageQuery) {
+  query["dateRangeType"] = "D"
+  return request({
+    url: apiPrefix + "daily/",
+    method: 'GET',
+    params: query
+  })
+}
+
+export function getLineWeekData(query: UserPageQuery) {
+  query["dateRangeType"] = "W"
+  return request({
+    url: apiPrefix + "daily/",
+    method: 'GET',
+    params: query
+  })
+}
+
+export function getLineMonthData(query: UserPageQuery) {
+  query["dateRangeType"] = "M"
+  return request({
+    url: apiPrefix + "daily/",
+    method: 'GET',
+    params: query
+  })
+}

+ 381 - 0
src/views/adManage/sb/searchTerm/crud.tsx

@@ -0,0 +1,381 @@
+import * as api from './api'
+import { dict, UserPageQuery, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
+import { inject } from 'vue'
+import {BaseColumn, SbBaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js'
+import XEUtils from 'xe-utils'
+
+export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+	const pageRequest = async (query: UserPageQuery) => {
+		const params = parseQueryParams(context.value)
+		XEUtils.assign(query, params)
+		return await api.GetList(query)
+	}
+
+	//权限判定
+	const hasPermissions = inject('$hasPermissions')
+
+	return {
+		crudOptions: {
+			table: {
+				height: 800,
+				rowKey: (row: any) => row.keywordId + row.searchTerm,
+				headerCellStyle: {
+					backgroundColor: '#f6f7fa', // 直接设置背景颜色
+					height: '20px',
+					// border: '0.5px solid #ddd',
+				},
+				cellStyle: {
+					border: 'none',
+					borderBottom: '0.5px solid #ddd',
+				},
+				showSummary: true,
+			},
+			container: {
+				fixedHeight: false,
+			},
+			actionbar: {
+				show: false,
+			},
+			search: {
+				show: false,
+			},
+			toolbar: {
+				buttons: {
+					search: {
+						show: true,
+					},
+					compact: {
+						show: false,
+					},
+				},
+			},
+			request: {
+				pageRequest,
+			},
+			rowHandle: {
+				show: false,
+			},
+			columns: {
+				query: {
+					title: '搜索词',
+					column: {
+						fixed: 'left',
+						width: 180,
+					}
+				},
+				matchType: {
+					title: '定向',
+					column: {
+						width: 180,
+						sortable: true,
+						formatter: (row) => {
+							console.log(row.value)
+							if (row.value != null) {
+								return row.value
+							} else {
+								return '--'
+							}
+						}
+					}
+				},
+				campaignName: {
+					title: '广告活动名称',
+					column: {
+						width: 180,
+					}
+				},
+				adGroupName: {
+					title: '广告组名称',
+					column: {
+						width: 180,
+					}
+				},
+				ACOS: {
+					title: 'ACOS',
+					column: {
+						align: 'right',
+						width: '120px',
+						sortable: true,
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="广告投入产出比,系统计算,广告花费/广告带来的销售额。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>ACOS</span>
+            </span>
+							)
+						}
+					}
+				},
+				ROAS: {
+					title: 'ROAS',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="广告支出回报,系统计算,广告带来的销售额/广告花费。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>ROAS</span>
+            </span>
+							)
+						}
+					}
+				},
+				Spend: {
+					title: '花费',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						border: '0.5px solid #ddd',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top"
+														content="来自亚马逊广告API,亚马逊系统会在3天内将无效点击从统计数据中删除,因此过去3天内的花费可能会有所变化">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>花费</span>
+            </span>
+							)
+						}
+					}
+				},
+				TotalSales: {
+					title: '销售额',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="
+        Seller类型店铺:<br />
+        销售额,来自亚马逊广告API。<br />
+        在点击广告后的7天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br/>出的广告商品及库存中其他商品的销售额;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单产生的销售额将从总销售额中删除。<br />
+        <br />
+        Vendor类型店铺:<br />
+        销售额,来自亚马逊广告API。<br />
+        在点击广告后的14天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的销售额;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单产生的销售额将从总销售额中删除。" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>销售额</span>
+            </span>
+							)
+						}
+					}
+				},
+				TotalPurchases: {
+					title: '订单数',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="
+        Seller类型店铺:<br />
+        订单数,来自亚马逊广告API。<br />
+        在点击广告后的7天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的订单数量;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单数量将从订单总数中删除。<br />
+        <br />
+        Vendor类型店铺:<br />
+        订单数,来自亚马逊广告API。<br />
+        在点击广告后的14天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的订单数量;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单数量将从订单总数中删除" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>订单数</span>
+            </span>
+							)
+						}
+					}
+				},
+				CPC: {
+					title: '点击成本',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '130px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="单次点击成本,系统计算,花费/点击量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击成本</span>
+            </span>
+							)
+						}
+					}
+				},
+				CPA: {
+					title: '订单成本',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '130px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="平均每笔订单的花费,系统计算,花费/广告订单量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>订单成本</span>
+            </span>
+							)
+						}
+					}
+				},
+				Impression: {
+					title: '曝光量',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="来自亚马逊广告API,广告被展示的次数。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>曝光量</span>
+            </span>
+							)
+						},
+						formatter: (row) => {
+							console.log(row.value)
+							if (row.value != null) {
+								return row.value
+							} else {
+								return '--'
+							}
+						}
+					}
+				},
+				Click: {
+					title: '点击量',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="来自亚马逊广告API,广告被点击的次数。亚马逊系统会在3天内将无效点击去除。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击量</span>
+            </span>
+							)
+						}
+					}
+				},
+				CTR: {
+					title: '点击率',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top" content="点击率,系统计算,点击量/曝光量。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击率</span>
+            </span>
+							)
+						}
+					}
+				},
+				PurchasesRate: {
+					title: '转化率',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '120px',
+						border: '0.5px solid #ddd',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top"
+														content="广告转化率,系统计算,广告订单量/点击量*100%,展示型推广vCPM成本类型的广告活动不予计算。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>转化率</span>
+            </span>
+							)
+						}
+					}
+				},
+				ViewableImpression: {
+					title: '可见曝光量',
+					column: {
+						align: 'right',
+						sortable: true,
+						width: '140px',
+						border: '0.5px solid #ddd',
+						renderHeader() {
+							return (
+									<span>
+                <el-tooltip placement="top"
+														content="来自亚马逊广告API,符合媒体评级委员会(Media Ratings Council)可见标准的曝光量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>可见曝光量</span>
+            </span>
+							)
+						},
+						formatter: (row) => {
+							console.log(row.value)
+							if (row.value != null) {
+								return row.value
+							} else {
+								return '--'
+							}
+						}
+					}
+				},
+			},
+		},
+	}
+}

+ 133 - 0
src/views/adManage/sb/searchTerm/index.vue

@@ -0,0 +1,133 @@
+<template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <template #header-middle>
+        <el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card">
+					<el-tab-pane label="数据趋势" name="dataTendency">
+						<DataTendencyChart
+							v-if="tabActiveName === 'dataTendency'"
+              :query="queryParams"
+							:fetch-card="getCardData"
+							:fetch-line="getLineData"
+							:fetch-line-month="getLineMonthData"
+							:fetch-line-week="getLineWeekData">
+						</DataTendencyChart>
+					</el-tab-pane>
+					<el-tab-pane label="散点视图" name="scatterView">
+						<div v-if="tabActiveName === 'scatterView'">敬请期待...</div>
+					</el-tab-pane>
+				</el-tabs>
+      </template>
+
+      <template #cell_query="scope">
+        <el-tooltip  effect="dark" :content="scope.row.query" placement="top">
+          <el-link :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.query }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_campaignName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName ?? '--' }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_adGroupName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.adGroupName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.adGroupName ?? '--' }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+          :field="field"
+          :value="scope.row[field]"
+          :prev-val="scope.row[`prev${field}`]"
+          :gap-val="scope.row[`gap${field}`]"
+          :date-range="dateRange"
+          :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
+		</fs-crud>
+	</fs-page>
+</template>
+
+<script lang="ts" setup>
+import {onMounted, ref, watch} from 'vue'
+import {FsPage, useFs} from '@fast-crud/fast-crud'
+import {createCrudOptions} from './crud'
+import DataTendencyChart from '/@/views/adManage/sb/chartComponents/dataTendency.vue'
+import {getCardData, getLineData, getLineMonthData, getLineWeekData} from './api'
+import {useShopInfo} from '/@/stores/shopInfo'
+import {usePublicData} from '/@/stores/publicData'
+import {storeToRefs} from 'pinia'
+import {BaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
+import DataCompare from '/@/components/dataCompare/index.vue'
+import router from '/@/router'
+
+const tabActiveName = ref("dataTendency")
+const shopInfo = useShopInfo()
+const publicData = usePublicData()
+const { dateRange } = storeToRefs(publicData)
+const { profile } = storeToRefs(shopInfo)
+const showCompare = ref(false)
+const queryParams = ref({
+  profileId: profile.value.profile_id,
+  dateRange
+})
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
+
+const jumpGroup = (row: any) => {
+  router.push({
+    name: 'CampaignDetail',
+    query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
+  })
+}
+
+onMounted(async () => {
+	crudExpose.doRefresh()
+})
+watch(
+	queryParams,
+	async () => {
+		crudExpose.doRefresh()
+	},
+  { deep: true }
+)
+
+</script>
+
+<style scoped>
+.campare-switch {
+  flex: none;
+}
+
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+2):nth-child(-n+4) .cell) {
+  display: none;
+}
+::v-deep(.el-table--border .el-table__footer-wrapper) {
+  border: none;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
+</style>

+ 1 - 9
src/views/adManage/sb/targets/crud.tsx

@@ -44,19 +44,11 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         fixedHeight: false
       },
       actionbar: {
-        show: true,
+        show: false,
         buttons: {
           add: {
             show: false
           },
-          create: {
-            text: '新建广告活动',
-            type: 'primary',
-            show: true,
-            click() {
-
-            }
-          }
         }
       },
       search: {

+ 147 - 160
src/views/adManage/sp/advertisedProducts/crud.tsx

@@ -7,168 +7,155 @@ import XEUtils from 'xe-utils'
 
 
 export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
-    const pageRequest = async (query: UserPageQuery) => {
-        const params = parseQueryParams(context.value)
-        XEUtils.assign(query, params)
-        return await api.GetList(query)
-    }
-    const editRequest = async ({form, row}: EditReq) => {
-        form.id = row.id
-        return await api.UpdateObj(form)
-    }
-    const delRequest = async ({row}: DelReq) => {
-        return await api.DelObj(row.id)
-    }
-    const addRequest = async ({form}: AddReq) => {
-        return await api.AddObj(form)
-    }
+  const pageRequest = async (query: UserPageQuery) => {
+    const params = parseQueryParams(context.value)
+    XEUtils.assign(query, params)
+    return await api.GetList(query)
+  }
+  const editRequest = async ({form, row}: EditReq) => {
+    form.id = row.id
+    return await api.UpdateObj(form)
+  }
+  const delRequest = async ({row}: DelReq) => {
+    return await api.DelObj(row.id)
+  }
+  const addRequest = async ({form}: AddReq) => {
+    return await api.AddObj(form)
+  }
 
-    //权限判定
-    const hasPermissions = inject('$hasPermissions')
+  //权限判定
+  const hasPermissions = inject('$hasPermissions')
 
-    return {
-        crudOptions: {
-            table: {
-                height: 800
-            },
-            container: {
-                fixedHeight: false
-            },
-            actionbar: {
-                show: true,
-                buttons: {
-                    add: {
-                        show: false
-                    },
-                }
-            },
-            search: {
-                show: false
-            },
-            toolbar: {
-                buttons: {
-                    search: {
-                        show: true
-                    },
-                    compact: {
-                        show: false
-                    }
-                }
-            },
-            request: {
-                pageRequest,
-                addRequest,
-                editRequest,
-                delRequest,
-            },
-            rowHandle: {
-                fixed: 'right',
-                width: 80,
-                buttons: {
-                    view: {
-                        show: false,
-                    },
-                    edit: {
-                        iconRight: 'Edit',
-                        type: 'text',
-                        text: null
-                        // show: hasPermissions('dictionary:Update'),
-                    },
-                    remove: {
-                        iconRight: 'Delete',
-                        type: 'text',
-                        text: null
-                        // show: hasPermissions('dictionary:Delete'),
-                    },
-                },
-            },
-            columns: {
-                id: {
-                    title: 'ID',
-                    column: {
-                        show: false
-                    },
-                    form: {
-                        show: false
-                    }
-                },
-                asin: {title: '商品',
-                    column: {
-                        align: 'center',
-                        fixed: 'left'
-                    },},
-                state: {
-                    title: '状态',
-                    column: {
-                        width: '90px',
-                        align: 'center'
-                    },
-                    type: 'dict-select',
-                    search: {
-                        show: true
-                    },
-                    dict: dict({
-                        data: [
-                            {value: 'PAUSED', label: '已暂停', color: 'warning'},
-                            {value: 'ENABLED', label: '投放中', color: 'success'},
-                        ]
-                    })
-                },
-                campaignName: {
-                    title: '广告活动名称',
-                    column: {
-                        width: '200px',
-                        align: 'center',
-                    },
-                    search: {
-                        show: true,
-                        component: {
-                            props: {
-                                clearable: true
-                            }
-                        }
-                    },
-                    form: {
-                        rules: [{required: true, message: '必填项'}]
-                    }
-                },
-                adGroupName: {
-                    title: '广告组名称',
-                    column: {
-                        align: 'center',
-                    },
-                },
-                bid: {
-                    title: '出价',
-                    column: {
-                        align: 'center',
-                    },
-                },
-                '标签': {},
-                Impression: {
-                    title: '曝光量',
-                    column: {
-                        align: 'center',
-                    },
-                },
-                Click: {
-                    title: '点击量',
-                    column: {
-                        align: 'center',
-                    },
-                },
-                CTR: {title: '点击率'},
-                Spend: {title: '花费'},
-                CPC: {title: '点击成本'},
-                TotalPurchases: {title: '订单数'},
-                TotalSales: {title: '销售额'},
-                TotalUnitOrdered: {title: '销量'},
-                PurchasesRate: {title: '转化率'},
-                ACOS: {title: 'ACOS'},
-                ROAS: {title: 'ROAS'},
-                CPA: {title: '订单成本'},
-                ...BaseColumn
-            }
+  return {
+    crudOptions: {
+      table: {
+        height: 800,
+        headerCellStyle: {
+          backgroundColor: '#f6f7fa', // 直接设置背景颜色
+          height: '20px',
+          // border: '0.5px solid #ddd',
+        },
+        cellStyle: {
+          border: 'none',
+          borderBottom: '0.5px solid #ddd',
+        },
+        showSummary: true,
+        },
+      container: {
+        fixedHeight: false
+      },
+      actionbar: {
+        show: false,
+        buttons: {
+          add: {
+            show: false
+          },
+        }
+      },
+      search: {
+        show: false
+      },
+      toolbar: {
+        buttons: {
+          search: {
+            show: true
+          },
+          compact: {
+            show: false
+          }
         }
+      },
+      request: {
+        pageRequest,
+        addRequest,
+        editRequest,
+        delRequest,
+      },
+      rowHandle: {
+        fixed: 'right',
+        width: 80,
+        buttons: {
+          view: {
+            show: false,
+          },
+          edit: {
+            iconRight: 'Edit',
+            type: 'text',
+            text: null
+            // show: hasPermissions('dictionary:Update'),
+          },
+          remove: {
+            iconRight: 'Delete',
+            type: 'text',
+            text: null
+            // show: hasPermissions('dictionary:Delete'),
+          },
+        },
+      },
+      columns: {
+        id: {
+          title: 'ID',
+          column: {
+            show: false
+          },
+          form: {
+            show: false
+          }
+        },
+        asin: {
+          title: '商品',
+          column: {
+            width: '130px',
+            align: 'left',
+            fixed: 'left'
+          },
+        },
+        state: {
+          title: '状态',
+          column: {
+            width: '90px',
+            align: 'center',
+            sortable: true
+          },
+          type: 'dict-select',
+          search: {
+            show: true
+          },
+          dict: dict({
+            data: [
+              {value: 'PAUSED', label: '已暂停', color: 'warning'},
+              {value: 'ENABLED', label: '投放中', color: 'success'},
+            ]
+          })
+        },
+        campaignName: {
+          title: '广告活动名称',
+          column: {
+            width: '180px',
+            align: 'left',
+          },
+          search: {
+            show: true,
+            component: {
+              props: {
+                clearable: true
+              }
+            }
+          },
+          form: {
+            rules: [{required: true, message: '必填项'}]
+          }
+        },
+        adGroupName: {
+          title: '广告组名称',
+          column: {
+            width: '180px',
+            align: 'center',
+          },
+        },
+
+        ...BaseColumn
+      }
     }
+  }
 }

+ 77 - 1
src/views/adManage/sp/advertisedProducts/index.vue

@@ -16,6 +16,43 @@
           <el-tab-pane label="散点视图" name="scatterView" :lazy="true"></el-tab-pane>
         </el-tabs>
       </template>
+
+      <template #cell_asin="scope">
+        <el-tooltip  effect="dark" :content="scope.row.asin" placement="top">
+          <el-link :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.asin }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_campaignName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_adGroupName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.adGroupName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.adGroupName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template v-for="field of Object.keys(SbBaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+            :field="field"
+            :value="scope.row[field]"
+            :prev-val="scope.row[`prev${field}`]"
+            :gap-val="scope.row[`gap${field}`]"
+            :date-range="dateRange"
+            :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
     </fs-crud>
   </fs-page>
 </template>
@@ -30,6 +67,8 @@ import {useShopInfo} from '/@/stores/shopInfo'
 import {getCardData, getLineData, getLineMonthData, getLineWeekData} from '/@/views/adManage/sp/campaigns/api'
 import {usePublicData} from '/@/stores/publicData'
 import {storeToRefs} from 'pinia'
+import {SbBaseColumn} from '/@/views/adManage/utils/commonTabColumn'
+import DataCompare from '/@/components/dataCompare/index.vue'
 
 
 const tabActiveName = ref('dataTendency')
@@ -47,6 +86,13 @@ const {crudBinding, crudRef, crudExpose} = useFs({createCrudOptions, context: qu
 const route = useRoute()
 const router = useRouter()
 const dataTendencyRef = ref()
+const showCompare = ref(false)
+const jumpGroup = (row: any) => {
+  router.push({
+    name: 'CampaignDetail',
+    query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
+  })
+}
 
 
 onMounted(() => {
@@ -71,7 +117,7 @@ watch(queryParams, async () => {
 
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
 .chart-tabs {
   margin: 5px 0;
 
@@ -79,5 +125,35 @@ watch(queryParams, async () => {
     padding-left: 0 !important;
   }
 }
+.campare-switch {
+  flex: none;
+}
+
+//::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+2):nth-child(-n+4) .cell) {
+//  display: none;
+//}
+
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper) {
+  border: 0;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
+
+.text-range {
+  color: #808184;
+}
 
 </style>

+ 295 - 227
src/views/adManage/sp/campaigns/crud.tsx

@@ -3,239 +3,307 @@ import {dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptions
 import {inject} from 'vue'
 import {BaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
 import {dynBidStrategyEnum} from '/@/views/adManage/utils/enum.js'
-import { parseQueryParams } from '/@/views/adManage/utils/tools.js'
+import {parseQueryParams} from '/@/views/adManage/utils/tools.js'
 import XEUtils from 'xe-utils'
 
-export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
-	const pageRequest = async (query: UserPageQuery) => {
-		const params = parseQueryParams(context.value)
-		XEUtils.assign(query, params)
-		return await api.GetList(query);
-	};
-	const editRequest = async ({ form, row }: EditReq) => {
-		form.id = row.id;
-		return await api.UpdateObj(form);
-	};
-	const delRequest = async ({ row }: DelReq) => {
-		return await api.DelObj(row.id);
-	};
-	const addRequest = async ({ form }: AddReq) => {
-		return await api.AddObj(form);
-	};
+export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  const pageRequest = async (query: UserPageQuery) => {
+    const params = parseQueryParams(context.value)
+    XEUtils.assign(query, params)
+    return await api.GetList(query)
+  }
+  const editRequest = async ({form, row}: EditReq) => {
+    form.id = row.id
+    return await api.UpdateObj(form)
+  }
+  const delRequest = async ({row}: DelReq) => {
+    return await api.DelObj(row.id)
+  }
+  const addRequest = async ({form}: AddReq) => {
+    return await api.AddObj(form)
+  }
 
-    //权限判定
-    const hasPermissions = inject('$hasPermissions')
+  //权限判定
+  const hasPermissions = inject('$hasPermissions')
 
-    return {
-        crudOptions: {
-            table: {
-                height: 800
-            },
-            container: {
-                fixedHeight: false
-            },
-            actionbar: {
-                show: true,
-                buttons: {
-                    add: {
-                        show: false
-                    },
-                    create: {
-                        text: '新建广告活动',
-                        type: 'primary',
-                        show: true,
-                        click() {
+  return {
+    crudOptions: {
+      table: {
+        height: 800,
+        headerCellStyle: {
+          backgroundColor: '#f6f7fa', // 直接设置背景颜色
+          height: '20px',
+          // border: '0.5px solid #ddd',
+        },
+        cellStyle: {
+          border: 'none',
+          borderBottom: '0.5px solid #ddd',
+        },
+        showSummary: true,
+      },
+      container: {
+        fixedHeight: false
+      },
+      actionbar: {
+        show: true,
+        buttons: {
+          add: {
+            show: false
+          },
+          create: {
+            text: '新建广告活动',
+            type: 'primary',
+            show: true,
+            click() {
 
-                        }
-                    }
-                }
-            },
-            search: {
-                show: false
-            },
-            toolbar: {
-                buttons: {
-                    search: {
-                        show: true
-                    },
-                    compact: {
-                        show: false
-                    }
-                }
-            },
-            request: {
-                pageRequest,
-                addRequest,
-                editRequest,
-                delRequest,
-            },
-            rowHandle: {
-                fixed: 'right',
-                width: 80,
-                buttons: {
-                    view: {
-                        show: false,
-                    },
-                    edit: {
-                        iconRight: 'Edit',
-                        type: 'text',
-                        text: null
-                        // show: hasPermissions('dictionary:Update'),
-                    },
-                    remove: {
-                        show: false
-                        // iconRight: 'Delete',
-                        // type: 'text',
-                        // text: null
-                        // show: hasPermissions('dictionary:Delete'),
-                    },
-                },
-            },
-            columns: {
-                id: {
-                    title: 'ID',
-                    column: {
-                        show: false
-                    },
-                    form: {
-                        show: false
-                    }
-                },
-                campaignName: {
-                    title: '广告活动',
-                    column: {
-                        width: '200px',
-                        fixed: 'left',
-                        align: 'center'
-                    },
-                    search: {
-                        show: true,
-                        component: {
-                            props: {
-                                clearable: true
-                            }
-                        }
-                    },
-                    form: {
-                        rules: [{required: true, message: '必填项'}]
-                    }
-                },
-                targetingType: {
-                    title: '投放类型',
-                    type: 'dict-select',
-                    search: {
-                        show: true
-                    },
-                    dict: dict({
-                        data: [
-                            {value: 'AUTO', label: '自动'},
-                            {value: 'MANUAL', label: '手动'},
-                        ]
-                    })
-                },
-                state: {
-                    title: '状态',
-                    column: {
-                        width: '90px',
-                        align: 'center'
-                    },
-                    type: 'dict-select',
-                    search: {
-                        show: true
-                    },
-                    dict: dict({
-                        data: [
-                            {value: 'PAUSED', label: '已暂停', color: 'warning'},
-                            {value: 'ENABLED', label: '投放中', color: 'success'},
-                        ]
-                    })
-                },
-                dynBidStrategy: {
-                    title: '竞价策略',
-                    form: {
-                        show: false,
-                    },
-                    column: {
-                        width: '160px'
-                    },
-                    type: 'dict-select',
-                    dict: dict({
-                        data: dynBidStrategyEnum
-                    })
-                },
-                startDate: {
-                    title: '开始日期',
-                    column: {
-                        width: '100px',
-                        align: 'center'
-                    },
-                },
-                endDate: {
-                    title: '结束日期',
-                    column: {
-                        width: '100px',
-                        align: 'center'
-                    },
-                },
-                budget: {
-                    title: '预算',
-                    column: {
-                        width: '100px',
-                        align: 'center'
-                    }
-                },
-                portfolioName: {
-                    title: '广告组合',
-                    column: {
-                        width: '100px',
-                        align: 'center'
-                    }
-                },
-                suggestedBudget: {
-                    title: '建议竞价',
-                    form: {
-                        show: false
-                    }
-                },
-                percentTimeInBudget: {
-                    title: '预算活跃均值',
-                    column: {
-                        minWidth: 150
-                    },
-                    form: {
-                        show: false
-                    }
-                },
-                MissedImpressions: {
-                    title: '预计错过的曝光',
-                    form: {
-                        show: false
-                    },
-                    column: {
-                        width: 180,
-                        align: 'center'
-                    },
-                },
-                MissedClicks: {
-                    title: '预计错过的点击',
-                    form: {
-                        show: false
-                    },
-                    column: {
-                        width: 180
-                    },
-                },
-                MissedSales: {
-                    title: '预计错过的销售',
-                    form: {
-                        show: false
-                    },
-                    column: {
-                        width: 180
-                    },
-                },
-                ...BaseColumn
             }
+          }
         }
+      },
+      search: {
+        show: false
+      },
+      toolbar: {
+        buttons: {
+          search: {
+            show: true
+          },
+          compact: {
+            show: false
+          }
+        }
+      },
+      request: {
+        pageRequest,
+        addRequest,
+        editRequest,
+        delRequest,
+      },
+      rowHandle: {
+        fixed: 'right',
+        width: 80,
+        buttons: {
+          view: {
+            show: false,
+          },
+          edit: {
+            iconRight: 'Edit',
+            type: 'text',
+            text: null
+            // show: hasPermissions('dictionary:Update'),
+          },
+          remove: {
+            show: false
+            // iconRight: 'Delete',
+            // type: 'text',
+            // text: null
+            // show: hasPermissions('dictionary:Delete'),
+          },
+        },
+      },
+      columns: {
+        id: {
+          title: 'ID',
+          column: {
+            show: false
+          },
+          form: {
+            show: false
+          }
+        },
+        campaignName: {
+          title: '广告活动名称',
+          column: {
+            width: '200px',
+            fixed: 'left',
+            align: 'left',
+            renderHeader() {
+              return (
+                  <span>
+                <el-tooltip placement="top" content="广告活动是一组使用共同广告预算的广告组。广告组用于组织商品(广告),以便您实现所需的业务目标。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>广告活动名称</span>
+            </span>
+              )
+            }
+          },
+          search: {
+            show: true,
+            component: {
+              props: {
+                clearable: true
+              }
+            }
+          },
+          form: {
+            rules: [{required: true, message: '必填项'}]
+          }
+        },
+        targetingType: {
+          title: '投放类型',
+          column: {
+            width: '100px',
+            align: 'center'
+          },
+          type: 'dict-select',
+          search: {
+            show: true
+          },
+          dict: dict({
+            data: [
+              {value: 'AUTO', label: '自动'},
+              {value: 'MANUAL', label: '手动'},
+            ]
+          })
+        },
+        state: {
+          title: '状态',
+          column: {
+            width: '90px',
+            align: 'center'
+          },
+          type: 'dict-select',
+          search: {
+            show: true
+          },
+          dict: dict({
+            data: [
+              {value: 'PAUSED', label: '已暂停', color: 'warning'},
+              {value: 'ENABLED', label: '投放中', color: 'success'},
+            ]
+          })
+        },
+        dynBidStrategy: {
+          title: '竞价策略',
+          form: {
+            show: false,
+          },
+          column: {
+            width: '160px'
+          },
+          type: 'dict-select',
+          dict: dict({
+            data: dynBidStrategyEnum
+          })
+        },
+        startDate: {
+          title: '开始日期',
+          column: {
+            width: '100px',
+            align: 'center'
+          },
+        },
+        endDate: {
+          title: '结束日期',
+          column: {
+            width: '100px',
+            align: 'center',
+            formatter: (row) => {
+              if (row.value !== null) {
+                return row.value
+              } else {
+                return '--'
+              }
+            }
+          },
+        },
+        portfolioName: {
+          title: '广告组合',
+          column: {
+            width: '130px',
+            align: 'center'
+          }
+        },
+        dailyBudget: {
+          title: '预算',
+          column: {
+            width: '100px',
+            align: 'center',
+            formatter: (row) => {
+              if (row.value !== null) {
+                return row.value
+              } else {
+                return '--'
+              }
+            }
+          }
+        },
+        suggestedBudget: {
+          title: '建议预算',
+          form: {
+            show: false
+          },
+          column: {
+            width: '100px',
+            align: 'center'
+          }
+        },
+        percentTimeInBudget: {
+          title: '预算活跃时间均值',
+          column: {
+            minWidth: 160,
+            renderHeader() {
+              return (
+                  <span>
+                <el-tooltip placement="top" content="预算覆盖每天投放时长占比的平均值。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>预算活跃时间均值</span>
+            </span>
+              )
+            }
+          },
+          form: {
+            show: false
+          }
+        },
+        MissedImpressions: {
+          title: '预计错过的曝光',
+          form: {
+            show: false
+          },
+          column: {
+            width: 180,
+            align: 'center',
+            renderHeader() {
+              return (
+                  <span>
+                <el-tooltip placement="top" content="平均每笔订单的花费,系统计算,花费/广告订单量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>订单成本</span>
+            </span>
+              )
+            }
+          },
+        },
+        MissedClicks: {
+          title: '预计错过的点击',
+          form: {
+            show: false
+          },
+          column: {
+            width: 180
+          },
+        },
+        MissedSales: {
+          title: '预计错过的销售',
+          form: {
+            show: false
+          },
+          column: {
+            width: 180
+          },
+        },
+        ...BaseColumn
+      }
     }
+  }
 }

+ 93 - 70
src/views/adManage/sp/campaigns/index.vue

@@ -1,101 +1,124 @@
 <template>
-	<fs-page class="fs-page-custom">
-		<fs-crud ref="crudRef" v-bind="crudBinding">
-			<template #header-middle>
-				<el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card">
-					<el-tab-pane label="数据趋势" name="dataTendency">
-						<DataTendencyChart
-							v-if="tabActiveName === 'dataTendency'"
-							:query="queryParams"
-							:fetchCard="getCardData"
-							:fetchLine="getLineData"
-							:fetch-line-month="getLineMonthData"
-							:fetch-line-week="getLineWeekData">
-						</DataTendencyChart>
-					</el-tab-pane>
-					<el-tab-pane label="广告结构" name="adStruct">
-						<AdStructChart v-if="tabActiveName === 'adStruct'" />
-					</el-tab-pane>
-					<el-tab-pane label="散点视图" name="scatterView">
-						<div v-if="tabActiveName === 'scatterView'">散点视图</div>
-					</el-tab-pane>
-				</el-tabs>
-			</template>
-			<template #cell_percentTimeInBudget="scope">
-				<el-progress :percentage="scope.row.percentTimeInBudget > 0 ? scope.row.percentTimeInBudget * 100 : 0" />
-			</template>
-			<template #cell_campaignName="scope">
-				<el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">{{ scope.row.campaignName }}</el-link>
-			</template>
-			<template #cell_MissedImpressions="scope">
-				{{ scope.row.MissedImpressionsLower ?? '0' }} ~ {{ scope.row.MissedImpressionsUpper ?? '0' }}
-			</template>
-			<template #cell_MissedClicks="scope"> {{ scope.row.MissedClicksLower ?? '0' }} ~ {{ scope.row.MissedClicksUpper ?? '0' }} </template>
-			<template #cell_MissedSales="scope"> {{ scope.row.MissedSalesLower ?? '0' }} ~ {{ scope.row.MissedSalesUpper ?? '0' }} </template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <template #header-middle>
+        <el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card">
+          <el-tab-pane label="数据趋势" name="dataTendency">
+            <DataTendencyChart
+                v-if="tabActiveName === 'dataTendency'"
+                :query="queryParams"
+                :fetchCard="getCardData"
+                :fetchLine="getLineData"
+                :fetch-line-month="getLineMonthData"
+                :fetch-line-week="getLineWeekData">
+            </DataTendencyChart>
+          </el-tab-pane>
+          <el-tab-pane label="广告结构" name="adStruct">
+            <AdStructChart v-if="tabActiveName === 'adStruct'"/>
+          </el-tab-pane>
+          <el-tab-pane label="散点视图" name="scatterView">
+            <div v-if="tabActiveName === 'scatterView'">散点视图</div>
+          </el-tab-pane>
+        </el-tabs>
+      </template>
+      <template #cell_percentTimeInBudget="scope">
+        <el-progress :percentage="scope.row.percentTimeInBudget > 0 ? scope.row.percentTimeInBudget * 100 : 0"/>
+      </template>
+      <template #cell_campaignName="scope">
+        <el-tooltip effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_MissedImpressions="scope">
+        {{ scope.row.MissedImpressionsLower ?? '0' }} ~ {{ scope.row.MissedImpressionsUpper ?? '0' }}
+      </template>
+      <template #cell_MissedClicks="scope"> {{ scope.row.MissedClicksLower ?? '0' }} ~ {{ scope.row.MissedClicksUpper ?? '0' }}</template>
+      <template #cell_MissedSales="scope"> {{ scope.row.MissedSalesLower ?? '0' }} ~ {{ scope.row.MissedSalesUpper ?? '0' }}</template>
 
-			<template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">
-				<DataCompare
-          :field="field"
-          :value="scope.row[field]"
-          :prev-val="scope.row[`prev${field}`]"
-          :gap-val="scope.row[`gap${field}`]"
-          :date-range="dateRange"
-          :show-compare="showCompare"/>
-			</template>
-			<template #toolbar-left>
-				<div class="campare-switch">
-					<span>数据对比 </span>
-					<el-switch v-model="showCompare" size="small" />
-				</div>
-			</template>
-		</fs-crud>
-	</fs-page>
+      <template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+            :field="field"
+            :value="scope.row[field]"
+            :prev-val="scope.row[`prev${field}`]"
+            :gap-val="scope.row[`gap${field}`]"
+            :date-range="dateRange"
+            :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small"/>
+        </div>
+      </template>
+    </fs-crud>
+  </fs-page>
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, computed, watch, onBeforeMount } from 'vue'
-import { useFs, FsPage } from '@fast-crud/fast-crud'
-import { createCrudOptions } from './crud'
-import { useShopInfo } from '/@/stores/shopInfo'
-import { usePublicData } from '/@/stores/publicData'
-import { storeToRefs } from 'pinia'
-import { useRoute, useRouter } from 'vue-router'
+import {ref, onMounted, computed, watch, onBeforeMount} from 'vue'
+import {useFs, FsPage} from '@fast-crud/fast-crud'
+import {createCrudOptions} from './crud'
+import {useShopInfo} from '/@/stores/shopInfo'
+import {usePublicData} from '/@/stores/publicData'
+import {storeToRefs} from 'pinia'
+import {useRoute, useRouter} from 'vue-router'
 import AdStructChart from './chartComponents/adStruct.vue'
 import DataTendencyChart from '/@/views/adManage/sp/chartComponents/dataTendency.vue'
-import { getCardData, getLineData, getLineMonthData, getLineWeekData } from './api'
-import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
+import {getCardData, getLineData, getLineMonthData, getLineWeekData} from './api'
+import {BaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
 import DataCompare from '/@/components/dataCompare/index.vue'
 
 const tabActiveName = ref('dataTendency')
 const shopInfo = useShopInfo()
 const publicData = usePublicData()
-const { dateRange } = storeToRefs(publicData)
-const { profile } = storeToRefs(shopInfo)
+const {dateRange} = storeToRefs(publicData)
+const {profile} = storeToRefs(shopInfo)
 const queryParams = ref({
   profileId: profile.value.profile_id,
   dateRange
 })
-const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
+const {crudBinding, crudRef, crudExpose} = useFs({createCrudOptions, context: queryParams})
 const router = useRouter()
 const showCompare = ref(false)
 
 onMounted(async () => {
-	crudExpose.doRefresh()
+  crudExpose.doRefresh()
 })
 const jumpGroup = (row: any) => {
-	router.push({
-		name: 'CampaignDetail',
-		query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
-	})
+  router.push({
+    name: 'CampaignDetail',
+    query: {campaignId: row.campaignId, tagsViewName: row.campaignName},
+  })
 }
 
 watch(queryParams, async () => {
-	crudExpose.doRefresh()
-}, { deep: true })
+  crudExpose.doRefresh()
+}, {deep: true})
 </script>
 
 <style lang="scss" scoped>
 .campare-switch {
-	flex: none;
+  flex: none;
+}
+
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+3):nth-child(-n+10) .cell) {
+  display: none;
+}
+::v-deep(.el-table--border .el-table__footer-wrapper) {
+  border: none;
+}
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
 }
 </style>

+ 1 - 1
src/views/adManage/sp/keywords/crud.tsx

@@ -36,7 +36,7 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         fixedHeight: false
       },
       actionbar: {
-        show: true,
+        show: false,
         buttons: {
           add: {
             show: false

+ 21 - 24
src/views/adManage/sp/placement/crud.tsx

@@ -28,7 +28,17 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
   return {
     crudOptions: {
       table: {
-        height: 800
+        height: 800,
+        headerCellStyle: {
+          backgroundColor: '#f6f7fa', // 直接设置背景颜色
+          height: '20px',
+          // border: '0.5px solid #ddd',
+        },
+        cellStyle: {
+          border: 'none',
+          borderBottom: '0.5px solid #ddd',
+        },
+        showSummary: true,
       },
       container: {
         fixedHeight: false
@@ -151,32 +161,19 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         bidAdjustment: {
           title: '竞价调整',
           column: {
-            align: 'center',
+            align: 'right',
             width: '100px',
+            formatter: (row) => {
+              console.log(row.value)
+              if (row.value != null) {
+                return row.value
+              } else {
+                return '--'
+              }
+            }
           }
         },
-        Impression: {
-          title: '曝光量',
-          column: {
-            align: 'center',
-          },
-        },
-        Click: {
-          title: '点击量',
-          column: {
-            align: 'center',
-          },
-        },
-        CTR: {title: '点击率', column: {align: 'center'}},
-        Spend: {title: '花费', column: {align: 'center'}},
-        CPC: {title: '点击成本', column: {align: 'center'}},
-        TotalPurchases: {title: '订单数', column: {align: 'center'}},
-        TotalSales: {title: '销售额', column: {align: 'center'}},
-        TotalUnitOrdered: {title: '销量', column: {align: 'center'}},
-        PurchasesRate: {title: '转化率', column: {align: 'center'}},
-        ACOS: {title: 'ACOS', column: {align: 'center'}},
-        ROAS: {title: 'ROAS', column: {align: 'center'}},
-        CPA: {title: '订单成本', column: {align: 'center'}},
+
         ...BaseColumn
       }
     }

+ 61 - 9
src/views/adManage/sp/placement/index.vue

@@ -20,7 +20,11 @@
         </el-tabs>
       </template>
       <template #cell_campaignName="scope">
-        <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">{{ scope.row.campaignName }}</el-link>
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
       </template>
       <template #cell_MissedImpressions="scope">
         {{ scope.row.MissedImpressionsLower ?? '0' }} ~ {{ scope.row.MissedImpressionsUpper ?? '0' }}
@@ -31,6 +35,22 @@
       <template #cell_MissedSales="scope">
         {{ scope.row.MissedSalesLower ?? '0' }} ~ {{ scope.row.MissedSalesUpper ?? '0' }}
       </template>
+
+      <template v-for="field of Object.keys(SbBaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+            :field="field"
+            :value="scope.row[field]"
+            :prev-val="scope.row[`prev${field}`]"
+            :gap-val="scope.row[`gap${field}`]"
+            :date-range="dateRange"
+            :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
     </fs-crud>
   </fs-page>
 </template>
@@ -46,6 +66,8 @@ import AdStructChart from './chartComponents/adStruct.vue'
 import { getCardData, getLineData, getLineMonthData, getLineWeekData } from '../campaigns/api'
 import {usePublicData} from '/@/stores/publicData'
 import {storeToRefs} from 'pinia'
+import {SbBaseColumn} from '/@/views/adManage/utils/commonTabColumn'
+import DataCompare from '/@/components/dataCompare/index.vue'
 
 
 const tabActiveName = ref('dataTendency')
@@ -58,14 +80,8 @@ const queryParams = ref({
   dateRange
 })
 const {crudBinding, crudRef, crudExpose} =  useFs({createCrudOptions, context: queryParams})
-
 const router = useRouter()
-
-onMounted(() => {
-  crudExpose.doRefresh()
-})
-
-
+const showCompare = ref(false)
 const jumpGroup = (row: any) => {
   router.push({
     name: 'CampaignDetail',
@@ -73,13 +89,20 @@ const jumpGroup = (row: any) => {
   })
 }
 
+onMounted(() => {
+  crudExpose.doRefresh()
+})
+
+
+
+
 watch(queryParams, async () => {
   crudExpose.doRefresh()
 }, { deep: true })
 
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
 .chart-tabs {
   margin: 5px 0;
 
@@ -87,5 +110,34 @@ watch(queryParams, async () => {
     padding-left: 0 !important;
   }
 }
+.campare-switch {
+  flex: none;
+}
+
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+2):nth-child(-n+4) .cell) {
+  display: none;
+}
+
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper) {
+  border: 0;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
 
+.text-range {
+  color: #808184;
+}
 </style>

+ 16 - 3
src/views/adManage/sp/purchasedOtherProducts/crud.tsx

@@ -19,6 +19,16 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 		crudOptions: {
 			table: {
 				height: 800,
+				headerCellStyle: {
+					backgroundColor: '#f6f7fa', // 直接设置背景颜色
+					height: '20px',
+					// border: '0.5px solid #ddd',
+				},
+				cellStyle: {
+					border: 'none',
+					borderBottom: '0.5px solid #ddd',
+				},
+				showSummary: true,
 			},
 			container: {
 				fixedHeight: false,
@@ -59,7 +69,7 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 					title: '状态',
 				},
 				campaignName: {
-					title: '广告活动',
+					title: '广告活动名称',
 					column: {
 						width: '200px',
 					},
@@ -75,8 +85,11 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 						rules: [{ required: true, message: '必填项' }],
 					},
 				},
-				adGroup: {
-					title: '广告组',
+				adGroupName: {
+					title: '广告组名称',
+					column: {
+						width: '200px',
+					},
 				},
 				matchType: {
 					title: '定向',

+ 54 - 4
src/views/adManage/sp/purchasedOtherProducts/index.vue

@@ -6,7 +6,7 @@
 					<el-tab-pane label="数据趋势" name="dataTendency">
 						<DataTendencyChart
               :query="queryParams"
-              :fetchCard="getCardData" 
+              :fetchCard="getCardData"
               :fetchLine="getLineData"
               :fetch-line-month="getLineMonthData"
               :fetch-line-week="getLineWeekData"
@@ -24,12 +24,26 @@
         <p>{{ scope.row.purchasedAsin }}</p>
       </template>
 
+      <template #cell_campaignName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_adGroupName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.adGroupName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.adGroupName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
       <template v-for="field of Object.keys(SpCampaignPuchasedOtherProductsColumn)" #[`cell_${field}`]="scope">
         <DataCompare
-          :field="field" 
+          :field="field"
           :value="scope.row[field]"
           :prev-val="scope.row[`prev${field}`]"
-          :gap-val="scope.row[`gap${field}`]" 
+          :gap-val="scope.row[`gap${field}`]"
           :date-range="dateRange"
           :show-compare="showCompare"/>
       </template>
@@ -55,6 +69,7 @@ import { storeToRefs } from 'pinia'
 import { spCampaignPuchasedOtherProductsMetricsEnum } from '/@/views/adManage/utils/enum.js'
 import { SpCampaignPuchasedOtherProductsColumn } from '/@/views/adManage/utils/commonTabColumn.js'
 import DataCompare from '/@/components/dataCompare/index.vue'
+import router from '/@/router'
 
 const tabActiveName = ref("dataTendency")
 const shopInfo = useShopInfo()
@@ -72,6 +87,12 @@ const queryParams = ref({
   dateRange
 })
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
+const jumpGroup = (row: any) => {
+  router.push({
+    name: 'CampaignDetail',
+    query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
+  })
+}
 
 onMounted(async () => {
 	crudExpose.doRefresh()
@@ -83,5 +104,34 @@ watch(queryParams, async () => {
 </script>
 
 <style scoped>
+.campare-switch {
+  flex: none;
+}
+
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+3):nth-child(-n+6) .cell) {
+  display: none;
+}
+
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper) {
+  border: 0;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
 
-</style>
+.text-range {
+  color: #808184;
+}
+</style>

+ 59 - 32
src/views/adManage/sp/targets/crud.tsx

@@ -29,13 +29,23 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
   return {
     crudOptions: {
       table: {
-        height: 800
+        height: 800,
+        headerCellStyle: {
+          backgroundColor: '#f6f7fa', // 直接设置背景颜色
+          height: '20px',
+          // border: '0.5px solid #ddd',
+        },
+        cellStyle: {
+          border: 'none',
+          borderBottom: '0.5px solid #ddd',
+        },
+        showSummary: true,
       },
       container: {
         fixedHeight: false
       },
       actionbar: {
-        show: true,
+        show: false,
         buttons: {
           add: {
             show: false
@@ -92,12 +102,20 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
             show: false
           }
         },
-        resolvedExpression_value: {title: '商品和分类'},
+        resolvedExpression_value: {
+          title: '商品和分类',
+          column: {
+            width: '130px',
+            align: 'left',
+            fixed: 'left'
+          }
+        },
         state: {
           title: '状态',
           column: {
             width: '90px',
-            align: 'center'
+            align: 'center',
+            sortable: true
           },
           type: 'dict-select',
           search: {
@@ -113,9 +131,8 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         campaignName: {
           title: '广告活动名称',
           column: {
-            width: '200px',
-            align: 'center',
-            fixed: 'left'
+            width: '180px',
+            align: 'left',
           },
           search: {
             show: true,
@@ -132,45 +149,55 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
         adGroupName: {
           title: '广告组名称',
           column: {
-            align: 'center',
+            align: 'left',
+            width: '180px'
           },
         },
-        suggestedBudget: {
+        suggestedBid: {
           title: '建议竞价',
           column: {
-            align: 'center',
+            align: 'right',
+            width: '130px'
           },
         },
         bid: {
           title: '出价',
           column: {
             align: 'center',
+            sortable: true,
           },
         },
-        '标签': {},
-        Impression: {
-          title: '曝光量',
-          column: {
-            align: 'center',
-          },
-        },
-        '搜索结果顶部展示份额': {},
-        Click: {
-          title: '点击量',
+        TopOfSearchImpressionShare: {
+          title: '搜索结果顶部展示份额',
           column: {
-            align: 'center',
-          },
+            align: 'right',
+            sortable: true,
+            width: '220px',
+            renderHeader() {
+              return (
+                  <span>
+                <el-tooltip placement="top" content="
+        广告活动获得的搜索结果顶部展示量占其获得的所有符合条件的搜索结果顶部展示量的百分比。<br />
+        符合条件与否由各种因素所决定,包括广告活动状态和投放状态。该指标适用于品牌推广活动和商品推广活动。<br />
+        对于商品推广,该指标提供了搜索结果顶部(首页)的展示量份额。<br />
+        默认展示所选时间范围内展示份额的最高值,如需查看分天的数据趋势,请点击数据详情按钮。" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>搜索结果顶部展示份额</span>
+            </span>
+              )
+            },
+            formatter: (row) => {
+              if (row.value !== null) {
+                return row.value
+              } else {
+                return '--'
+              }
+            }
+          }
         },
-        CTR: {title: '点击率'},
-        Spend: {title: '花费'},
-        CPC: {title: '点击成本'},
-        TotalPurchases: {title: '订单数'},
-        TotalSales: {title: '销售额'},
-        TotalUnitOrdered: {title: '销量'},
-        PurchasesRate: {title: '转化率'},
-        ACOS: {title: 'ACOS'},
-        ROAS: {title: 'ROAS'},
-        CPA: {title: '订单成本'},
         ...BaseColumn
       }
     }

+ 73 - 2
src/views/adManage/sp/targets/index.vue

@@ -19,6 +19,40 @@
           <el-tab-pane label="散点视图" name="scatterView" :lazy="true"></el-tab-pane>
         </el-tabs>
       </template>
+
+      <template #cell_campaignName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.campaignName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.campaignName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_adGroupName="scope">
+        <el-tooltip  effect="dark" :content="scope.row.adGroupName" placement="top">
+          <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">
+            <div class="en-text">{{ scope.row.adGroupName }}</div>
+          </el-link>
+        </el-tooltip>
+      </template>
+      <template #cell_suggestedBid="scope">
+        <div>${{ scope.row.suggestedBid }}</div>
+        <div class="text-range">${{ scope.row.suggestedBid_lower }} ~ ${{ scope.row.suggestedBid_upper }}</div>
+      </template>
+      <template v-for="field of Object.keys(SbBaseColumn)" #[`cell_${field}`]="scope">
+        <DataCompare
+            :field="field"
+            :value="scope.row[field]"
+            :prev-val="scope.row[`prev${field}`]"
+            :gap-val="scope.row[`gap${field}`]"
+            :date-range="dateRange"
+            :show-compare="showCompare"/>
+      </template>
+      <template #toolbar-left>
+        <div class="campare-switch">
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
     </fs-crud>
   </fs-page>
 </template>
@@ -34,6 +68,8 @@ import {usePublicData} from '/@/stores/publicData'
 import AdStructChart from './chartComponents/adStruct.vue'
 import {getCardData, getLineData, getLineMonthData, getLineWeekData} from '/@/views/adManage/sp/campaigns/api'
 import {storeToRefs} from 'pinia'
+import {SbBaseColumn} from '/@/views/adManage/utils/commonTabColumn'
+import DataCompare from '/@/components/dataCompare/index.vue'
 
 
 const tabActiveName = ref('dataTendency')
@@ -51,7 +87,13 @@ const route = useRoute()
 const router = useRouter()
 const adStructChartRef = ref()
 const dataTendencyRef = ref()
-
+const showCompare = ref(false)
+const jumpGroup = (row: any) => {
+  router.push({
+    name: 'CampaignDetail',
+    query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
+  })
+}
 
 onMounted(() => {
   crudExpose.doRefresh()
@@ -77,7 +119,7 @@ watch(queryParams, async () => {
 
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
 .chart-tabs {
   margin: 5px 0;
 
@@ -86,4 +128,33 @@ watch(queryParams, async () => {
   }
 }
 
+.campare-switch {
+  flex: none;
+}
+::v-deep(.el-table__footer-wrapper td.el-table__cell:nth-child(n+3):nth-child(-n+6) .cell) {
+  display: none;
+}
+.en-text {
+  max-width: 100%;
+  font-size: 13px;
+  font-weight: 420;
+  word-break: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: normal;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+::v-deep(.el-table__footer-wrapper) {
+  border: 0;
+}
+::v-deep(.el-table .el-table__footer-wrapper .cell) {
+  font-weight: 600;
+}
+
+.text-range {
+  color: #808184;
+}
+
 </style>

+ 237 - 63
src/views/adManage/utils/commonTabColumn.tsx

@@ -1,124 +1,289 @@
 export const BaseColumn = {
   Impression: {
     title: '曝光量',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="来自亚马逊广告API,广告被展示的次数。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>曝光量</span>
+            </span>
+        )
+      },
+      formatter: (row) => {
+        console.log(row.value)
+        if (row.value != null) {
+          return row.value
+        } else {
+          return '--'
+        }
+      }
     }
   },
   Click: {
     title: '点击量',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="来自亚马逊广告API,广告被点击的次数。亚马逊系统会在3天内将无效点击去除。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击量</span>
+            </span>
+        )
+      }
     }
   },
   CTR: {
     title: '点击率',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="点击率,系统计算,点击量/曝光量。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击率</span>
+            </span>
+        )
+      }
     }
   },
   Spend: {
     title: '花费',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      border: '0.5px solid #ddd',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top"
+                            content="来自亚马逊广告API,亚马逊系统会在3天内将无效点击从统计数据中删除,因此过去3天内的花费可能会有所变化">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>花费</span>
+            </span>
+        )
+      }
     }
   },
   CPC: {
     title: '点击成本',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '130px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="单次点击成本,系统计算,花费/点击量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>点击成本</span>
+            </span>
+        )
+      }
     }
   },
   TotalPurchases: {
-    title: '订单量',
-    form: {
-      show: false
-    },
-    column:{
+    title: '订单数',
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="
+        Seller类型店铺:<br />
+        订单数,来自亚马逊广告API。<br />
+        在点击广告后的7天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的订单数量;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单数量将从订单总数中删除。<br />
+        <br />
+        Vendor类型店铺:<br />
+        订单数,来自亚马逊广告API。<br />
+        在点击广告后的14天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的订单数量;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单数量将从订单总数中删除" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>订单数</span>
+            </span>
+        )
+      }
     }
   },
   TotalUnitOrdered: {
     title: '销量',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="
+        Seller类型店铺:<br />
+        销售件数,来自亚马逊广告API。<br />
+        在点击广告后的7天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的件数;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单和72小时内取消的订单产生的销售件数将从销量总数中删除。<br />
+        <br />
+        Vendor类型店铺:<br />
+        销售件数,来自亚马逊广告API。<br />
+        在点击广告后的14天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的件数;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单和72小时内取消的订单产生的销售件数将从销量总数中删除。" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>销量</span>
+            </span>
+        )
+      }
     }
   },
   TotalSales: {
     title: '销售额',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="
+        Seller类型店铺:<br />
+        销售额,来自亚马逊广告API。<br />
+        在点击广告后的7天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br/>出的广告商品及库存中其他商品的销售额;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单产生的销售额将从总销售额中删除。<br />
+        <br />
+        Vendor类型店铺:<br />
+        销售额,来自亚马逊广告API。<br />
+        在点击广告后的14天内(商品推广)、14天内(品牌推广)、浏览或点击广告后的14天内(展示型推广)售<br />出的广告商品及库存中其他商品的销售额;<br />
+        亚马逊系统此项数据最多可能延迟12小时更新。因此,“今天”日期范围内的销售数据可能会延迟。<br />
+        付款失败的订单数量和72小时内取消的订单产生的销售额将从总销售额中删除。" raw-content>
+        <span>
+        <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>销售额</span>
+            </span>
+        )
+      }
     }
   },
   PurchasesRate: {
     title: '转化率',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      border: '0.5px solid #ddd',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top"
+                            content="广告转化率,系统计算,广告订单量/点击量*100%,展示型推广vCPM成本类型的广告活动不予计算。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>转化率</span>
+            </span>
+        )
+      }
     }
   },
   ACOS: {
     title: 'ACOS',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      width: '120px',
+      sortable: true,
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="广告投入产出比,系统计算,广告花费/广告带来的销售额。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>ACOS</span>
+            </span>
+        )
+      }
     }
   },
   ROAS: {
     title: 'ROAS',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '120px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="广告支出回报,系统计算,广告带来的销售额/广告花费。">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>ROAS</span>
+            </span>
+        )
+      }
     }
   },
   CPA: {
     title: '订单成本',
-    form: {
-      show: false
-    },
-    column:{
+    column: {
       align: 'right',
-      minWidth: '125px'
+      sortable: true,
+      width: '130px',
+      renderHeader() {
+        return (
+            <span>
+                <el-tooltip placement="top" content="平均每笔订单的花费,系统计算,花费/广告订单量">
+            <span>
+                <el-icon size="14" style="display:inline-block; padding-top:2px; margin-right:3px;"><InfoFilled/></el-icon>
+            </span>
+            </el-tooltip>
+            <span>订单成本</span>
+            </span>
+        )
+      }
     }
-  }
+  },
 }
 
 export const SpCampaignPuchasedOtherProductsColumn = {
@@ -128,7 +293,8 @@ export const SpCampaignPuchasedOtherProductsColumn = {
       show: false
     },
     column:{
-      align: 'right'
+      align: 'right',
+
     }
   },
   TotalUnitOrderedOtherSKU: {
@@ -507,6 +673,14 @@ export const SbBaseColumn = {
             <span>可见曝光量</span>
             </span>
       )
+      },
+      formatter: (row) => {
+        console.log(row.value)
+        if (row.value != null) {
+          return row.value
+        } else {
+          return '--'
+        }
       }
     }
   },