Browse Source

订单管理

chenlei1231 3 months ago
parent
commit
2cd6f939ee

+ 3 - 1
src/assets/less/common.less

@@ -106,7 +106,9 @@
 .seo_keywords_rank_wrap,
 .seo-keywords-list,
 .adweb-enquiry-list,
-.adweb-waste-enquiry-list{
+.adweb-waste-enquiry-list,
+.traffic-analysis-page,
+.enquiry-analysis-page{
   padding-top: 72px !important;
 
   .search-form {

+ 1 - 1
src/assets/less/home.less

@@ -43,7 +43,7 @@
     width: auto;
   }
   .top-title {
-    margin: 20px 0;
+    //margin: 20px 0;
 
     .t1 {
       font-size: 18px;

+ 1 - 1
src/components/Adweb/selectSite.vue

@@ -117,7 +117,7 @@
   .search-adweb-site {
     margin-bottom: 0;
   }
-  :deep(.ant-select-focused .ant-select-selection-item) {
+  :deep(.ant-select-open .ant-select-selection-item) {
     color: #cfcbcba6 !important;
   }
 

+ 1 - 0
src/enums/roleEnum.ts

@@ -6,6 +6,7 @@ export enum RoleEnum {
   SEO_ADMIN = 'seo_admin',
   ADWEB_SITE_MANAGER = 'adweb_site_manager',
   ADWEB_SEO_MANAGER = 'adweb_seo_manager',
+  ADWEB_CHANNEL_ADMIN = 'adweb_channel_admin',
   // tester
   TEST = 'test',
 }

+ 440 - 439
src/views/adweb/data/enquiryAnalysis.vue

@@ -1,39 +1,40 @@
 <template>
-  <div class="search-form">
-    <!-- 站点选择和时间筛选 -->
-    <a-row class="r1" :gutter="8">
-      <a-col :xl="7" :xxl="6">
-        <div class="choose-site">
-          <span class="t1">站点:</span>
-          <select-site @set-site-info="changeSite" select-width="100%" />
-        </div>
-      </a-col>
-      <a-col :xl="8" :xxl="6">
-        <div class="choose-site">
-          <span class="t1">统计时间:</span>
-          <a-range-picker @change="onChangeDatePicker" :disabledDate="disabledDate" :value="rangeDate" style="width: 70%" />
-        </div>
-      </a-col>
-      <a-col :xl="9" :xxl="12">
-        <a-button-group class="time-btn-group">
-          <a-button :class="queryParam.dateType == '' ? 'active' : ''" @click="setTime('')">全部时间</a-button>
-          <a-button :class="queryParam.dateType == 'thirtyDay' ? 'active' : ''" @click="setTime('thirtyDay')">近30天</a-button>
-          <a-button :class="queryParam.dateType == 'sevenDay' ? 'active' : ''" @click="setTime('sevenDay')">近一周</a-button>
-          <a-button :class="queryParam.dateType == 'yesterday' ? 'active' : ''" @click="setTime('yesterday')">昨日</a-button>
-          <a-button :class="queryParam.dateType == 'today' ? 'active' : ''" @click="setTime('today')">今日</a-button>
-        </a-button-group>
-      </a-col>
-    </a-row>
-  </div>
-  <a-spin :spinning="loading" tip="加载中...">
-    <a-row class="r2">
+  <div class="enquiry-analysis-page">
+    <div class="search-form">
+      <!-- 站点选择和时间筛选 -->
+      <a-row class="r1 search-form-container" :gutter="8">
+        <a-col :xl="7" :xxl="6">
+          <div class="choose-site">
+            <span class="t1">站点:</span>
+            <select-site @set-site-info="changeSite" select-width="100%" />
+          </div>
+        </a-col>
+        <a-col :xl="8" :xxl="6">
+          <div class="choose-site">
+            <span class="t1">统计时间:</span>
+            <a-range-picker @change="onChangeDatePicker" :disabledDate="disabledDate" :value="rangeDate" style="width: 70%" />
+          </div>
+        </a-col>
+        <a-col :xl="9" :xxl="12">
+          <a-button-group class="time-btn-group">
+            <a-button :class="queryParam.dateType == '' ? 'active' : ''" @click="setTime('')">全部时间</a-button>
+            <a-button :class="queryParam.dateType == 'thirtyDay' ? 'active' : ''" @click="setTime('thirtyDay')">近30天</a-button>
+            <a-button :class="queryParam.dateType == 'sevenDay' ? 'active' : ''" @click="setTime('sevenDay')">近一周</a-button>
+            <a-button :class="queryParam.dateType == 'yesterday' ? 'active' : ''" @click="setTime('yesterday')">昨日</a-button>
+            <a-button :class="queryParam.dateType == 'today' ? 'active' : ''" @click="setTime('today')">今日</a-button>
+          </a-button-group>
+        </a-col>
+      </a-row>
+    </div>
+    <a-spin :spinning="loading" tip="加载中...">
+      <a-row class="r2">
         <a-col :span="8">
           <p class="t1">询盘数</p>
           <p class="t3">{{ enquiryIndexNumber.enquiry.toLocaleString() }}</p>
         </a-col>
         <a-col :span="8">
           <p class="t1">未读询盘数</p>
-            <p class="t3">{{ enquiryIndexNumber.unRead.toLocaleString() }}</p>
+          <p class="t3">{{ enquiryIndexNumber.unRead.toLocaleString() }}</p>
         </a-col>
         <a-col :span="8">
           <p class="t1">UV到询盘的转化率</p>
@@ -41,511 +42,511 @@
         </a-col>
       </a-row>
 
-    <a-row>
-      <a-col :span="24">
-        <a-card style="margin: 10px" title="询盘趋势图">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-row class="r5-1">
-              <a-col :span="24">
-                <enquiry-chart v-if="coreDataChart.x.length > 0"
-                            :dataSource="coreDataChart"></enquiry-chart>
-                <a-empty v-else style="float: right;width: 100%;margin-top: 110px;"></a-empty>
-              </a-col>
+      <a-row>
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="询盘趋势图">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-row class="r5-1">
+                <a-col :span="24">
+                  <enquiry-chart v-if="coreDataChart.x.length > 0" :dataSource="coreDataChart" />
+                  <a-empty v-else style="float: right; width: 100%; margin-top: 110px" />
+                </a-col>
+              </a-row>
             </a-row>
-          </a-row>
-        </a-card>
-      </a-col>
-      <a-col :span="24">
-        <a-card style="margin: 10px" title="询盘地域分布">
-          <a-row class="r5">
-            <a-col :span="18">
-              <map-adweb v-if="countryMapData.length > 0" :dataSource="countryMapData"
-                         height="400"></map-adweb>
-              <a-empty v-else style="margin-top: 50px;">
-              </a-empty>
-            </a-col>
-
-            <a-col :span="6">
-              <a-table
-                :rowKey="(record,index)=>{return index}"
-                class="chartTable"
-                :scroll="{ y: 500 }"
-                :pagination=false
-                :columns="chartDetailDataCol"
-                :data-source="chartDetailData"
-                :showHeader="false">
-                <template #bodyCell="{ column, record }">
-                  <template v-if="column.key === 'flagSlot' ">
-            <span class="img-box">
-              <span :class="'flag-icon flag-icon-'+record.countryCode"></span>
-            </span>
-                  </template>
-                  <template v-if="column.key === 'numSlot' ">
-                    {{ record.enquires }} | {{ record.enquiresProportion }}
+          </a-card>
+        </a-col>
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="询盘地域分布">
+            <a-row class="r5">
+              <a-col :span="18">
+                <map-adweb v-if="countryMapData.length > 0" :dataSource="countryMapData" height="400" />
+                <a-empty v-else style="margin-top: 50px" />
+              </a-col>
+
+              <a-col :span="6">
+                <a-table
+                  :rowKey="
+                    (record, index) => {
+                      return index;
+                    }
+                  "
+                  class="chartTable"
+                  :scroll="{ y: 500 }"
+                  :pagination="false"
+                  :columns="chartDetailDataCol"
+                  :data-source="chartDetailData"
+                  :showHeader="false"
+                >
+                  <template #bodyCell="{ column, record }">
+                    <template v-if="column.key === 'flagSlot'">
+                      <span class="img-box">
+                        <span :class="'flag-icon flag-icon-' + record.countryCode"></span>
+                      </span>
+                    </template>
+                    <template v-if="column.key === 'numSlot'"> {{ record.enquires }} | {{ record.enquiresProportion }} </template>
                   </template>
-                </template>
-              </a-table>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-    </a-row>
-  </a-spin>
+                </a-table>
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+      </a-row>
+    </a-spin>
+  </div>
 </template>
 <script lang="ts" name="data-enquiryAnalysis" setup>
-import selectSite from "@/components/Adweb/selectSite.vue";
-import enquiryChart from "./chart/enquiryChart.vue";
-import { reactive, ref } from "vue";
-import { getAction } from "@/api/manage/manage";
-import MapAdweb from "@/components/chart/mapAdweb.vue";
-import "flag-icon-css/css/flag-icons.css";
-import dayjs from 'dayjs';
-
-const queryParam = reactive<any>({});
-queryParam.limit = 10;
-queryParam.siteCode = localStorage.getItem("siteCode");
-const loading = ref(false);
-const chartDetailDataCol = ref([
-  {
-    title: "国旗",
-    align: "center",
-    key: "flagSlot",
-    width: 30,
-    scopedSlots: { customRender: "flagSlot" }
-  },
-  {
-    title: "国家",
-    align: "left",
-    dataIndex: "countryName",
-    customRender: function(text, record) {
-      return text === null ? record.country : text;
-    }
-  },
-  {
-    title: "数量",
-    align: "right",
-    key: "numSlot",
-    scopedSlots: { customRender: "numSlot" }
-  }
-]);
-const enquiryIndexNumber = ref<any>({
-  unRead: 0,
-  conversionRate: '0%',
-  enquiry: 0,
-});
-const countryMapData = ref<any>([]);
+  import selectSite from '@/components/Adweb/selectSite.vue';
+  import enquiryChart from './chart/enquiryChart.vue';
+  import { reactive, ref } from 'vue';
+  import { getAction } from '@/api/manage/manage';
+  import MapAdweb from '@/components/chart/mapAdweb.vue';
+  import 'flag-icon-css/css/flag-icons.css';
+  import dayjs from 'dayjs';
+
+  const queryParam = reactive<any>({});
+  queryParam.limit = 10;
+  queryParam.siteCode = localStorage.getItem('siteCode');
+  const loading = ref(false);
+  const chartDetailDataCol = ref([
+    {
+      title: '国旗',
+      align: 'center',
+      key: 'flagSlot',
+      width: 30,
+      scopedSlots: { customRender: 'flagSlot' },
+    },
+    {
+      title: '国家',
+      align: 'left',
+      dataIndex: 'countryName',
+      customRender: function (text, record) {
+        return text === null ? record.country : text;
+      },
+    },
+    {
+      title: '数量',
+      align: 'right',
+      key: 'numSlot',
+      scopedSlots: { customRender: 'numSlot' },
+    },
+  ]);
+  const enquiryIndexNumber = ref<any>({
+    unRead: 0,
+    conversionRate: '0%',
+    enquiry: 0,
+  });
+  const countryMapData = ref<any>([]);
   const coreDataChart = ref({
-  x: [],
-  uv: [],
-  pv: [],
-  enquiry: []
-});
-
-const chartDetailData = ref<any>([]);
-
-
-function changeSite(selectedSiteInfo: any) {
-  queryParam.siteCode = selectedSiteInfo.code;
-  localStorage.setItem("siteCode", queryParam.siteCode);
-  reloadData();
-}
-
-function reloadData() {
-  loading.value = true;
-  getFlowIndexNumber();
-  getCountryMapData();
-}
-//访客量、浏览量、询盘数量、折线图以及统计
-const getFlowIndexNumber = async () => {
-  try {
-    const res = await getAction("/dmp-data/site-overview/stats", queryParam);
-    if (!res.result) {
-      enquiryIndexNumber.value = {
-        unRead: 0,
-        conversionRate: '0%',
-        enquiry: 0,
-      };
-      coreDataChart.value = {
-        x: [],
-        uv: [],
-        pv: [],
-        enquiry: []
-      };
+    x: [],
+    uv: [],
+    pv: [],
+    enquiry: [],
+  });
+
+  const chartDetailData = ref<any>([]);
+
+  function changeSite(selectedSiteInfo: any) {
+    queryParam.siteCode = selectedSiteInfo.code;
+    localStorage.setItem('siteCode', queryParam.siteCode);
+    reloadData();
+  }
+
+  function reloadData() {
+    loading.value = true;
+    getFlowIndexNumber();
+    getCountryMapData();
+  }
+  //访客量、浏览量、询盘数量、折线图以及统计
+  const getFlowIndexNumber = async () => {
+    try {
+      const res = await getAction('/dmp-data/site-overview/stats', queryParam);
+      if (!res.result) {
+        enquiryIndexNumber.value = {
+          unRead: 0,
+          conversionRate: '0%',
+          enquiry: 0,
+        };
+        coreDataChart.value = {
+          x: [],
+          uv: [],
+          pv: [],
+          enquiry: [],
+        };
+        loading.value = false;
+        return;
+      }
+
+      enquiryIndexNumber.value.unRead = res.result.unreadEnquires;
+      enquiryIndexNumber.value.conversionRate = res.result.enquiryConversionRate;
+      enquiryIndexNumber.value.enquiry = res.result.enquires;
+      const r = res.result.dailyStats;
+      const x = [],
+        pv = [],
+        uv = [],
+        enquiry = [];
+      if (r != null && r.length > 0) {
+        for (let item of r) {
+          x.push(item.date);
+          pv.push(item.pageViews);
+          uv.push(item.totalUsers);
+          enquiry.push(item.enquires);
+        }
+      }
+      coreDataChart.value.x = x;
+      coreDataChart.value.pv = pv;
+      coreDataChart.value.uv = uv;
+      coreDataChart.value.enquiry = enquiry;
       loading.value = false;
-      return;
+    } catch (error) {
+      console.error(error);
     }
-
-    enquiryIndexNumber.value.unRead = res.result.unreadEnquires;
-    enquiryIndexNumber.value.conversionRate = res.result.enquiryConversionRate;
-    enquiryIndexNumber.value.enquiry = res.result.enquires;
-    const r = res.result.dailyStats;
-    const x = [], pv = [], uv = [], enquiry = [];
-    if (r != null && r.length > 0) {
-      for (let item of r) {
-        x.push(item.date);
-        pv.push(item.pageViews);
-        uv.push(item.totalUsers);
-        enquiry.push(item.enquires);
+  };
+  const getCountryMapData = async () => {
+    try {
+      const res = await getAction('/dmp-data/enquiry-country/stats', queryParam);
+      if (res.code === 200) {
+        chartDetailData.value = res.result;
+        countryMapData.value = chartDetailData.value.map((entry) => ({
+          name: entry.countryName,
+          value: entry.enquires,
+        }));
       }
+    } catch (error) {
+      console.error(error);
     }
-    coreDataChart.value.x = x;
-    coreDataChart.value.pv = pv;
-    coreDataChart.value.uv = uv;
-    coreDataChart.value.enquiry = enquiry;
-    loading.value = false;
-  } catch (error) {
-    console.error(error);
-  }
-};
-const getCountryMapData = async () => {
-  try {
-    const res = await getAction("/dmp-data/enquiry-country/stats", queryParam);
-    if (res.code === 200) {
-      chartDetailData.value = res.result;
-      countryMapData.value = chartDetailData.value.map(entry => ({
-        name: entry.countryName,
-        value: entry.enquires
-      }));
+  };
+  const rangeDate = ref([]);
+
+  const onChangeDatePicker = (date, dateString) => {
+    if (dateString.length > 0) {
+      console.log('rangeDate:', rangeDate.value);
+      rangeDate.value = date;
+      console.log('date:', date);
+      queryParam.start = dateString[0];
+      queryParam.end = dateString[1];
+      queryParam.dateType = undefined;
+      reloadData();
     }
-  } catch (error) {
-    console.error(error);
-  }
-};
-const rangeDate = ref([]);
-
-const onChangeDatePicker = (date, dateString) => {
-  if (dateString.length > 0) {
-    console.log("rangeDate:", rangeDate.value);
-    rangeDate.value = date;
-    console.log("date:", date);
-    queryParam.start = dateString[0];
-    queryParam.end = dateString[1];
-    queryParam.dateType = undefined;
-    reloadData();
-  }
-};
-
-function disabledDate(current) {
-  return current && current > dayjs();
-}
-
-const setTime = (time) => {
-  queryParam.dateType = time;
-  queryParam.start = "";
-  queryParam.end = "";
-
-  if (time == "") {
-    rangeDate.value = undefined;
-  } else if (time == "sevenDay") {
-    rangeDate.value = [dayjs().add(-7, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "thirtyDay") {
-    rangeDate.value = [dayjs().add(-30, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "yesterday") {
-    rangeDate.value = [dayjs().add(-1, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "today") {
-    rangeDate.value = [dayjs(), dayjs()];
+  };
+
+  function disabledDate(current) {
+    return current && current > dayjs();
   }
 
-  reloadData();
-};
+  const setTime = (time) => {
+    queryParam.dateType = time;
+    queryParam.start = '';
+    queryParam.end = '';
+
+    if (time == '') {
+      rangeDate.value = undefined;
+    } else if (time == 'sevenDay') {
+      rangeDate.value = [dayjs().add(-7, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'thirtyDay') {
+      rangeDate.value = [dayjs().add(-30, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'yesterday') {
+      rangeDate.value = [dayjs().add(-1, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'today') {
+      rangeDate.value = [dayjs(), dayjs()];
+    }
 
+    reloadData();
+  };
 </script>
 <style lang="less" scoped>
-.self-pop {
-  .ant-popover-inner-content {
-    background: rgb(245, 243, 254);
+  .self-pop {
+    .ant-popover-inner-content {
+      background: rgb(245, 243, 254);
 
-    p {
-      font-size: 13px;
+      p {
+        font-size: 13px;
+      }
     }
-  }
-
-  .ant-popover-arrow {
-    border-color: rgb(245, 243, 254) !important;
-  }
-}
-
-.img-box {
-  width: 22px;
-  height: 15px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-
-  img {
-    width: 100%;
-    height: 100%;
-  }
-}
 
-.ant-alert {
-  /deep/ .ant-btn {
-    border-radius: 0;
-    margin-left: 10px;
+    .ant-popover-arrow {
+      border-color: rgb(245, 243, 254) !important;
+    }
   }
-}
-
-.theme-color {
-  color: @primary-color;
-}
 
-.r1 {
-  margin: 20px;
-
-  .choose-site {
+  .img-box {
+    width: 22px;
+    height: 15px;
     display: flex;
-  }
+    justify-content: center;
+    align-items: center;
 
-  .t1 {
-    font-size: 18px;
-    font-weight: 400;
-    letter-spacing: 0px;
-    line-height: 32px;
-    margin-left: 10px;
+    img {
+      width: 100%;
+      height: 100%;
+    }
   }
 
-  .ant-form-item {
-    flex: 1;
+  .ant-alert {
+    /deep/ .ant-btn {
+      border-radius: 0;
+      margin-left: 10px;
+    }
   }
 
-  .ant-calendar-picker {
-    margin-right: 20px;
+  .theme-color {
+    color: @primary-color;
   }
 
+  .r1 {
+    margin: 20px;
 
-  /deep/ .ant-btn {
-    background: transparent;
-    margin-right: 10px;
-    padding: 4px 15px;
-    border: 1px solid #d9d9d9;
-    border-radius: 4px;
-    transition: all 0.3s;
+    .choose-site {
+      display: flex;
+    }
 
-    &:hover {
-      color: @primary-color;
-      border-color: @primary-color;
+    .t1 {
+      font-size: 18px;
+      font-weight: 400;
+      letter-spacing: 0px;
+      line-height: 32px;
+      margin-left: 10px;
     }
 
-    &.active {
-      color: @primary-color;
-      background: #e6f7ff;
-      border-color: @primary-color;
+    .ant-form-item {
+      flex: 1;
+    }
+
+    .ant-calendar-picker {
+      margin-right: 20px;
     }
-  }
 
-  .time-btn-group {
     /deep/ .ant-btn {
-      background: #fff;
+      background: transparent;
+      margin-right: 10px;
       padding: 4px 15px;
       border: 1px solid #d9d9d9;
+      border-radius: 4px;
       transition: all 0.3s;
-      margin-right: 0;
-
-      &:first-child {
-        border-top-left-radius: 4px;
-        border-bottom-left-radius: 4px;
-      }
-
-      &:last-child {
-        border-top-right-radius: 4px;
-        border-bottom-right-radius: 4px;
-      }
-
-      &:not(:first-child) {
-        margin-left: -1px;
-      }
 
       &:hover {
         color: @primary-color;
         border-color: @primary-color;
-        position: relative;
-        z-index: 1;
-        background: #fff;
       }
 
       &.active {
         color: @primary-color;
         background: #e6f7ff;
         border-color: @primary-color;
-        position: relative;
-        z-index: 2;
       }
     }
-  }
-}
 
-.r2 {
-  background: #fff;
-  padding: 30px 20px;
-  margin: 10px;
+    .time-btn-group {
+      /deep/ .ant-btn {
+        background: #fff;
+        padding: 4px 15px;
+        border: 1px solid #d9d9d9;
+        transition: all 0.3s;
+        margin-right: 0;
+
+        &:first-child {
+          border-top-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+        }
 
-  .ant-col:not(:last-child) {
-    border-right: 1px solid #e6e6e6;
-  }
+        &:last-child {
+          border-top-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+        }
 
-  p {
-    margin: 0;
-    text-align: center;
+        &:not(:first-child) {
+          margin-left: -1px;
+        }
 
-    &.t1 {
-      color: #333;
-      margin-bottom: 15px;
+        &:hover {
+          color: @primary-color;
+          border-color: @primary-color;
+          position: relative;
+          z-index: 1;
+          background: #fff;
+        }
 
-      img {
-        margin-right: 10px;
-        width: 15px;
-        margin-top: -5px;
+        &.active {
+          color: @primary-color;
+          background: #e6f7ff;
+          border-color: @primary-color;
+          position: relative;
+          z-index: 2;
+        }
       }
     }
-
-    &.t2 {
-      color: @primary-color;
-      font-size: 30px;
-      font-weight: 500;
-      line-height: 1;
-      padding-left: 25px;
-    }
-
-    &.t3 {
-      font-size: 32px;
-      font-weight: 700;
-      letter-spacing: 0px;
-      line-height: 38px;
-      color: rgba(13, 62, 122, 1);
-    }
   }
-}
-
-.r5 {
-  background: #fff;
-  padding: 10px;
-  border-radius: 10px;
-  margin: 0 !important;
 
-  .wrap {
-    box-shadow: 0px 2px 4px 0px @primary-color;
-    padding: 15px;
-    border-radius: 10px;
-    overflow: hidden;
+  .r2 {
     background: #fff;
-    transition: all .3s;
+    padding: 30px 20px;
+    margin: 0 10px 10px 10px;
 
-    &.blue {
-      box-shadow: 0px 2px 4px 0px @primary-color;
+    .ant-col:not(:last-child) {
+      border-right: 1px solid #e6e6e6;
     }
 
-    &.effect:hover {
-      box-shadow: none;
-      background: rgb(241, 248, 255);
-    }
+    p {
+      margin: 0;
+      text-align: center;
 
-    img {
-      width: 15px;
-    }
+      &.t1 {
+        color: #333;
+        margin-bottom: 15px;
 
-    .fr {
-      float: right;
-      width: calc(100% - 15px);
-      text-align: center;
+        img {
+          margin-right: 10px;
+          width: 15px;
+          margin-top: -5px;
+        }
+      }
 
-      p:last-child {
+      &.t2 {
+        color: @primary-color;
         font-size: 30px;
-        text-align: center;
-        margin-top: 10px;
+        font-weight: 500;
+        line-height: 1;
+        padding-left: 25px;
+      }
 
+      &.t3 {
+        font-size: 32px;
+        font-weight: 700;
+        letter-spacing: 0px;
+        line-height: 38px;
+        color: rgba(13, 62, 122, 1);
       }
     }
   }
 
-  /deep/ .ant-table-thead > tr > th {
-    background: rgb(241, 248, 255);
-    border: none;
-    color: #000;
+  .r5 {
+    background: #fff;
     padding: 10px;
-  }
+    border-radius: 10px;
+    margin: 0 !important;
 
-  /deep/ .ant-table-tbody .ant-table-row td {
-    padding: 10px;
-    color: #000;
-  }
+    .wrap {
+      box-shadow: 0px 2px 4px 0px @primary-color;
+      padding: 15px;
+      border-radius: 10px;
+      overflow: hidden;
+      background: #fff;
+      transition: all 0.3s;
+
+      &.blue {
+        box-shadow: 0px 2px 4px 0px @primary-color;
+      }
 
-  .r5-1 {
-    display: inline-block;
-    width: 100%;
-    margin-top: 30px;
+      &.effect:hover {
+        box-shadow: none;
+        background: rgb(241, 248, 255);
+      }
 
-    .fl {
-      float: left;
-      position: relative;
+      img {
+        width: 15px;
+      }
 
-      .ant-btn {
-        border-radius: 0;
-        border: none;
-        margin-right: 10px;
+      .fr {
+        float: right;
+        width: calc(100% - 15px);
+        text-align: center;
+
+        p:last-child {
+          font-size: 30px;
+          text-align: center;
+          margin-top: 10px;
+        }
       }
     }
 
-    .fr {
-      float: right;
-      line-height: 2;
+    /deep/ .ant-table-thead > tr > th {
+      background: rgb(241, 248, 255);
+      border: none;
+      color: #000;
+      padding: 10px;
+    }
+
+    /deep/ .ant-table-tbody .ant-table-row td {
+      padding: 10px;
+      color: #000;
+    }
 
-      span {
-        margin-right: 30px;
+    .r5-1 {
+      display: inline-block;
+      width: 100%;
+      margin-top: 30px;
 
-        i {
-          display: inline-block;
-          width: 25px;
-          height: 3px;
-          background: #544BEB;
-          position: relative;
-          top: -4px;
-          margin-right: 20px;
+      .fl {
+        float: left;
+        position: relative;
+
+        .ant-btn {
+          border-radius: 0;
+          border: none;
+          margin-right: 10px;
         }
+      }
 
-        &:last-child i {
-          background: #F0B358;
+      .fr {
+        float: right;
+        line-height: 2;
+
+        span {
+          margin-right: 30px;
+
+          i {
+            display: inline-block;
+            width: 25px;
+            height: 3px;
+            background: #544beb;
+            position: relative;
+            top: -4px;
+            margin-right: 20px;
+          }
+
+          &:last-child i {
+            background: #f0b358;
+          }
         }
       }
     }
-  }
 
-  .box {
-    border-radius: 10px;
-    text-align: center;
-    min-height: 180px;
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
+    .box {
+      border-radius: 10px;
+      text-align: center;
+      min-height: 180px;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
 
-    p {
-      color: #fff;
+      p {
+        color: #fff;
 
-      img {
-        width: 19px;
-        margin: -5px 10px 0 0;
+        img {
+          width: 19px;
+          margin: -5px 10px 0 0;
+        }
       }
-    }
 
-    .num {
-      font-size: 30px;
-      margin-bottom: 10px;
-    }
+      .num {
+        font-size: 30px;
+        margin-bottom: 10px;
+      }
 
-    &.b1 {
-      background: rgb(233, 107, 95);
-    }
+      &.b1 {
+        background: rgb(233, 107, 95);
+      }
 
-    &.b2 {
-      background: rgb(88, 204, 168);
-    }
+      &.b2 {
+        background: rgb(88, 204, 168);
+      }
 
-    &.b3 {
-      background: rgb(124, 152, 252);
-    }
+      &.b3 {
+        background: rgb(124, 152, 252);
+      }
 
-    &.b4 {
-      background: #F0B358;
+      &.b4 {
+        background: #f0b358;
+      }
     }
   }
-}
-</style>
+</style>

+ 736 - 755
src/views/adweb/data/trafficAnalysis.vue

@@ -1,864 +1,845 @@
 <template>
-  <div class="search-form">
-    <!-- 站点选择和时间筛选 -->
-    <a-row class="r1" :gutter="8">
-      <a-col :xl="7" :xxl="6">
-        <div class="choose-site">
-          <span class="t1">站点:</span>
-          <select-site @set-site-info="changeSite" select-width="100%" />
-        </div>
-      </a-col>
-      <a-col :xl="8" :xxl="6">
-        <div class="choose-site">
-          <span class="t1">统计时间:</span>
-          <a-range-picker @change="onChangeDatePicker" :disabledDate="disabledDate" :value="rangeDate" style="width: 70%" />
-        </div>
-      </a-col>
-      <a-col :xl="9" :xxl="12">
-        <a-button-group class="time-btn-group">
-          <a-button :class="queryParam.dateType == '' ? 'active' : ''" @click="setTime('')">全部时间</a-button>
-          <a-button :class="queryParam.dateType == 'thirtyDay' ? 'active' : ''" @click="setTime('thirtyDay')">近30天</a-button>
-          <a-button :class="queryParam.dateType == 'sevenDay' ? 'active' : ''" @click="setTime('sevenDay')">近一周</a-button>
-          <a-button :class="queryParam.dateType == 'yesterday' ? 'active' : ''" @click="setTime('yesterday')">昨日</a-button>
-          <a-button :class="queryParam.dateType == 'today' ? 'active' : ''" @click="setTime('today')">今日</a-button>
-        </a-button-group>
-      </a-col>
-    </a-row>
-  </div>
-  <a-spin :spinning="loading" tip="加载中...">
-    <a-row class="r2">
-      <a-col :span="6">
-        <p class="t1">访客数(UV)</p>
-        <p class="t3">{{ flowIndexNums.uv.toLocaleString() }}</p>
-      </a-col>
-      <a-col :span="6">
-        <p class="t1">浏览量(PV)</p>
-        <p class="t3">{{ flowIndexNums.pv.toLocaleString() }}</p>
-      </a-col>
-      <a-col :span="6">
-        <p class="t1">会话数</p>
-        <p class="t3">{{ flowIndexNums.sessions.toLocaleString() }}</p>
-      </a-col>
-      <a-col :span="6">
-        <p class="t1">询盘数</p>
-        <p class="t3">{{ flowIndexNums.enquiry.toLocaleString() }}</p>
-      </a-col>
-    </a-row>
-    <a-row>
-      <a-col :span="24">
-        <a-card style="margin: 10px" title="核心数据">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-row class="r5-1">
-              <a-col :span="24">
-                <area-chart v-if="coreDataChart.x.length > 0"
-                            :dataSource="coreDataChart"></area-chart>
-                <a-empty v-else style="float: right;width: 100%;margin-top: 110px;"></a-empty>
+  <div class="traffic-analysis-page">
+    <div class="search-form">
+      <!-- 站点选择和时间筛选 -->
+      <a-row class="r1 search-form-container" :gutter="8">
+        <a-col :xl="7" :xxl="6">
+          <div class="choose-site">
+            <span class="t1">站点:</span>
+            <select-site @set-site-info="changeSite" select-width="100%" />
+          </div>
+        </a-col>
+        <a-col :xl="8" :xxl="6">
+          <div class="choose-site">
+            <span class="t1">统计时间:</span>
+            <a-range-picker @change="onChangeDatePicker" :disabledDate="disabledDate" :value="rangeDate" style="width: 70%" />
+          </div>
+        </a-col>
+        <a-col :xl="9" :xxl="12">
+          <a-button-group class="time-btn-group">
+            <a-button :class="queryParam.dateType == '' ? 'active' : ''" @click="setTime('')">全部时间</a-button>
+            <a-button :class="queryParam.dateType == 'thirtyDay' ? 'active' : ''" @click="setTime('thirtyDay')">近30天</a-button>
+            <a-button :class="queryParam.dateType == 'sevenDay' ? 'active' : ''" @click="setTime('sevenDay')">近一周</a-button>
+            <a-button :class="queryParam.dateType == 'yesterday' ? 'active' : ''" @click="setTime('yesterday')">昨日</a-button>
+            <a-button :class="queryParam.dateType == 'today' ? 'active' : ''" @click="setTime('today')">今日</a-button>
+          </a-button-group>
+        </a-col>
+      </a-row>
+    </div>
+    <a-spin :spinning="loading" tip="加载中...">
+      <a-row class="r2">
+        <a-col :span="6">
+          <p class="t1">访客数(UV)</p>
+          <p class="t3">{{ flowIndexNums.uv.toLocaleString() }}</p>
+        </a-col>
+        <a-col :span="6">
+          <p class="t1">浏览量(PV)</p>
+          <p class="t3">{{ flowIndexNums.pv.toLocaleString() }}</p>
+        </a-col>
+        <a-col :span="6">
+          <p class="t1">会话数</p>
+          <p class="t3">{{ flowIndexNums.sessions.toLocaleString() }}</p>
+        </a-col>
+        <a-col :span="6">
+          <p class="t1">询盘数</p>
+          <p class="t3">{{ flowIndexNums.enquiry.toLocaleString() }}</p>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="核心数据">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-row class="r5-1">
+                <a-col :span="24">
+                  <area-chart v-if="coreDataChart.x.length > 0" :dataSource="coreDataChart" />
+                  <a-empty v-else style="float: right; width: 100%; margin-top: 110px" />
+                </a-col>
+              </a-row>
+            </a-row>
+            <a-row class="r2">
+              <a-col style="width: 20%">
+                <p class="t1">日均访问量</p>
+                <p class="t3">{{ statistics.averageVisit.toLocaleString() }}</p>
+              </a-col>
+              <a-col style="width: 20%">
+                <p class="t1">平均访问时长</p>
+                <p class="t3">{{ statistics.averageVisitDuration }}</p>
+              </a-col>
+              <a-col style="width: 20%">
+                <p class="t1">访客平均访问页面数</p>
+                <p class="t3">{{ statistics.averageVisitPage.toLocaleString() }}</p>
+              </a-col>
+              <a-col style="width: 20%">
+                <p class="t1">跳出率</p>
+                <p class="t3">{{ statistics.bounceRate }}</p>
+              </a-col>
+              <a-col style="width: 20%">
+                <p class="t1">UV到询盘转化率</p>
+                <p class="t3">{{ statistics.conversionRate }}</p>
               </a-col>
             </a-row>
-          </a-row>
-          <a-row class="r2">
-            <a-col style="width: 20%;">
-              <p class="t1">日均访问量</p>
-              <p class="t3">{{ statistics.averageVisit.toLocaleString() }}</p>
-            </a-col>
-            <a-col style="width: 20%;">
-              <p class="t1">平均访问时长</p>
-              <p class="t3">{{ statistics.averageVisitDuration }}</p>
-            </a-col>
-            <a-col style="width: 20%;">
-              <p class="t1">访客平均访问页面数</p>
-              <p class="t3">{{ statistics.averageVisitPage.toLocaleString() }}</p>
-            </a-col>
-            <a-col style="width: 20%;">
-              <p class="t1">跳出率</p>
-              <p class="t3">{{ statistics.bounceRate }}</p>
-            </a-col>
-            <a-col style="width: 20%;">
-              <p class="t1">UV到询盘转化率</p>
-              <p class="t3">{{ statistics.conversionRate }}</p>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-      <a-col :span="24">
-        <a-card style="margin: 10px" title="访客数地域分布">
-          <a-row class="r5">
-            <a-col :span="18">
-              <map-adweb v-if="countryMapData.length > 0" :dataSource="countryMapData"
-                         height="400"></map-adweb>
-              <a-empty v-else style="margin-top: 50px;">
-              </a-empty>
-            </a-col>
-
-            <a-col :span="6">
-              <a-table
-                :rowKey="(record,index)=>{return index}"
-                class="chartTable"
-                :scroll="{ y: 500 }"
-                :pagination=false
-                :columns="chartDetailDataCol"
-                :data-source="chartDetailData"
-                :showHeader="false">
-                <template #bodyCell="{ column, record }">
-                  <template v-if="column.key === 'flagSlot' ">
-            <span class="img-box">
-              <span :class="'flag-icon flag-icon-'+record.countryCode"></span>
-            </span>
+          </a-card>
+        </a-col>
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="访客数地域分布">
+            <a-row class="r5">
+              <a-col :span="18">
+                <map-adweb v-if="countryMapData.length > 0" :dataSource="countryMapData" height="400" />
+                <a-empty v-else style="margin-top: 50px" />
+              </a-col>
+
+              <a-col :span="6">
+                <a-table
+                  :rowKey="
+                    (record, index) => {
+                      return index;
+                    }
+                  "
+                  class="chartTable"
+                  :scroll="{ y: 500 }"
+                  :pagination="false"
+                  :columns="chartDetailDataCol"
+                  :data-source="chartDetailData"
+                  :showHeader="false"
+                >
+                  <template #bodyCell="{ column, record }">
+                    <template v-if="column.key === 'flagSlot'">
+                      <span class="img-box">
+                        <span :class="'flag-icon flag-icon-' + record.countryCode"></span>
+                      </span>
+                    </template>
+                    <template v-if="column.key === 'numSlot'"> {{ record.totalUsers }} | {{ record.totalUsersProportion }} </template>
                   </template>
-                  <template v-if="column.key === 'numSlot' ">
-                    {{ record.totalUsers }} | {{ record.totalUsersProportion }}
+                </a-table>
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+
+        <a-col :span="12">
+          <a-card style="margin: 10px" title="访客数设备分布">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-col :span="24">
+                <DeviceStatsUV :deviceStats="deviceStats" />
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+        <a-col :span="12">
+          <a-card style="margin: 10px" title="浏览量设备分布">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-col :span="24">
+                <DeviceStatsPV :deviceStats="deviceStats" />
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+
+        <!-- 来源媒介 -->
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="来源媒介">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-col :span="24">
+                <a-table :columns="mediaListColumns" :data-source="mediaDatasource" size="middle" rowKey="type" :pagination="false">
+                  <template #filterDropdown>
+                    <div style="padding: 10px">
+                      affiliate:通过联属营销计划点击链接的用户<br />
+                      cpc:(每次点击费用的缩写)点击付费广告的用户<br />
+                      organic:点击搜索引擎中的链接的用户<br />
+                      referral:点击网站上的链接(例如,视频说明中的链接)的用户<br />
+                      (none):直接流量
+                    </div>
                   </template>
-                </template>
-              </a-table>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-
-      <a-col :span="12">
-        <a-card style="margin: 10px" title="访客数设备分布">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-col :span="24">
-              <DeviceStatsUV :deviceStats="deviceStats"></DeviceStatsUV>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-      <a-col :span="12">
-        <a-card style="margin: 10px" title="浏览量设备分布">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-col :span="24">
-              <DeviceStatsPV :deviceStats="deviceStats"></DeviceStatsPV>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-
-      <!-- 来源媒介 -->
-      <a-col :span="24">
-        
-        <a-card style="margin: 10px" title="来源媒介">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-col :span="24">
-              <a-table
-                :columns="mediaListColumns"
-                :data-source="mediaDatasource"
-                size="middle"
-                rowKey="type"
-                :pagination="false">
-                <div style="padding: 10px;" slot="filterDropdown">
-                  affiliate:通过联属营销计划点击链接的用户<br />
-                  cpc:(每次点击费用的缩写)点击付费广告的用户<br />
-                  organic:点击搜索引擎中的链接的用户<br />
-                  referral:点击网站上的链接(例如,视频说明中的链接)的用户<br />
-                  (none):直接流量
-                </div>
-                <a-icon slot="filterIcon" type='question-circle'
-                        :style="{ fontSize:'16px',color:  '#108ee9' }" />
-                <template #bodyCell="{ column, record, index, text }">
-                  <template v-if="column.key === 'typeSlotFirst' ">
-                    {{ record.type.split("/")[0] }}
+                  <template #filterIcon>
+                    <a-icon type="question-circle" :style="{ fontSize: '16px', color: '#108ee9' }" />
                   </template>
-                  <template v-if="column.key === 'typeSlotLast' ">
-                    <a-popover>
-                      <template slot="content">
-                        <template v-if="record.type.split('/')[1] === ' affiliate'">
-                          通过联属营销计划点击链接的用户
-                        </template>
-                        <template v-if="record.type.split('/')[1] === ' cpc'">
-                          (每次点击费用的缩写)点击付费广告的用户
-                        </template>
-                        <template v-if="record.type.split('/')[1] === ' organic'">
-                          点击搜索引擎中的链接的用户
-                        </template>
-                        <template v-if="record.type.split('/')[1] === ' referral'">
-                          点击网站上的链接(例如,视频说明中的链接)的用户
+                  <template #bodyCell="{ column, record, index, text }">
+                    <template v-if="column.key === 'typeSlotFirst'">
+                      {{ record.type.split('/')[0] }}
+                    </template>
+                    <template v-if="column.key === 'typeSlotLast'">
+                      <a-popover>
+                        <template #content>
+                          <template v-if="record.type.split('/')[1] === ' affiliate'"> 通过联属营销计划点击链接的用户 </template>
+                          <template v-if="record.type.split('/')[1] === ' cpc'"> (每次点击费用的缩写)点击付费广告的用户 </template>
+                          <template v-if="record.type.split('/')[1] === ' organic'"> 点击搜索引擎中的链接的用户 </template>
+                          <template v-if="record.type.split('/')[1] === ' referral'"> 点击网站上的链接(例如,视频说明中的链接)的用户 </template>
+                          <template v-if="record.type.split('/')[1] === ' (none)'"> 直接流量 </template>
                         </template>
-                        <template v-if="record.type.split('/')[1] === ' (none)'">
-                          直接流量
-                        </template>
-                      </template>
-                      {{ record.type.split("/")[1] }}
-                    </a-popover>
-                  </template>
-                  <template v-if="column.key === 'avgSessionDurationSlot' ">
-                    <span style="margin-left: 30px;">{{ record.avgSessionDuration }} s</span>
+                        {{ record.type.split('/')[1] }}
+                      </a-popover>
+                    </template>
+                    <template v-if="column.key === 'avgSessionDurationSlot'">
+                      <span style="margin-left: 30px">{{ record.avgSessionDuration }} s</span>
+                    </template>
                   </template>
-                </template>
-
-              </a-table>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-
-      <!-- 最多访问TOP10 -->
-      <a-col :span="24">
-        <a-card style="margin: 10px" title="最多访问TOP10">
-          <a-row class="r5" :gutter="[20,20]">
-            <a-col :span="24">
-              <a-table
-                :columns="mostAccessColumns"
-                :data-source="mostAccessDatasource"
-                size="middle"
-                rowKey="type"
-                :pagination="false">
-                <template #bodyCell="{ column, record, index, text }">
-                  <template v-if="column.key ==='pagePathSlot' ">
-                    <a-popover>
-                      <template slot="content">
-                        {{ text }}
-                      </template>
-                      <a :href="text" target="_blank">
-                        <div
-                          style="width: 700px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
+                </a-table>
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+
+        <!-- 最多访问TOP10 -->
+        <a-col :span="24">
+          <a-card style="margin: 10px" title="最多访问TOP10">
+            <a-row class="r5" :gutter="[20, 20]">
+              <a-col :span="24">
+                <a-table :columns="mostAccessColumns" :data-source="mostAccessDatasource" size="middle" rowKey="type" :pagination="false">
+                  <template #bodyCell="{ column, record, index, text }">
+                    <template v-if="column.key === 'pagePathSlot'">
+                      <a-popover>
+                        <template #content>
                           {{ text }}
-                        </div>
-                      </a>
-                    </a-popover>
-                  </template>
-                  <template v-if="column.key ==='centerSlot' ">
-                    <span style="margin-left: 20px;">{{ text }}</span>
-                  </template>
-                  <template v-if="column.key ==='avgTimeOnPageSlot' ">
-                    <span style="margin-left: 30px;">{{ text }} s</span>
+                        </template>
+                        <a :href="text" target="_blank">
+                          <div style="width: 700px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
+                            {{ text }}
+                          </div>
+                        </a>
+                      </a-popover>
+                    </template>
+                    <template v-if="column.key === 'centerSlot'">
+                      <span style="margin-left: 20px">{{ text }}</span>
+                    </template>
+                    <template v-if="column.key === 'avgTimeOnPageSlot'">
+                      <span style="margin-left: 30px">{{ text }} s</span>
+                    </template>
                   </template>
-                </template>
-              </a-table>
-            </a-col>
-          </a-row>
-        </a-card>
-      </a-col>
-    </a-row>
-  </a-spin>
+                </a-table>
+              </a-col>
+            </a-row>
+          </a-card>
+        </a-col>
+      </a-row>
+    </a-spin>
+  </div>
 </template>
 
 <script lang="ts" name="data-trafficAnalysis" setup>
-import selectSite from "@/components/Adweb/selectSite.vue";
-import areaChart from "./chart/areaChart.vue";
-import { computed, reactive, ref } from "vue";
-import { getAction } from "@/api/manage/manage";
-import MapAdweb from "@/components/chart/mapAdweb.vue";
-import DeviceStatsPV from "./components/DeviceStatsPV.vue";
-import DeviceStatsUV from "./components/DeviceStatsUV.vue";
-import "flag-icon-css/css/flag-icons.css";
-import dayjs from 'dayjs';
-
-
-const queryParam = reactive<any>({});
-queryParam.limit = 10;
-queryParam.siteCode = localStorage.getItem("siteCode");
-const loading = ref(false);
-const chartDetailDataCol = ref([
-  {
-    title: "国旗",
-    align: "center",
-    key: "flagSlot",
-    width: 30,
-    scopedSlots: { customRender: "flagSlot" }
-  },
-  {
-    title: "国家",
-    align: "left",
-    dataIndex: "countryName",
-    customRender: function(text, record) {
-      return text === null ? record.country : text;
-    }
-  },
-  {
-    title: "数量",
-    align: "right",
-    key: "numSlot",
-    scopedSlots: { customRender: "numSlot" }
-  }
-]);
-// 来源媒介列表
-const mediaListColumns = ref([
-  {
-    title: "来源",
-    key: "typeSlotFirst",
-    scopedSlots: {
-      customRender: "typeSlotFirst"
-    }
-  },
-  {
-    title: "媒介",
-    key: "typeSlotLast",
-    scopedSlots: {
-      filterDropdown: "filterDropdown",
-      filterIcon: "filterIcon",
-      customRender: "typeSlotLast"
-    }
-  },
-  {
-    title: "访客数(UV)",
-    dataIndex: "totalUsers"
-  },
-  {
-    title: "占比",
-    dataIndex: "totalUsersProportion"
-  },
-  {
-    title: "新访客数",
-    dataIndex: "newUsers"
-  },
-  {
-    title: "新客占比",
-    dataIndex: "newUsersRatio"
-  },
-  {
-    title: "浏览量(PV)",
-    dataIndex: "pageViews"
-  },
-  {
-    title: "平均访问页面数",
-    dataIndex: "pageViewsPerSession"
-  },
-  {
-    title: "会话数",
-    dataIndex: "sessions"
-  },
-  {
-    title: "平均会话时长",
-    key: "avgSessionDurationSlot",
-    sortDirections: ["descend", "ascend"],
-    sorter: (a, b) => a.avgSessionDuration - b.avgSessionDuration,
-    scopedSlots: {
-      customRender: "avgSessionDurationSlot"
-    }
+  import selectSite from '@/components/Adweb/selectSite.vue';
+  import areaChart from './chart/areaChart.vue';
+  import { computed, reactive, ref } from 'vue';
+  import { getAction } from '@/api/manage/manage';
+  import MapAdweb from '@/components/chart/mapAdweb.vue';
+  import DeviceStatsPV from './components/DeviceStatsPV.vue';
+  import DeviceStatsUV from './components/DeviceStatsUV.vue';
+  import 'flag-icon-css/css/flag-icons.css';
+  import dayjs from 'dayjs';
+
+  const queryParam = reactive<any>({});
+  queryParam.limit = 10;
+  queryParam.siteCode = localStorage.getItem('siteCode');
+  const loading = ref(false);
+  const chartDetailDataCol = ref([
+    {
+      title: '国旗',
+      align: 'center',
+      key: 'flagSlot',
+      width: 30,
+      scopedSlots: { customRender: 'flagSlot' },
+    },
+    {
+      title: '国家',
+      align: 'left',
+      dataIndex: 'countryName',
+      customRender: function (text, record) {
+        return text === null ? record.country : text;
+      },
+    },
+    {
+      title: '数量',
+      align: 'right',
+      key: 'numSlot',
+      scopedSlots: { customRender: 'numSlot' },
+    },
+  ]);
+  // 来源媒介列表
+  const mediaListColumns = ref([
+    {
+      title: '来源',
+      key: 'typeSlotFirst',
+      scopedSlots: {
+        customRender: 'typeSlotFirst',
+      },
+    },
+    {
+      title: '媒介',
+      key: 'typeSlotLast',
+      scopedSlots: {
+        filterDropdown: 'filterDropdown',
+        filterIcon: 'filterIcon',
+        customRender: 'typeSlotLast',
+      },
+    },
+    {
+      title: '访客数(UV)',
+      dataIndex: 'totalUsers',
+    },
+    {
+      title: '占比',
+      dataIndex: 'totalUsersProportion',
+    },
+    {
+      title: '新访客数',
+      dataIndex: 'newUsers',
+    },
+    {
+      title: '新客占比',
+      dataIndex: 'newUsersRatio',
+    },
+    {
+      title: '浏览量(PV)',
+      dataIndex: 'pageViews',
+    },
+    {
+      title: '平均访问页面数',
+      dataIndex: 'pageViewsPerSession',
+    },
+    {
+      title: '会话数',
+      dataIndex: 'sessions',
+    },
+    {
+      title: '平均会话时长',
+      key: 'avgSessionDurationSlot',
+      sortDirections: ['descend', 'ascend'],
+      sorter: (a, b) => a.avgSessionDuration - b.avgSessionDuration,
+      scopedSlots: {
+        customRender: 'avgSessionDurationSlot',
+      },
+    },
+  ]);
+
+  // 最多访问TOP10列表
+  const mostAccessColumns = ref([
+    {
+      title: '来源',
+      dataIndex: 'pagePath',
+      scopedSlots: {
+        customRender: 'pagePathSlot',
+      },
+    },
+    {
+      title: '浏览量(PV)',
+      dataIndex: 'pageViews',
+      defaultSortOrder: 'descend',
+      sorter: (a, b) => a.pageViews - b.pageViews,
+      width: 160,
+      scopedSlots: {
+        customRender: 'centerSlot',
+      },
+    },
+    {
+      title: '浏览量占比',
+      dataIndex: 'pvProportion',
+      width: 160,
+      scopedSlots: {
+        customRender: 'centerSlot',
+      },
+    },
+    // {
+    //   title: '平均页面停留时间',
+    //   dataIndex: 'avgTimeOnPage',
+    //   sortDirections: ['descend', 'ascend'],
+    //   width: 160,
+    //   scopedSlots: {
+    //     customRender: 'avgTimeOnPageSlot',
+    //   }
+    // },
+  ]);
+
+  function changeSite(selectedSiteInfo: any) {
+    queryParam.siteCode = selectedSiteInfo.code;
+    localStorage.setItem('siteCode', queryParam.siteCode);
+    reloadData();
   }
-]);
-
-// 最多访问TOP10列表
-const mostAccessColumns = ref([
-  {
-    title: "来源",
-    dataIndex: "pagePath",
-    scopedSlots: {
-      customRender: "pagePathSlot"
-    }
-  },
-  {
-    title: "浏览量(PV)",
-    dataIndex: "pageViews",
-    defaultSortOrder: "descend",
-    sorter: (a, b) => a.pageViews - b.pageViews,
-    width: 160,
-    scopedSlots: {
-      customRender: "centerSlot"
-    }
-  },
-  {
-    title: "浏览量占比",
-    dataIndex: "pvProportion",
-    width: 160,
-    scopedSlots: {
-      customRender: "centerSlot"
-    }
+
+  //重新刷新页面数据
+  function reloadData() {
+    loading.value = true;
+    getFlowIndexNumber();
+    getCountryMapData();
+    getMediaList();
+    getMostAccessList();
+    getDeviceStats();
   }
-  // {
-  //   title: '平均页面停留时间',
-  //   dataIndex: 'avgTimeOnPage',
-  //   sortDirections: ['descend', 'ascend'],
-  //   width: 160,
-  //   scopedSlots: {
-  //     customRender: 'avgTimeOnPageSlot',
-  //   }
-  // },
-]);
-
-function changeSite(selectedSiteInfo: any) {
-  queryParam.siteCode = selectedSiteInfo.code;
-  localStorage.setItem("siteCode", queryParam.siteCode);
-  reloadData();
-}
-
-//重新刷新页面数据
-function reloadData() {
-  loading.value = true;
-  getFlowIndexNumber();
-  getCountryMapData();
-  getMediaList();
-  getMostAccessList();
-  getDeviceStats();
-}
-
-const flowIndexNums = ref({
-  uv: 0,
-  pv: 0,
-  sessions: 0,
-  enquiry: 0
-});
-const coreDataChart = ref({
-  x: [],
-  uv: [],
-  pv: [],
-  enquiry: []
-});
-const statistics = ref({
-  averageVisit: 0,
-  averageVisitDuration: 0,
-  averageVisitPage: 0,
-  bounceRate: "0%",
-  conversionRate: "0%"
-});
-
-//访客量、浏览量、询盘数量、折线图以及统计
-const getFlowIndexNumber = async () => {
-  try {
-    const res = await getAction("/dmp-data/site-overview/stats", queryParam);
-    if (!res.result) {
-      flowIndexNums.value = {
-        uv: 0,
-        pv: 0,
-        sessions: 0,
-        enquiry: 0
-      };
-      coreDataChart.value = {
-        x: [],
-        uv: [],
-        pv: [],
-        enquiry: []
-      };
-      statistics.value = {
-        averageVisit: 0,
-        averageVisitDuration: 0,
-        averageVisitPage: 0,
-        bounceRate: "0%",
-        conversionRate: "0%"
-      };
-      loading.value = false;
-      return;
-    }
 
-    flowIndexNums.value.uv = res.result.totalUsers;
-    flowIndexNums.value.pv = res.result.pageViews;
-    flowIndexNums.value.sessions = res.result.sessions;
-    flowIndexNums.value.enquiry = res.result.enquires;
-    const r = res.result.dailyStats;
-    const x = [], pv = [], uv = [], enquiry = [];
-    if (r != null && r.length > 0) {
-      for (let item of r) {
-        x.push(item.date);
-        pv.push(item.pageViews);
-        uv.push(item.totalUsers);
-        enquiry.push(item.enquires);
+  const flowIndexNums = ref({
+    uv: 0,
+    pv: 0,
+    sessions: 0,
+    enquiry: 0,
+  });
+  const coreDataChart = ref({
+    x: [],
+    uv: [],
+    pv: [],
+    enquiry: [],
+  });
+  const statistics = ref({
+    averageVisit: 0,
+    averageVisitDuration: 0,
+    averageVisitPage: 0,
+    bounceRate: '0%',
+    conversionRate: '0%',
+  });
+
+  //访客量、浏览量、询盘数量、折线图以及统计
+  const getFlowIndexNumber = async () => {
+    try {
+      const res = await getAction('/dmp-data/site-overview/stats', queryParam);
+      if (!res.result) {
+        flowIndexNums.value = {
+          uv: 0,
+          pv: 0,
+          sessions: 0,
+          enquiry: 0,
+        };
+        coreDataChart.value = {
+          x: [],
+          uv: [],
+          pv: [],
+          enquiry: [],
+        };
+        statistics.value = {
+          averageVisit: 0,
+          averageVisitDuration: 0,
+          averageVisitPage: 0,
+          bounceRate: '0%',
+          conversionRate: '0%',
+        };
+        loading.value = false;
+        return;
       }
+
+      flowIndexNums.value.uv = res.result.totalUsers;
+      flowIndexNums.value.pv = res.result.pageViews;
+      flowIndexNums.value.sessions = res.result.sessions;
+      flowIndexNums.value.enquiry = res.result.enquires;
+      const r = res.result.dailyStats;
+      const x = [],
+        pv = [],
+        uv = [],
+        enquiry = [];
+      if (r != null && r.length > 0) {
+        for (let item of r) {
+          x.push(item.date);
+          pv.push(item.pageViews);
+          uv.push(item.totalUsers);
+          enquiry.push(item.enquires);
+        }
+      }
+      coreDataChart.value.x = x;
+      coreDataChart.value.pv = pv;
+      coreDataChart.value.uv = uv;
+      coreDataChart.value.enquiry = enquiry;
+
+      statistics.value.averageVisit = res.result.dailyTotalUsers;
+      statistics.value.averageVisitDuration = res.result.avgTimeOnPage;
+      statistics.value.averageVisitPage = res.result.pageViewsPerSession;
+      statistics.value.bounceRate = res.result.bounceRate;
+      statistics.value.conversionRate = res.result.enquiryConversionRate;
+      loading.value = false;
+    } catch (error) {
+      console.error(error);
+    }
+  };
+  const chartDetailData = ref([]);
+  const countryMapData = ref([]);
+
+  //访客数地域分布
+  const getCountryMapData = async () => {
+    try {
+      const res = await getAction('/dmp-data/country/stats', queryParam);
+      if (res.code === 200) {
+        chartDetailData.value = res.result;
+        countryMapData.value = chartDetailData.value.map((entry) => ({
+          name: entry.countryName,
+          value: entry.totalUsers,
+        }));
+      }
+    } catch (error) {
+      console.error(error);
+    }
+  };
+  const mediaDatasource = ref([]);
+
+  const deviceStats = ref([]); // 设备统计数据
+
+  // 新增获取设备统计数据的函数
+  const getDeviceStats = async () => {
+    try {
+      const res = await getAction('/dmp-data/device/stats', queryParam);
+      if (res.code === 200) {
+        deviceStats.value = res.result; // Update the deviceStats with the response
+      } else {
+        deviceStats.value = []; // Reset if there's an error
+      }
+    } catch (error) {
+      console.error(error);
+    }
+  };
+
+  //来源媒介列表、最多访问top10列表
+  const getMediaList = async () => {
+    try {
+      const res = await getAction('/dmp-data/source-medium/stats', queryParam);
+      if (res.code == 200) {
+        mediaDatasource.value = res.result;
+      } else {
+        mediaDatasource.value = [];
+      }
+    } catch (error) {
+      console.error(error);
+    }
+  };
+  const mostAccessDatasource = ref([]);
+
+  //
+  const getMostAccessList = async () => {
+    try {
+      const res = await getAction('/dmp-data/page-path/stats', queryParam);
+      if (res.code == 200) {
+        mostAccessDatasource.value = res.result;
+      } else {
+        mostAccessDatasource.value = [];
+      }
+    } catch (error) {
+      console.error(error);
     }
-    coreDataChart.value.x = x;
-    coreDataChart.value.pv = pv;
-    coreDataChart.value.uv = uv;
-    coreDataChart.value.enquiry = enquiry;
-
-    statistics.value.averageVisit = res.result.dailyTotalUsers;
-    statistics.value.averageVisitDuration = res.result.avgTimeOnPage;
-    statistics.value.averageVisitPage = res.result.pageViewsPerSession;
-    statistics.value.bounceRate = res.result.bounceRate;
-    statistics.value.conversionRate = res.result.enquiryConversionRate;
-    loading.value = false;
-  } catch (error) {
-    console.error(error);
-  }
-};
-const chartDetailData = ref([]);
-const countryMapData = ref([]);
-
-//访客数地域分布
-const getCountryMapData = async () => {
-  try {
-    const res = await getAction("/dmp-data/country/stats", queryParam);
-    if (res.code === 200) {
-      chartDetailData.value = res.result;
-      countryMapData.value = chartDetailData.value.map(entry => ({
-        name: entry.countryName,
-        value: entry.totalUsers
-      }));
-    }
-  } catch (error) {
-    console.error(error);
-  }
-};
-const mediaDatasource = ref([]);
-
-const deviceStats = ref([]); // 设备统计数据
-
-// 新增获取设备统计数据的函数
-const getDeviceStats = async () => {
-  try {
-    const res = await getAction("/dmp-data/device/stats", queryParam);
-    if (res.code === 200) {
-      deviceStats.value = res.result; // Update the deviceStats with the response
-    } else {
-      deviceStats.value = []; // Reset if there's an error
-    }
-  } catch (error) {
-    console.error(error);
-  }
-};
-
-//来源媒介列表、最多访问top10列表
-const getMediaList = async () => {
-  try {
-    const res = await getAction("/dmp-data/source-medium/stats", queryParam);
-    if (res.code == 200) {
-      mediaDatasource.value = res.result;
-    } else {
-      mediaDatasource.value = [];
-    }
-  } catch (error) {
-    console.error(error);
-  }
-};
-const mostAccessDatasource = ref([]);
-
-//
-const getMostAccessList = async () => {
-  try {
-    const res = await getAction("/dmp-data/page-path/stats", queryParam);
-    if (res.code == 200) {
-      mostAccessDatasource.value = res.result;
-    } else {
-      mostAccessDatasource.value = [];
-    }
-  } catch (error) {
-    console.error(error);
-  }
-};
+  };
 
-const rangeDate = ref([]);
+  const rangeDate = ref([]);
 
-const onChangeDatePicker = (date, dateString) => {
-  if (dateString.length > 0) {
-    rangeDate.value = date;
-    queryParam.start = dateString[0];
-    queryParam.end = dateString[1];
-    queryParam.dateType = undefined;
-    reloadData();
-  }
-};
-
-//日期选择只能今天之前
-function disabledDate(current) {
-  return current && current > dayjs();
-}
-
-const setTime = (time) => {
-  queryParam.dateType = time;
-  queryParam.start = "";
-  queryParam.end = "";
-
-  if (time == "") {
-    rangeDate.value = undefined;
-  } else if (time == "sevenDay") {
-    rangeDate.value = [dayjs().add(-7, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "thirtyDay") {
-    rangeDate.value = [dayjs().add(-30, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "yesterday") {
-    rangeDate.value = [dayjs().add(-1, 'd'), dayjs().add(-1, 'd')];
-  } else if (time == "today") {
-    rangeDate.value = [dayjs(), dayjs()];
+  const onChangeDatePicker = (date, dateString) => {
+    if (dateString.length > 0) {
+      rangeDate.value = date;
+      queryParam.start = dateString[0];
+      queryParam.end = dateString[1];
+      queryParam.dateType = undefined;
+      reloadData();
+    }
+  };
+
+  //日期选择只能今天之前
+  function disabledDate(current) {
+    return current && current > dayjs();
   }
 
-  reloadData();
-};
+  const setTime = (time) => {
+    queryParam.dateType = time;
+    queryParam.start = '';
+    queryParam.end = '';
+
+    if (time == '') {
+      rangeDate.value = undefined;
+    } else if (time == 'sevenDay') {
+      rangeDate.value = [dayjs().add(-7, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'thirtyDay') {
+      rangeDate.value = [dayjs().add(-30, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'yesterday') {
+      rangeDate.value = [dayjs().add(-1, 'd'), dayjs().add(-1, 'd')];
+    } else if (time == 'today') {
+      rangeDate.value = [dayjs(), dayjs()];
+    }
 
+    reloadData();
+  };
 </script>
 <style lang="less" scoped>
-.self-pop {
-  .ant-popover-inner-content {
-    background: rgb(245, 243, 254);
+  .self-pop {
+    .ant-popover-inner-content {
+      background: rgb(245, 243, 254);
 
-    p {
-      font-size: 13px;
+      p {
+        font-size: 13px;
+      }
     }
-  }
 
-  .ant-popover-arrow {
-    border-color: rgb(245, 243, 254) !important;
-  }
-}
-
-.img-box {
-  width: 22px;
-  height: 15px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-
-  img {
-    width: 100%;
-    height: 100%;
-  }
-}
-
-.ant-alert {
-  /deep/ .ant-btn {
-    border-radius: 0;
-    margin-left: 10px;
+    .ant-popover-arrow {
+      border-color: rgb(245, 243, 254) !important;
+    }
   }
-}
 
-.theme-color {
-  color: @primary-color;
-}
-
-.r1 {
-  margin: 20px;
-
-  .choose-site {
+  .img-box {
+    width: 22px;
+    height: 15px;
     display: flex;
-  }
+    justify-content: center;
+    align-items: center;
 
-  .t1 {
-    font-size: 18px;
-    font-weight: 400;
-    letter-spacing: 0px;
-    line-height: 32px;
-    margin-left: 10px;
+    img {
+      width: 100%;
+      height: 100%;
+    }
   }
 
-  .ant-form-item {
-    flex: 1;
+  .ant-alert {
+    /deep/ .ant-btn {
+      border-radius: 0;
+      margin-left: 10px;
+    }
   }
 
-  .ant-calendar-picker {
-    margin-right: 20px;
+  .theme-color {
+    color: @primary-color;
   }
 
+  .r1 {
+    margin: 20px;
 
-  /deep/ .ant-btn {
-    background: transparent;
-    margin-right: 10px;
-    padding: 4px 15px;
-    border: 1px solid #d9d9d9;
-    border-radius: 4px;
-    transition: all 0.3s;
+    .choose-site {
+      display: flex;
+    }
 
-    &:hover {
-      color: @primary-color;
-      border-color: @primary-color;
+    .t1 {
+      font-size: 18px;
+      font-weight: 400;
+      letter-spacing: 0px;
+      line-height: 32px;
+      margin-left: 10px;
     }
 
-    &.active {
-      color: @primary-color;
-      background: #e6f7ff;
-      border-color: @primary-color;
+    .ant-form-item {
+      flex: 1;
+    }
+
+    .ant-calendar-picker {
+      margin-right: 20px;
     }
-  }
 
-  .time-btn-group {
     /deep/ .ant-btn {
-      background: #fff;
+      background: transparent;
+      margin-right: 10px;
       padding: 4px 15px;
       border: 1px solid #d9d9d9;
+      border-radius: 4px;
       transition: all 0.3s;
-      margin-right: 0;
-
-      &:first-child {
-        border-top-left-radius: 4px;
-        border-bottom-left-radius: 4px;
-      }
-
-      &:last-child {
-        border-top-right-radius: 4px;
-        border-bottom-right-radius: 4px;
-      }
-
-      &:not(:first-child) {
-        margin-left: -1px;
-      }
 
       &:hover {
         color: @primary-color;
         border-color: @primary-color;
-        position: relative;
-        z-index: 1;
-        background: #fff;
       }
 
       &.active {
         color: @primary-color;
         background: #e6f7ff;
         border-color: @primary-color;
-        position: relative;
-        z-index: 2;
       }
     }
-  }
-}
 
-.r2 {
-  background: #fff;
-  padding: 30px 20px;
-  margin: 10px;
+    .time-btn-group {
+      /deep/ .ant-btn {
+        background: #fff;
+        padding: 4px 15px;
+        border: 1px solid #d9d9d9;
+        transition: all 0.3s;
+        margin-right: 0;
+
+        &:first-child {
+          border-top-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+        }
 
-  .ant-col:not(:last-child) {
-    border-right: 1px solid #e6e6e6;
-  }
+        &:last-child {
+          border-top-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+        }
 
-  p {
-    margin: 0;
-    text-align: center;
+        &:not(:first-child) {
+          margin-left: -1px;
+        }
 
-    &.t1 {
-      color: #333;
-      margin-bottom: 15px;
+        &:hover {
+          color: @primary-color;
+          border-color: @primary-color;
+          position: relative;
+          z-index: 1;
+          background: #fff;
+        }
 
-      img {
-        margin-right: 10px;
-        width: 15px;
-        margin-top: -5px;
+        &.active {
+          color: @primary-color;
+          background: #e6f7ff;
+          border-color: @primary-color;
+          position: relative;
+          z-index: 2;
+        }
       }
     }
-
-    &.t2 {
-      color: @primary-color;
-      font-size: 30px;
-      font-weight: 500;
-      line-height: 1;
-      padding-left: 25px;
-    }
-
-    &.t3 {
-      font-size: 32px;
-      font-weight: 700;
-      letter-spacing: 0px;
-      line-height: 38px;
-      color: rgba(13, 62, 122, 1);
-    }
   }
-}
-
-.r5 {
-  background: #fff;
-  padding: 10px;
-  border-radius: 10px;
-  margin: 0 !important;
 
-  .wrap {
-    box-shadow: 0px 2px 4px 0px @primary-color;
-    padding: 15px;
-    border-radius: 10px;
-    overflow: hidden;
+  .r2 {
     background: #fff;
-    transition: all .3s;
+    padding: 30px 20px;
+    margin: 0 10px 10px 10px;
 
-    &.blue {
-      box-shadow: 0px 2px 4px 0px @primary-color;
+    .ant-col:not(:last-child) {
+      border-right: 1px solid #e6e6e6;
     }
 
-    &.effect:hover {
-      box-shadow: none;
-      background: rgb(241, 248, 255);
-    }
+    p {
+      margin: 0;
+      text-align: center;
 
-    img {
-      width: 15px;
-    }
+      &.t1 {
+        color: #333;
+        margin-bottom: 15px;
 
-    .fr {
-      float: right;
-      width: calc(100% - 15px);
-      text-align: center;
+        img {
+          margin-right: 10px;
+          width: 15px;
+          margin-top: -5px;
+        }
+      }
 
-      p:last-child {
+      &.t2 {
+        color: @primary-color;
         font-size: 30px;
-        text-align: center;
-        margin-top: 10px;
+        font-weight: 500;
+        line-height: 1;
+        padding-left: 25px;
+      }
 
+      &.t3 {
+        font-size: 32px;
+        font-weight: 700;
+        letter-spacing: 0px;
+        line-height: 38px;
+        color: rgba(13, 62, 122, 1);
       }
     }
   }
 
-  /deep/ .ant-table-thead > tr > th {
-    background: rgb(241, 248, 255);
-    border: none;
-    color: #000;
+  .r5 {
+    background: #fff;
     padding: 10px;
-  }
+    border-radius: 10px;
+    margin: 0 !important;
 
-  /deep/ .ant-table-tbody .ant-table-row td {
-    padding: 10px;
-    color: #000;
-  }
+    .wrap {
+      box-shadow: 0px 2px 4px 0px @primary-color;
+      padding: 15px;
+      border-radius: 10px;
+      overflow: hidden;
+      background: #fff;
+      transition: all 0.3s;
+
+      &.blue {
+        box-shadow: 0px 2px 4px 0px @primary-color;
+      }
+
+      &.effect:hover {
+        box-shadow: none;
+        background: rgb(241, 248, 255);
+      }
 
-  .r5-1 {
-    display: inline-block;
-    width: 100%;
-    margin-top: 30px;
+      img {
+        width: 15px;
+      }
 
-    .fl {
-      float: left;
-      position: relative;
+      .fr {
+        float: right;
+        width: calc(100% - 15px);
+        text-align: center;
 
-      .ant-btn {
-        border-radius: 0;
-        border: none;
-        margin-right: 10px;
+        p:last-child {
+          font-size: 30px;
+          text-align: center;
+          margin-top: 10px;
+        }
       }
     }
 
-    .fr {
-      float: right;
-      line-height: 2;
+    /deep/ .ant-table-thead > tr > th {
+      background: rgb(241, 248, 255);
+      border: none;
+      color: #000;
+      padding: 10px;
+    }
 
-      span {
-        margin-right: 30px;
+    /deep/ .ant-table-tbody .ant-table-row td {
+      padding: 10px;
+      color: #000;
+    }
 
-        i {
-          display: inline-block;
-          width: 25px;
-          height: 3px;
-          background: #544BEB;
-          position: relative;
-          top: -4px;
-          margin-right: 20px;
+    .r5-1 {
+      display: inline-block;
+      width: 100%;
+      margin-top: 30px;
+
+      .fl {
+        float: left;
+        position: relative;
+
+        .ant-btn {
+          border-radius: 0;
+          border: none;
+          margin-right: 10px;
         }
+      }
 
-        &:last-child i {
-          background: #F0B358;
+      .fr {
+        float: right;
+        line-height: 2;
+
+        span {
+          margin-right: 30px;
+
+          i {
+            display: inline-block;
+            width: 25px;
+            height: 3px;
+            background: #544beb;
+            position: relative;
+            top: -4px;
+            margin-right: 20px;
+          }
+
+          &:last-child i {
+            background: #f0b358;
+          }
         }
       }
     }
-  }
 
-  .box {
-    border-radius: 10px;
-    text-align: center;
-    min-height: 180px;
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
+    .box {
+      border-radius: 10px;
+      text-align: center;
+      min-height: 180px;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
 
-    p {
-      color: #fff;
+      p {
+        color: #fff;
 
-      img {
-        width: 19px;
-        margin: -5px 10px 0 0;
+        img {
+          width: 19px;
+          margin: -5px 10px 0 0;
+        }
       }
-    }
 
-    .num {
-      font-size: 30px;
-      margin-bottom: 10px;
-    }
+      .num {
+        font-size: 30px;
+        margin-bottom: 10px;
+      }
 
-    &.b1 {
-      background: rgb(233, 107, 95);
-    }
+      &.b1 {
+        background: rgb(233, 107, 95);
+      }
 
-    &.b2 {
-      background: rgb(88, 204, 168);
-    }
+      &.b2 {
+        background: rgb(88, 204, 168);
+      }
 
-    &.b3 {
-      background: rgb(124, 152, 252);
-    }
+      &.b3 {
+        background: rgb(124, 152, 252);
+      }
 
-    &.b4 {
-      background: #F0B358;
+      &.b4 {
+        background: #f0b358;
+      }
     }
   }
-}
 </style>

+ 12 - 1
src/views/adweb/site/AdwebSite.api.ts

@@ -1,6 +1,11 @@
 import { defHttp } from '/src/utils/http/axios';
 import { useMessage } from '/src/hooks/web/useMessage';
-
+import { getTenantById } from '@/views/system/tenant/tenant.api';
+import { getAuthCache } from '@/utils/auth';
+import { TENANT_ID } from '@/enums/cacheEnum';
+import { RoleEnum } from '@/enums/roleEnum';
+import { useUserStore } from '@/store/modules/user';
+const userStore = useUserStore();
 const { createConfirm } = useMessage();
 
 enum Api {
@@ -87,3 +92,9 @@ export const getGoogleAdsAccount = (params) => defHttp.get({ url: Api.getGoogleA
  * @param params
  */
 export const bindGoogleAdsAccount = (params) => defHttp.post({ url: Api.bindGoogleAdsAccount, params }, { joinParamsToUrl: true });
+
+export const isSohoeb2b = async (params) => {
+  const result = await getTenantById({ id: getAuthCache(TENANT_ID) });
+
+  return userStore.getRoleList.includes(RoleEnum.ADWEB_CHANNEL_ADMIN) && result.name.includes('苏豪纺织集团');
+};

+ 8 - 0
src/views/adweb/site/AdwebSite.data.ts

@@ -1,5 +1,6 @@
 import { BasicColumn } from '/src/components/Table';
 import dayjs from 'dayjs';
+import { isSohoeb2b } from '@/views/adweb/site/AdwebSite.api';
 
 //列表数据
 export const columns: BasicColumn[] = [
@@ -64,6 +65,13 @@ export const columns: BasicColumn[] = [
     dataIndex: 'completeProcess',
   },
   {
+    title: '订单url',
+    align: 'left',
+    dataIndex: 'orderUrl',
+    // 编辑时隐藏密码框
+    ifShow: await isSohoeb2b({}),
+  },
+  {
     title: '创建时间',
     align: 'left',
     dataIndex: 'ctime',

+ 73 - 36
src/views/adweb/site/AdwebSiteList.vue

@@ -161,16 +161,16 @@
     <!--SEO流程-->
     <seo-process ref="seoProcessRef" :visible="seoProcessVisible" :title="processTitle" @close="closeProcess" @reload="reload" />
     <google-ads-modal ref="googleAdsModalRef" @success="reload" />
+    <Sohoeb2bOrder ref="sohoeb2bOrderRef" @reload="reload" />
   </div>
 </template>
 
 <script lang="ts" name="adweb-adwebSite" setup>
   import { computed, onBeforeMount, reactive, ref } from 'vue';
-  import { getAction } from '/@/api/manage/manage';
   import { BasicTable, TableAction } from '/src/components/Table';
   import { useListPage } from '/src/hooks/system/useListPage';
   import { columns, superQuerySchema } from './AdwebSite.data';
-  import { batchDelete, deleteOne, getExportUrl, getImportUrl, list, gtmListUrl, saveOrUpdate } from './AdwebSite.api';
+  import { batchDelete, deleteOne, getExportUrl, getImportUrl, list, saveOrUpdate } from './AdwebSite.api';
   import AdwebSiteModal from './components/AdwebSiteModal.vue';
   import { useUserStore } from '/src/store/modules/user';
   import SeoProcess from '@/views/adweb/site/components/SeoProcess.vue';
@@ -181,6 +181,10 @@
   import { useMessage } from '@/hooks/web/useMessage';
   import SiteSetEnquiry from '@/views/adweb/site/components/SiteSetEnquiry.vue';
   import GoogleAdsModal from './components/GoogleAdsModal.vue';
+  import { getAuthCache } from '@/utils/auth';
+  import { TENANT_ID } from '@/enums/cacheEnum';
+  import { getTenantById } from '@/views/system/tenant/tenant.api';
+  import Sohoeb2bOrder from '@/views/adweb/site/components/Sohoeb2bOrder.vue';
 
   const formRef = ref();
   const queryParam = reactive<any>({});
@@ -190,6 +194,7 @@
   const processTitle = ref('');
   const seoProcessVisible = ref(false);
   const seoProcessRef = ref();
+  const sohoeb2bOrderRef = ref();
   const gtmRef = ref();
   const siteSetEnquiryRef = ref();
   const googleAdsModalRef = ref();
@@ -209,6 +214,14 @@
     );
   });
 
+  // 租户管理员角色
+  const isTenantAdmin = computed(() => {
+    return userStore.getRoleList.includes(RoleEnum.ADWEB_CHANNEL_ADMIN);
+  });
+
+  // 是否是苏豪纺织的租户
+  const isSohoeb2b = ref(false);
+
   const { createMessage } = useMessage();
 
   //注册table数据
@@ -254,6 +267,10 @@
   // 高级查询配置
   const superQueryConfig = reactive(superQuerySchema);
 
+  onBeforeMount(async () => {
+    isSohoeb2bTenant();
+  });
+
   /**
    * 高级查询事件
    */
@@ -311,6 +328,12 @@
       .finally(() => {});
   }
 
+  function isSohoeb2bTenant() {
+    getTenantById({ id: getAuthCache(TENANT_ID) }).then((res) => {
+      isSohoeb2b.value = res.name.includes('苏豪纺织集团');
+    });
+  }
+
   /**
    * 批量删除事件
    */
@@ -346,45 +369,55 @@
         label: '详情',
         onClick: handleDetail.bind(null, record),
       },
-      {
-        label: '询盘设置',
-        onClick: setEnquiry.bind(null, record),
-      },
     ];
 
-    // 站点不是删除状态
-    if (record.status != 0) {
+    // 针对租户管理员,并且是苏豪纺织的租户,可以查看订单管理
+    if (isTenantAdmin.value && isSohoeb2b.value) {
       dropDown.push({
-        label: '站点删除',
-        onClick: siteDeleteStatus.bind(null, record),
+        label: '订单管理',
+        onClick: setSohoeb2bOrder.bind(null, record),
       });
-    }
-
-    // 站点已发布,并且是正式域名时可以添加GTM 代码
-    if (record.isDomain === 1 && record.status === 1) {
-      dropDown.push(
-        {
-          label: 'GTM代码',
-          onClick: addGtm.bind(null, record),
-        },
-        {
-          label: 'Google Ads',
-          onClick: bindGoogleAds.bind(null, record),
-        }
-      );
-    }
-
-    // 当前是管理员,并且站点是被删除状态
-    if (isAdmin.value && record.status === 0) {
+    } else {
       dropDown.push({
-        label: '资源删除',
-        popConfirm: {
-          title: '该站点将从系统中删除,站点资源将会保留15天,是否确认删除',
-          confirm: handleDelete.bind(null, record),
-          placement: 'topLeft',
-        },
+        label: '询盘设置',
+        onClick: setEnquiry.bind(null, record),
       });
+
+      // 站点不是删除状态
+      if (record.status != 0) {
+        dropDown.push({
+          label: '站点删除',
+          onClick: siteDeleteStatus.bind(null, record),
+        });
+      }
+
+      // 站点已发布,并且是正式域名时可以添加GTM 代码
+      if (record.isDomain === 1 && record.status === 1) {
+        dropDown.push(
+          {
+            label: 'GTM代码',
+            onClick: addGtm.bind(null, record),
+          },
+          {
+            label: 'Google Ads',
+            onClick: bindGoogleAds.bind(null, record),
+          }
+        );
+      }
+
+      // 当前是管理员,并且站点是被删除状态
+      if (isAdmin.value && record.status === 0) {
+        dropDown.push({
+          label: '资源删除',
+          popConfirm: {
+            title: '该站点将从系统中删除,站点资源将会保留15天,是否确认删除',
+            confirm: handleDelete.bind(null, record),
+            placement: 'topLeft',
+          },
+        });
+      }
     }
+
     return dropDown;
   }
 
@@ -394,8 +427,12 @@
   }
 
   // 询盘设置
-  function setEnquiry(r) {
-    siteSetEnquiryRef.value.init(r);
+  function setEnquiry(record) {
+    siteSetEnquiryRef.value.init(record);
+  }
+
+  function setSohoeb2bOrder(record) {
+    sohoeb2bOrderRef.value.init(record);
   }
 
   /**

+ 124 - 0
src/views/adweb/site/components/Sohoeb2bOrder.vue

@@ -0,0 +1,124 @@
+<template>
+  <a-drawer
+    title="订单设置"
+    :maskClosable="true"
+    width="850"
+    placement="right"
+    :closable="true"
+    @close="handleCancel"
+    v-model:open="modalVisible"
+    :ok-button-props="okBtnStatus"
+    destroy-on-close
+    style="overflow: auto; padding-bottom: 53px"
+  >
+    <!--订单设置-->
+    <a-spin :spinning="spinning" :tip="tipTitle">
+      <a-form ref="formRef" :model="formState" :rules="formRules" :label-col="labelCol" :wrapper-col="wrapperCol">
+        <a-form-item label="订单URL" name="orderUrl">
+          <a-input placeholder="请输入订单URL" v-model:value="formState.orderUrl" />
+        </a-form-item>
+
+        <a-form-item hidden="hidden" label="ID" name="id">
+          <a-input type="hidden" placeholder="订单ID" v-model:value="formState.orderUrlID" />
+        </a-form-item>
+      </a-form>
+    </a-spin>
+
+    <div
+      :style="{
+        position: 'absolute',
+        right: 0,
+        bottom: 0,
+        width: '100%',
+        borderTop: '1px solid #e9e9e9',
+        padding: '10px 16px',
+        background: '#fff',
+        textAlign: 'right',
+        zIndex: 1,
+      }"
+    >
+      <a-button type="primary" @click="handleOk" v-if="okBtnStatus" :loading="loadingDrawerBtn"> 提交 </a-button>
+    </div>
+  </a-drawer>
+</template>
+
+<script setup lang="ts">
+  import { reactive, ref } from 'vue';
+  import { postAction } from '@/api/manage/manage';
+  import { useMessage } from '@/hooks/web/useMessage';
+  import pick from 'lodash.pick';
+
+  const modalVisible = ref(false);
+  const labelCol = reactive({ span: 3 });
+  const wrapperCol = reactive({ span: 21 });
+  const spinning = ref(false);
+  const tipTitle = ref('');
+  let formState = reactive({ code: '', orderUrl: '', domain: '', orderUrlID: '' });
+  const okBtnStatus = ref(true);
+  const loadingDrawerBtn = ref(false);
+
+  const formRef = ref();
+  const formRules = reactive({
+    orderUrl: [{ required: true, message: '订单URL必填', trigger: 'blur' }],
+  });
+  const { createMessage } = useMessage();
+
+  function init(record) {
+    Object.assign(formState, pick(record, 'code', 'orderUrl', 'domain', 'orderUrlID'));
+    modalVisible.value = true;
+  }
+
+  function handleCancel() {
+    formState.orderUrlID = '';
+    formState.orderUrl = '';
+    formState.domain = '';
+    formState.code = '';
+    spinning.value = false;
+    modalVisible.value = false;
+    loadingDrawerBtn.value = false;
+  }
+
+  async function handleOk() {
+    await formRef.value
+      .validate()
+      .then(() => {
+        loadingDrawerBtn.value = true;
+        spinning.value = true;
+
+        let orderUrlData = {
+          siteCode: formState.code,
+          domainName: formState.domain,
+          orderUrl: formState.orderUrl,
+          id: formState.orderUrlID,
+        };
+
+        postAction('/adweb/adwebSiteManage/set/order/url', orderUrlData, 120000)
+          .then(function (res) {
+            console.log('res:{}', res);
+            if (res.code == 200) {
+              modalVisible.value = false;
+
+              createMessage.success('操作成功!');
+            } else {
+              createMessage.error(res.message);
+            }
+          })
+          .catch(function (err) {
+            console.log(err);
+            loadingDrawerBtn.value = false;
+            spinning.value = false;
+          })
+          .finally(() => {
+            loadingDrawerBtn.value = false;
+            spinning.value = false;
+          });
+      })
+      .catch(() => {
+        return false;
+      });
+  }
+
+  defineExpose({ init });
+</script>
+
+<style scoped lang="less"></style>