Przeglądaj źródła

完善首页数据、出包渠道

wangzhiqiang 4 miesięcy temu
rodzic
commit
f3084e4140

+ 10 - 0
src/api/dashboard.js

@@ -0,0 +1,10 @@
+import request from '@/utils/system/request'
+
+// 查询广告平台收益
+export function getIndexProfit(data) {
+    return request({
+        url: '/agent-service/index/profit',
+        method: 'post',
+        data
+    })
+}

+ 38 - 0
src/api/outBagModule.js

@@ -0,0 +1,38 @@
+import request from '@/utils/system/request'
+
+// 新增渠道类型
+export function ditchAddOne(data) {
+    return request({
+        url: '/agent-service/ditch/addOne',
+        method: 'post',
+        data
+    })
+}
+
+// 删除渠道类型
+export function ditchDeleteOne(params) {
+    return request({
+        url: '/agent-service/ditch/deleteOne',
+        method: 'get',
+        params
+    })
+}
+
+// 获取渠道类型列表
+export function ditchList(data) {
+    return request({
+        url: '/agent-service/ditch/list',
+        method: 'post',
+        data
+    })
+}
+
+// 修改渠道类型
+export function ditchUpdateOne(data) {
+    return request({
+        url: '/agent-service/ditch/updateOne',
+        method: 'post',
+        data
+    })
+}
+

+ 379 - 204
src/views/main/dashboard/components/charts/earningsChart.vue

@@ -1,242 +1,417 @@
 <template>
     <div class="layout-container-main" id="jcsb">
         <div class="item" id="box1">
-            <div class="layout-container-main-top" style="display: flex;justify-content: space-between;">
+            <div class="layout-container-main-top">
                 <div class="top-left">
                     <div class="line"></div>
-                    <span>用户在线量</span>
-                    <!--  <div v-for="(item, index) in options" :key="item.value">
-                        <span class="text" :class="{ active: tabIndex == index }" @click="clickTap(index, item)">{{
-                            item.label
-                            }}</span>
-                    </div> -->
+                    <span>收益</span>
+                </div>
+                <div class="main">
+                    <el-row>
+                        <el-col :span="8">
+                            <el-statistic title="今日收益" :value="268.5" precision="2" />
+                        </el-col>
+                        <el-col :span="8">
+                            <el-statistic title="昨日收益" :value="2685" precision="2" />
+                        </el-col>
+                        <el-col :span="8">
+                            <el-statistic title="本月收益" :value="2685" precision="2" />
+                        </el-col>
+                    </el-row>
                 </div>
-                <!--  <div>
-                    <el-select v-model="value1" placeholder="年份" style="width: 100px" @change="changeData1">
-                        <el-option v-for="item in year" :key="item.value" :label="`${item.label}年`"
-                            :value="item.value" />
-                    </el-select>
-                    <el-select v-model="value2" placeholder="月份" style="width: 80px" @change="changeData">
-                        <el-option v-for="(item, index) in 12" :key="index" :label="`${item}月`" :value="item" />
-                    </el-select>
-                </div> -->
-                <div class="main"></div>
             </div>
             <div class="main-echart" ref="chartRef">
-                <Chart :option="options" />
-            </div>
+                <el-table class="table" :data="tableData" border height="100%" :fit="true" :scroll-x="false"
+                    :style="{ width: '100%' }">
+                    <el-table-column prop="platform" label="统计" align="center" />
+                    <el-table-column prop="today" label="今日" align="center" />
+                    <el-table-column prop="yesterday" label="昨日" align="center" />
+                    <el-table-column prop="month" label="本月" align="center" />
+                </el-table>
 
+                <Chart class="chart" :option="options" />
+            </div>
         </div>
     </div>
 </template>
 
-<script lang="js" setup>
-    import { defineComponent, reactive, ref, onMounted } from 'vue'
-    import Chart from '@/components/charts/index.vue'
-    // import * as echarts from 'echarts'
-
-    const seriesData = [450, 200, 300, 520, 800, 760, 700, 680, 700, 650, 690, 710, 450, 200, 300, 520, 800, 760, 700, 680, 700, 650, 690, 710]
-    const xAxisList = [
-        '00:00',
-        '01:00',
-        '02:00',
-        '03:00',
-        '04:00',
-        '05:00',
-        '06:00',
-        '07:00',
-        '08:00',
-        '09:00',
-        '10:00',
-        '11:00',
-        '12:00',
-        '13:00',
-        '14:00',
-        '15:00',
-        '16:00',
-        '17:00',
-        '18:00',
-        '19:00',
-        '20:00',
-        '21:00',
-        '22:00',
-        '23:00',
-    ]
-    const options = {
-        title: {
-            text: "单位:个", // 主标题文本,支持使用 \n 换行
-            textStyle: {
-                color: "#808080", // 主标题文字的颜色
-                fontSize: 12 // 主标题文字的字体大小
-            },
-            left: "20", // title 组件离容器左侧的距离
-            top: "20" // title 组件离容器上侧的距离
+<script setup>
+import { defineComponent, reactive, ref, onMounted, onBeforeMount } from 'vue'
+import Chart from '@/components/charts/index.vue'
+import { getIndexProfit } from '@/api/dashboard.js'
+//穿山甲、优量汇、快手、Sigmob、百度
+
+// 收益统计表格数据格式
+const tableData = ref([])
+
+const getIndexProfitData = async () => {
+    let res = await getIndexProfit()
+    tableData.value = res.data
+
+    console.log('收益数据', res)
+}
+
+onBeforeMount(async () => {
+    await getIndexProfitData()
+})
+
+const xAxisList = [
+    '00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00',
+    '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00',
+    '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'
+];
+
+const seriesData = [450, 200, 300, 520, 800, 760, 700, 680, 700, 650, 690, 710, 450, 200, 300, 520, 800, 760, 700, 680, 700, 650, 690, 710];
+// 穿山甲数据(随机生成,保持原40-80范围)
+const seriesData1 = [42, 25, 33, 55, 76, 68, 72, 63, 71, 65, 62, 69, 45, 22, 31, 53, 79, 73, 68, 64, 72, 61, 67, 70];
+
+// 优量汇数据(模拟中型广告平台,范围200-500)
+const seriesData2 = (() => {
+    const base = [380, 210, 290, 470, 490, 420, 450, 430, 460, 410, 440, 480];
+    return [...base, ...base.map(v => v * 0.9)]; // 下午数据略降
+})();
+
+// 快手数据(模拟短视频平台,高峰在晚间)
+const seriesData3 = [
+    320, 180, 220, 300, 350,
+    420, 550, 680, 720, 650, // 早高峰
+    600, 580, 320, 280, 350,
+    480, 620, 750, 820, 880, // 晚高峰
+    760, 680, 550, 450
+];
+
+// Sigmob数据(模拟国际广告平台,较平稳)
+const seriesData4 = Array(24).fill(0).map(
+    (_, i) => 350 + Math.sin(i / 4) * 100 + (i > 12 ? -20 : 0) + Math.random() * 30
+).map(v => Math.round(v));
+
+// 百度数据(模拟搜索广告,白天稳定)
+const seriesData5 = xAxisList.map((_, i) =>
+    i < 8 ? 280 + i * 20 :       // 清晨上升
+        i < 18 ? 420 + (i % 3) * 15 :  // 白天稳定
+            400 - (i - 18) * 25            // 夜间下降
+);
+
+
+const options = {
+    /* title: {
+        text: "单位:个",
+        textStyle: {
+            color: "#808080",
+            fontSize: 12
+        },
+        left: "20",
+        top: "0"
+    }, */
+    grid: {
+        top: 20,
+        right: 20,
+        bottom: 0,  // 可根据需要设为 0~40
+        left: 40,
+        containLabel: true
+    },
+    tooltip: {
+        trigger: 'axis', // 触发类型为坐标轴
+        axisPointer: {
+            type: 'cross' // 指示器类型为十字准星
+        },
+        formatter: function (params) {
+            // 自定义提示框内容
+            let result = params[0].axisValue + '<br>'; // 显示时间点
+            params.forEach(function (item) {
+                // 为每个系列添加数据行
+                result += '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:'
+                    + item.color + '"></span>'
+                    + item.seriesName + ': ' + item.value + '<br>';
+            });
+            return result;
+        }
+    },
+    legend: {
+        data: ['平均收益', '穿山甲', '优量汇', '快手', 'Sigmob', '百度'],
+        top: 'top',
+        textStyle: {
+            color: '#808080'
+        }
+    },
+    xAxis: {
+        type: 'category',
+        data: xAxisList,
+        axisLabel: {
+            color: "#808080",
+            fontSize: 12
+        },
+        axisLine: {
+            show: false,
         },
-        tooltip: {
-            trigger: 'axis',
-            formatter: '{c}个' // 提示框浮层内容格式器
+        axisTick: {
+            show: false
         },
-        legend: {
-            data: ['在线量'],
-            top: 'top', // 或者自定义位置
-            textStyle: {
-                color: '#808080'
+        splitLine: {
+            show: false
+        },
+    },
+    yAxis: {
+        min: 0,
+        nameTextStyle: {
+            color: '#808080',
+            fontSize: 12,
+        },
+        axisLabel: {
+            color: "#808080",
+            fontSize: 12
+        },
+        axisLine: {
+            show: false
+        },
+        axisTick: {
+            show: false
+        },
+        splitLine: {
+            show: true,
+            lineStyle: {
+                color: 'rgba(0,0,0,0.15)',
             }
+        }
+    },
+    series: [
+        {
+            type: 'line',
+            name: '平均收益',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
+            },
+            itemStyle: {
+                color: '#70e3cd'
+            },
+            lineStyle: {
+                color: '#70e3cd',
+                width: 2,
+            },
+            data: seriesData,
+        },
+        {
+            type: 'line',
+            name: '穿山甲',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
+            },
+            itemStyle: {
+                color: '#add7f6'
+            },
+            lineStyle: {
+                color: '#add7f6',
+                width: 2,
+            },
+            data: seriesData1,
         },
-        xAxis: {
-            type: 'category',
-            data: xAxisList,
-            axisLabel: {
-                // 坐标轴字体颜色
-                color: "#808080",
-                fontSize: 12
+        {
+            type: 'line',
+            name: '优量汇',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
+            },
+            itemStyle: {
+                color: '#f7a8b8'
+            },
+            lineStyle: {
+                color: '#f7a8b8',
+                width: 2,
             },
-            axisLine: {
-                show: false, // 是否显示
+            data: seriesData2,
+        },
+        {
+            type: 'line',
+            name: '快手',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
             },
-            axisTick: { // y轴刻度线
-                show: false // 是否显示
+            itemStyle: {
+                color: '#ffcc5c'
             },
-            splitLine: { // 网格
-                show: false // 是否显示
+            lineStyle: {
+                color: '#ffcc5c',
+                width: 2,
             },
+            data: seriesData3,
         },
-        yAxis: {
-            min: 0,
-            nameTextStyle: {
-                color: '#808080',
-                fontSize: 12,
-            },
-            axisLabel: {
-                // 坐标轴字体颜色
-                color: "#808080",
-                fontSize: 12
-            },
-            axisLine: {
-                show: false
-            },
-            axisTick: {
-                // y轴刻度线
-                show: false
-            },
-            splitLine: { // 网格
-                show: true, // 是否显示
-                lineStyle: {
-                    color: 'rgba(0,0,0,0.15)', // 颜色
-                }
-            }
+        {
+            type: 'line',
+            name: 'Sigmob',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
+            },
+            itemStyle: {
+                color: '#88d8b0'
+            },
+            lineStyle: {
+                color: '#88d8b0',
+                width: 2,
+            },
+            data: seriesData4,
         },
+        {
+            type: 'line',
+            name: '百度',
+            symbolSize: 6,
+            z: 1,
+            label: {
+                show: false // Hide labels
+            },
+            itemStyle: {
+                color: '#9966cc'
+            },
+            lineStyle: {
+                color: '#9966cc',
+                width: 2,
+            },
+            data: seriesData5,
+        }
+    ]
+};
 
-        series: [
-            {
-                type: 'line',
-                name: '在线量',
-                symbolSize: 10,
-                z: 1,
-                label: {
-                    show: true, // 线条折点处显示值
-                    position: 'top', // 标签的位置
-                    color: "#808080", // 文字颜色
-                    fontSize: 12, // 文字像素
-                },
-                itemStyle: {
-                    color: '#325DEC' // 图形的颜色
-                },
-                lineStyle: {
-                    color: '#325DEC', // 线的颜色
-                    width: 1, // 线的宽度
-                },
-                data: seriesData, // 数据
-            }
-        ]
-    };
-
-    /*   const chartRef = ref(null)
-  
-      onMounted(() => {
-          const chart = echarts.init(chartRef.value)
-          chart.setOption(options)
-      }) */
 </script>
 
 <style lang="scss" scoped>
-    .box {
-        margin: 20px auto 0;
-        width: calc(100% - 40px);
-        /* height: 400px; */
-        background: var(--system-page-background);
-        padding: 20px 20px 10px;
-        overflow: hidden;
-    }
+.layout-container-main {
+    margin-top: 10px;
+    display: flex;
+    /* margin: 0 1.25rem; */
+    flex-wrap: wrap;
+    justify-content: space-between;
 
-    .layout-container-main {
+    .item {
+        width: calc(100vw - 1.13rem - 1.31rem);
         display: flex;
-        /* margin: 0 1.25rem; */
-        flex-wrap: wrap;
+        flex-direction: column;
+        padding: 1.13rem 1.31rem;
+        margin-bottom: 1.25rem;
+        /* height: 26.94rem; */
+        border-radius: 0.5rem;
+        background: #fff;
+        box-shadow: 0 0 0.13rem #00000029;
 
-        .item {
-            width: 100%;
+        .layout-container-main-top {
+            height: 6vh;
             display: flex;
-            flex-direction: column;
-            padding: 1.13rem 1.31rem;
-            margin-bottom: 1.25rem;
-            height: 26.94rem;
-            border-radius: 0.5rem;
-            background: #fff;
-            box-shadow: 0 0 0.13rem #00000029;
-
-            .layout-container-main-top {
-                height: 6vh;
-
-                .top-left {
-                    display: flex;
-
-                    .line {
-                        width: 0.25rem;
-                        height: 1.56rem;
-                        border-radius: 0.13rem;
-                        background: #fdb818;
-                    }
-
-                    span {
-                        margin: 0 1rem;
-                        font-family: "PingFang SC SNaNremibold";
-                        font-weight: 600;
-                        font-size: 1.13rem;
-
-                        color: #333;
-                    }
-
-                    .text {
-                        display: inline-block;
-                        // margin: 0 0.63rem;
-                        width: 3.63rem;
-                        font-weight: 400;
-                        height: 1.88rem;
-                        line-height: 1.88rem;
-                        border-radius: 0.25rem;
-                        background: transparent;
-                        border: 0.03rem solid #999;
-                        font-size: 0.88rem;
-                        text-align: center;
-                        color: #999;
-                        cursor: pointer;
-                    }
-
-                    .active {
-                        border-radius: 0.25rem;
-                        background: #fdb818;
-                        color: #fff;
-                        border: 0.03rem solid #fff;
-                    }
+            // justify-content: space-between;
+
+            .top-left {
+                display: flex;
+
+                .line {
+                    width: 0.25rem;
+                    height: 1.56rem;
+                    border-radius: 0.13rem;
+                    background: #409eff;
+                }
+
+                span {
+                    margin: 0 1rem;
+                    font-family: "PingFang SC SNaNremibold";
+                    font-weight: 600;
+                    font-size: 1.13rem;
+
+                    color: #333;
+                }
+
+                .text {
+                    display: inline-block;
+                    /* // margin: 0 0.63rem; */
+                    width: 3.63rem;
+                    font-weight: 400;
+                    height: 1.88rem;
+                    line-height: 1.88rem;
+                    border-radius: 0.25rem;
+                    background: transparent;
+                    border: 0.03rem solid #999;
+                    font-size: 0.88rem;
+                    text-align: center;
+                    color: #999;
+                    cursor: pointer;
+                }
+
+                .active {
+                    border-radius: 0.25rem;
+                    background: #fdb818;
+                    color: #fff;
+                    border: 0.03rem solid #fff;
                 }
             }
 
-            .main-echart {
-                width: 100%;
-                height: 55vh;
-                /* background-color: red; */
+            .main {
+                // flex: 1;
+                min-width: 300px;
+            }
+        }
+
+        .main-echart {
+            width: 100%;
+            display: flex;
+            height: 55vh;
+
+            .table {
+                flex: 1;
+                min-width: 250px;
+                /* 防止过窄导致表格挤压 */
+                overflow-x: auto;
+            }
+
+            .table :deep(.el-table__body-wrapper tbody tr) {
+                // height: calc(100% / 7);
+                height: calc(61vh / 6);
+            }
+
+            .chart {
+                flex: 3;
+                min-width: 300px;
+            }
+
+            @media screen and (max-width: 1024px) {
+                flex-direction: column;
+
+                .table,
+                .chart {
+                    width: 100%;
+                    min-width: unset;
+                }
+
+                .table {
+                    flex: 2;
+                    overflow-x: auto;
+                    margin-bottom: 10px;
+                }
+
+                .table :deep(.el-table__body-wrapper tbody tr) {
+                    height: calc(100% / 6);
+                }
+
+                .chart {
+                    flex: 3;
+                }
             }
         }
     }
+}
+
+
+.stats-table {
+    margin: 20px;
+    width: 100vw;
+}
+
+:deep(.el-table__header th) {
+    background-color: #f5f7fa;
+    font-weight: bold;
+}
 </style>

+ 61 - 24
src/views/main/dashboard/components/charts/ecpmChaet.vue

@@ -1,35 +1,23 @@
 <template>
-    <!-- <div class="layout-container-main" id="jcsb">
-        <div class="item" id="box1">
-            <div class="layout-container-main-top" style="display: flex;justify-content: space-between;">
-                <div class="top-left">
-                    <div class="line"></div>
-                    <span>ECPM趋势</span>
-                </div>
-                <div class="main"></div>
-            </div>
-            <div class="main-echart" style="height: 55vh;" ref="chartRef">
-                <Chart :option="options" />
-            </div>
-        </div>
-    </div> -->
     <div class="layout-container-main" id="jcsb">
-
         <div class="item" id="box1">
-            <div class="layout-container-main-top" style="display: flex;justify-content: space-between;">
+            <div class="layout-container-main-top">
                 <div class="top-left">
                     <div class="line"></div>
-                    <span>收益统计</span>
+                    <span>平均ECPM</span>
                 </div>
                 <div class="main"></div>
             </div>
             <div class="main-echart" ref="chartRef">
-                <el-table :data="tableData" border style="width: 100%">
+                <el-table class="table" :data="tableData" border height="100%" :fit="true" :scroll-x="false"
+                    :style="{ width: '100%' }">
                     <el-table-column prop="platform" label="统计" align="center" />
                     <el-table-column prop="today" label="今日" align="center" />
                     <el-table-column prop="yesterday" label="昨日" align="center" />
                     <el-table-column prop="month" label="本月" align="center" />
                 </el-table>
+
+                <Chart class="chart" :option="options" />
             </div>
         </div>
     </div>
@@ -86,8 +74,15 @@ const options = {
             fontSize: 12
         },
         left: "20",
-        top: "20"
+        top: "0"
     }, */
+    grid: {
+        top: 20,
+        right: 20,
+        bottom: 0,  // 可根据需要设为 0~40
+        left: 40,
+        containLabel: true
+    },
     tooltip: {
         trigger: 'axis', // 触发类型为坐标轴
         axisPointer: {
@@ -305,8 +300,7 @@ const tableData = ref([
     justify-content: space-between;
 
     .item {
-        width: 100%;
-        /* width: 40vw; */
+        width: calc(100vw - 1.13rem - 1.31rem);
         display: flex;
         flex-direction: column;
         padding: 1.13rem 1.31rem;
@@ -318,6 +312,8 @@ const tableData = ref([
 
         .layout-container-main-top {
             height: 6vh;
+            display: flex;
+            justify-content: space-between;
 
             .top-left {
                 display: flex;
@@ -326,7 +322,7 @@ const tableData = ref([
                     width: 0.25rem;
                     height: 1.56rem;
                     border-radius: 0.13rem;
-                    background: #fdb818;
+                    background: #409eff;
                 }
 
                 span {
@@ -365,8 +361,49 @@ const tableData = ref([
 
         .main-echart {
             width: 100%;
-            /* height: 55vh; */
-            /* background-color: red; */
+            display: flex;
+            height: 55vh;
+
+            .table {
+                flex: 1;
+                min-width: 250px;
+                /* 防止过窄导致表格挤压 */
+                overflow-x: auto;
+            }
+
+            .table :deep(.el-table__body-wrapper tbody tr) {
+                // height: calc(100% / 7);
+                height: calc(61vh / 6);
+            }
+
+            .chart {
+                flex: 3;
+                min-width: 300px;
+            }
+
+            @media screen and (max-width: 1024px) {
+                flex-direction: column;
+
+                .table,
+                .chart {
+                    width: 100%;
+                    min-width: unset;
+                }
+
+                .table {
+                    flex: 2;
+                    overflow-x: auto;
+                    margin-bottom: 10px;
+                }
+
+                .table :deep(.el-table__body-wrapper tbody tr) {
+                    height: calc(100% / 6);
+                }
+
+                .chart {
+                    flex: 3;
+                }
+            }
         }
     }
 }

+ 1 - 1
src/views/main/dashboard/components/charts/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div>
+    <earningsChart />
     <ecpmChaet />
     <userDataChart />
     <!-- <onlineChart /> -->
-    <!-- <earningsChart /> -->
 
     <!-- <barChart /> -->
     <!-- <el-row :gutter="20">

+ 50 - 12
src/views/main/dashboard/components/charts/userDataChart.vue

@@ -1,21 +1,22 @@
 <template>
     <div class="layout-container-main" id="jcsb">
         <div class="item" id="box1">
-            <div class="layout-container-main-top" style="display: flex;justify-content: space-between;">
+            <div class="layout-container-main-top">
                 <div class="top-left">
                     <div class="line"></div>
                     <span>平台用户行为数据统计与趋势图</span>
                 </div>
                 <div class="main"></div>
             </div>
-            <div class="main-echart" style="height: 55vh;" ref="chartRef">
-                <el-table class="table" :data="tableData" border height="100%">
+            <div class="main-echart" ref="chartRef">
+                <el-table class="table" :data="tableData" border height="100%" :fit="true" :scroll-x="false"
+                    :style="{ width: '100%' }">
                     <el-table-column prop="name" label="统计" align="center" />
                     <el-table-column prop="today" label="今日" align="center" />
                     <el-table-column prop="yesterday" label="昨日" align="center" />
                     <el-table-column prop="month" label="本月" align="center" />
                 </el-table>
-                <Chart class="line" :option="options" />
+                <Chart class="chart" :option="options" />
             </div>
         </div>
     </div>
@@ -27,6 +28,13 @@ import Chart from '@/components/charts/index.vue'
 //穿山甲、优量汇、快手、Sigmob、百度
 
 const options = {
+    grid: {
+        top: 20,
+        right: 20,
+        bottom: 0,  // 可根据需要设为 0~40
+        left: 40,
+        containLabel: true
+    },
     tooltip: {
         trigger: 'axis'
     },
@@ -37,8 +45,8 @@ const options = {
         type: 'category',
         boundaryGap: false,
         data: [
-            '2025-06-23 00:00', '2025-06-23 04:00', '2025-06-23 08:00',
-            '2025-06-23 12:00', '2025-06-23 16:00', '2025-06-23 20:00'
+            '00:00', '04:00', '08:00',
+            '12:00', '16:00', '20:00'
         ]
     },
     yAxis: {
@@ -113,7 +121,7 @@ const tableData = ref([
     justify-content: space-between;
 
     .item {
-        width: 100%;
+        width: calc(100vw - 1.13rem - 1.31rem);
         /* width: 40vw; */
         display: flex;
         flex-direction: column;
@@ -126,6 +134,8 @@ const tableData = ref([
 
         .layout-container-main-top {
             height: 6vh;
+            display: flex;
+            justify-content: space-between;
 
             .top-left {
                 display: flex;
@@ -134,7 +144,7 @@ const tableData = ref([
                     width: 0.25rem;
                     height: 1.56rem;
                     border-radius: 0.13rem;
-                    background: #fdb818;
+                    background: #409eff;
                 }
 
                 span {
@@ -173,21 +183,49 @@ const tableData = ref([
 
         .main-echart {
             width: 100%;
-            height: 500%;
             display: flex;
+            height: 55vh;
 
             .table {
                 flex: 1;
+                min-width: 250px;
+                /* 防止过窄导致表格挤压 */
+                overflow-x: auto;
             }
 
             .table :deep(.el-table__body-wrapper tbody tr) {
-                // height: calc(100% / 7);
-                height: calc(50.8vh / 7);
+                // height: calc(100% / 8);
+                height: calc(58.1vh / 8);
                 /* 均匀分7行 */
             }
 
-            .line {
+            .chart {
                 flex: 3;
+                min-width: 300px;
+            }
+
+            @media screen and (max-width: 1024px) {
+                flex-direction: column;
+
+                .table,
+                .chart {
+                    width: 100%;
+                    min-width: unset;
+                }
+
+                .table {
+                    flex: 2;
+                    overflow-x: auto;
+                    margin-bottom: 10px;
+                }
+
+                .table :deep(.el-table__body-wrapper tbody tr) {
+                    height: calc(100% / 8);
+                }
+
+                .chart {
+                    flex: 3;
+                }
             }
         }
     }

+ 3 - 3
src/views/main/formworkErection/adPlatformAdmin.vue

@@ -165,12 +165,12 @@
     loadDictData().then(() => {
       dynamicFormItems.value = [
         {
-          label: '渠道ID',
+          label: '平台ID',
           prop: 'nickName',
           type: 'input',
         },
         {
-          label: '渠道名称',
+          label: '平台名称',
           prop: 'nickName',
           type: 'input',
         },
@@ -194,7 +194,7 @@
           ]
         },
         {
-          label: '渠道状态',
+          label: '平台状态',
           prop: 'channelType',
           type: 'select',
           options: [

+ 13 - 1
src/views/main/formworkErection/appAdmin.vue

@@ -28,7 +28,19 @@
             </span>
           </template>
         </el-table-column>
-        <el-table-column prop="channelName" label="广告平台名称" width="120" />
+        <el-table-column prop="channelName" label="广告平台名称" width="160">
+          <template #default="scope">
+            <el-tag
+              style="margin-left: 5px;"
+              v-for="item in scope.row.channelName?.split(',')"
+              :key="item"
+              :type="item"
+              effect="dark"
+            >
+              {{ item }}
+            </el-tag>
+          </template>
+        </el-table-column>
         <el-table-column prop="networkAppName" label="关联渠道应用" width="120" />
         <el-table-column prop="nickName" label="所属用户" width="100" />
         <el-table-column prop="appType" label="应用类型" width="100">

+ 48 - 172
src/views/main/outBagModule/channelTypeAdmin.vue

@@ -8,28 +8,20 @@
     <div class="layout-container">
       <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
         @selection-change="handleSelectionChange">
-        <el-table-column prop="placementId" label="渠道类型" />
-        <el-table-column prop="placementName" label="用途" />
-        <el-table-column prop="adFormat" label="所属代理">
+        <el-table-column prop="ditchId" label="渠道ID" />
+        <el-table-column prop="ditchName" label="渠道类型名称" />
+        <el-table-column prop="createTime" label="创建时间">
           <template #default="scope">
-            {{ getDictionaryName("ad_format", scope.row.adFormat) }}
+            {{ convertUTCToBeijing(scope.row.createTime) }}
           </template>
         </el-table-column>
-        <el-table-column prop="appName" label="创建时间" />
-        <el-table-column prop="networkAppName" label="更新时间" />
-        <el-table-column prop="appType" label="操作人" width="100">
-          <template #default="scope">
-            {{ getDictionaryName("app_type", scope.row.appType) }}
-          </template>
-        </el-table-column>
-        <el-table-column prop="appName" label="备注" />
-        <el-table-column label="操作" fixed="right">
+        <el-table-column label="操作" fixed="right" width="200">
           <template #default="scope">
             <div class="button">
               <el-button class="button-item" type="primary" style="margin-bottom: 5px;" @click="edit(scope.row)">
                 编辑
               </el-button>
-              <el-popconfirm placement="left" title="确认删除该广告位?" @confirm="removeType(scope.row)">
+              <el-popconfirm placement="left" title="确认删除该渠道?" @confirm="removeType(scope.row)">
                 <template #reference>
                   <el-button class="button-item" style="margin-bottom: 5px;" type="danger">删除
                   </el-button>
@@ -43,39 +35,10 @@
 
     <!-- 操作弹窗 -->
     <Layer :layer="layer" @confirm="submit(ruleForm)" @close="layer.show = false">
-      <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="240px" style="margin-right:30px;">
-        <el-row :gutter="5">
-          <el-col :span="10">
-            <el-form-item label="渠道类型名称:" required prop="placementName">
-              <el-input v-model="formEdit.placementName" placeholder="请输入渠道类型名称" clearable />
-            </el-form-item>
-          </el-col>
-          <el-col :span="2"></el-col>
-          <el-col :span="10">
-            <el-form-item label="用途:" required prop="appData">
-              <el-select v-model="formEdit.appData" filterable placeholder="请选择用途">
-                <el-option v-for="item in useWayOptions" :key="item.label" :label="item.label" :value="item.value">
-                </el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="5">
-          <el-col :span="10">
-            <el-form-item label="所属代理:" required prop="adFormat">
-              <el-select v-model="formEdit.adFormat" placeholder="请选择所属代理">
-                <el-option v-for="item in agencyOptions" :key="item.label" :label="item.label" :value="item.value">
-                </el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="2"></el-col>
-          <el-col :span="10">
-            <el-form-item label="备注:" required prop="remark">
-              <el-input v-model="formEdit.remark" placeholder="请输入备注" clearable />
-            </el-form-item>
-          </el-col>
-        </el-row>
+      <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="120px" style="margin-right:30px;">
+        <el-form-item label="渠道类型名称:" required prop="ditchName">
+          <el-input v-model="formEdit.ditchName" placeholder="请输入渠道类型名称" clearable />
+        </el-form-item>
       </el-form>
     </Layer>
   </div>
@@ -87,18 +50,15 @@ import From from "@/components/from/index.vue";
 import Table from "@/components/table/index.vue";
 import Layer from '@/components/layer/index.vue'
 import { ElMessage } from 'element-plus'
-import { getUserList, getStaticList, riskBannedUser, riskLockUser } from '@/api/userModule.js'
-import { riskChangeUserStatus } from '@/api/riskModule.js'
 import { convertUTCToBeijing } from '@/utils/index.js'
 import { useGetDictList } from '@/hooks/useGetDictList.js'
 import { useStore } from 'vuex'
-import { appList, placementList, placementDel, placementSave } from "@/api/formworkErection";
+import { ditchList, ditchAddOne, ditchDeleteOne, ditchUpdateOne } from '@/api/outBagModule.js'
 
 const store = useStore()
 const { dictData, loadDictData, getOptions, getDictionaryName } = useGetDictList();
 const form = ref(null);
 const tableData = ref([]);
-const appData = ref([]);
 
 // 分页参数, 供table使用
 const page = reactive({
@@ -108,14 +68,6 @@ const page = reactive({
   total: 0,
 });
 
-// 分页参数, 供table使用
-const appPage = reactive({
-  pageNum: 1,
-  pageSizes: 999,
-  limit: 999,
-  total: 0,
-});
-
 // 用途options
 const useWayOptions = reactive([
   { value: 1, label: '应用商城' },
@@ -134,39 +86,11 @@ const agencyOptions = reactive([
   { value: 6, label: '合众' },
 ])
 
-// 分页数据
-const getAppList = async () => {
-  let res = await appList({ ...appFormSearch.value });
-  appData.value = res.data;
-  console.log('appData.value', appData.value)
-};
-
-const changeAppTableData = () => {
-  appFormSearch.value.pageNum = appPage.pageNum;
-  appFormSearch.value.pageSizes = appPage.pageSizes;
-  appFormSearch.value.limit = appPage.limit;
-  // 分页切换
-  getAppList();
-};
-
 const formSearch = ref({
-  channelOrigin: null,// 渠道来源
-  channelType: null,// 渠道类型
-  lastLoginTime: '',// 最新登录时间
+  ditchName: null,
   limit: 20,// 当前页数量(查询量)
-  nickName: null,// 用户昵称
   page: 1,// 当前页码
   pageSizes: 20,// 总页数
-  registryTime: null,// 注册时间
-  total: null,// 总条数
-  userType: null,// 用户类型
-});
-
-
-const appFormSearch = ref({
-  page: 1,// 当前页码
-  pageSizes: 999,// 总页数
-  limit: 999,
   total: null,// 总条数
 });
 
@@ -175,7 +99,6 @@ const dynamicFormItems = ref([])
 onBeforeMount(() => {
   settingData()
   getList();
-  changeAppTableData()
 });
 
 // 获取缓存数据设置筛选数据
@@ -184,22 +107,16 @@ const settingData = () => {
     dynamicFormItems.value = [
       {
         label: '渠道名称',
-        prop: 'placementId',
+        prop: 'ditchName',
         type: 'input',
       },
-      {
-        label: '所属代理',
-        prop: 'placementId1',
-        type: 'select',
-        options: agencyOptions
-      },
     ]
   })
 }
 
 // 分页数据
 const getList = async () => {
-  let res = await placementList({ ...formSearch.value });
+  let res = await ditchList({ ...formSearch.value });
   tableData.value = res.data;
   page.total = res.pageMeta.total;
 };
@@ -219,12 +136,7 @@ const handleFormSubmitted = (formData) => {
   formSearch.value.pageSizes = 20;
   formSearch.value.total = page.total;
   formSearch.value.limit = 20;
-  formSearch.value.nickName = formData.nickName;
-  formSearch.value.channelOrigin = formData.channelOrigin;
-  formSearch.value.channelType = formData.channelType;
-  formSearch.value.userType = formData.userType;
-  formSearch.value.lastLoginTime = formData.lastLoginTime || null
-  formSearch.value.registryTime = formData.registryTime || null
+  formSearch.value.ditchName = formData.ditchName;
 
   getList();
 };
@@ -232,17 +144,13 @@ const handleFormSubmitted = (formData) => {
 // 表单重置
 const handleFormReset = () => {
   formSearch.value = {
-    channelOrigin: null,// 渠道来源
-    channelType: null,// 渠道类型
-    lastLoginTime: null,// 最新登录时间
+    ditchName: null,
     limit: 20,// 当前页数量(查询量)
-    nickName: null,// 用户昵称
     page: 1,// 当前页码
     pageSizes: 20,// 总页数
-    registryTime: null,// 注册时间
     total: null,// 总条数
-    userType: null,// 用户类型
   };
+
   getList();
 };
 
@@ -254,93 +162,62 @@ const handleSelectionChange = (val) => {
 // 弹窗
 const layer = ref({
   show: false,
-  title: "新增广告位",
+  title: "新增渠道类型",
   showButton: true,
-  width: '60vw'
+  width: '30vw',
+  edit: false, //是否编辑
 });
 
 const formEdit = ref({
-  adFormat: undefined,//广告样式 *
-  appId: undefined,//应用ID *
-  appName: undefined,//应用名称 *
-  enabled: undefined,//启用状态
-  networkAppId: '1210971759',//广告渠道应用ID
-  networkAppName: 'youlianghui',//广告渠道应用名称
-  placementId: undefined,//广告位id
-  placementName: undefined,//广告位名称 *
-  remark: undefined, //备注 *
-  status: undefined, //广告位状态 1-锁定 2-待审核 3-正常 *
-  appData: [],//关联应用
+  ditchId: undefined,
+  ditchName: undefined,
 })
 
 const edit = (row) => {
   ruleForm.value?.resetFields()
   if (row) {
-    layer.value.title = '编辑广告位'
-    formEdit.value.placementName = row.placementName
-    formEdit.value.adFormat = row.adFormat
-    formEdit.value.remark = row.remark
-    formEdit.value.status = row.status
-    formEdit.value.placementId = row.placementId
-    formEdit.value.appData = appData.value.find(item => item.appId === row.appId);
-
+    layer.value.title = '编辑渠道类型'
+    layer.value.edit = true
+    formEdit.value.ditchId = row.ditchId
+    formEdit.value.ditchName = row.ditchName
   } else {
-    layer.value.title = '新增广告位'
+    layer.value.title = '新增渠道类型'
+    layer.value.edit = false
     // 重置数据
-    let formDatas = {
-      adFormat: undefined,//广告样式
-      appId: undefined,//应用ID
-      appName: undefined,//应用名称
-      enabled: undefined,//启用状态
-      networkAppId: '1210971759',//广告渠道应用ID
-      networkAppName: 'youlianghui',//广告渠道应用名称
-      placementId: undefined,//广告位id
-      placementName: undefined,//广告位名称
-      remark: undefined, //备注
-      status: undefined, //广告位状态 1-锁定 2-待审核 3-正常
-      appData: [],//关联应用
+    formEdit.value = {
+      ditchId: undefined,
+      ditchName: undefined,
     }
-    Object.assign(formEdit.value, formDatas)
   }
   layer.value.show = true
-
 }
 
 const ruleForm = ref(null);
 
 const rules = reactive({
-  appData: [
-    { required: true, message: "请选择关联应用", trigger: "change" },
-  ],
-  placementName: [
-    { required: true, message: "请输入广告位名称", trigger: "blur" },
-  ],
-  adFormat: [
-    { required: true, message: "请选择广告样式", trigger: "change" },
-  ],
-  remark: [
-    { required: true, message: "请输入备注", trigger: "blur" },
-  ],
-  status: [
-    { required: true, message: "请选择广告位状态", trigger: "change" },
+  ditchName: [
+    { required: true, message: "请输入新增渠道类型名称", trigger: "blur" },
   ],
 });
 
 const submit = async (formEl) => {
-  formEdit.value.appId = formEdit.value.appData.appId
-  formEdit.value.appName = formEdit.value.appData.appName
   await formEl.validate(async (valid, fields) => {
     if (valid) {
       // 提交内容
-      delete formEdit.value.appData
-      console.log('新增提交的内容', formEdit.value)
-
-      await placementSave({ ...formEdit.value }).then((res) => {
-        ElMessage.success('保存成功')
-        getList();
-      })
-
-      layer.value.show = false
+      // console.log('新增提交的内容', formEdit.value)
+      if (layer.value.edit) {
+        await ditchUpdateOne({ ...formEdit.value }).then((res) => {
+          ElMessage.success('保存成功')
+          layer.value.show = false
+          getList();
+        })
+      } else {
+        await ditchAddOne({ ...formEdit.value }).then((res) => {
+          ElMessage.success('保存成功')
+          layer.value.show = false
+          getList();
+        })
+      }
     } else {
       console.log("error submit!", fields);
     }
@@ -349,8 +226,7 @@ const submit = async (formEl) => {
 
 // 删除用户
 const removeType = async (row) => {
-  console.log('删除', row)
-  await placementDel({ placementId: row.placementId }).then((res) => {
+  await ditchDeleteOne({ ditchId: row.ditchId }).then((res) => {
     ElMessage.success('删除成功')
     getList();
   })

+ 30 - 10
src/views/main/riskModule/components/configForm.vue

@@ -101,7 +101,7 @@
 
                         <!-- 日期 -->
                         <template v-else-if="item.configType === '3'">
-                            <div style="width: 240px !important;">
+                            <div style="max-width: 240px !important;">
                                 <el-date-picker v-if="item.multy === 2" v-model="item.configVal" type="date"
                                     placeholder="请选择" :class="{ 'is-error': item.error_configVal }"
                                     @input="clearFieldError(index, 'configVal')" />
@@ -113,14 +113,14 @@
                             </div>
                         </template>
                     
-                        <template v-if="!layer.disabled">
-                            <el-button v-if="configFormList.configList.length === index + 1" class="button-item"
-                                type="primary" @click="addItem">
-                                添加
-                            </el-button>
-                            <el-button class="button-item" type="danger" @click="removeItem(index)">删除</el-button>
-                        </template>
                     </div>
+                    <template v-if="!layer.disabled">
+                        <el-button v-if="configFormList.configList.length === index + 1" class="button-item"
+                            type="primary" @click="addItem">
+                            添加
+                        </el-button>
+                        <el-button class="button-item" type="danger" @click="removeItem(index)">删除</el-button>
+                    </template>
                 </div>
             </el-scrollbar>
             <template #footer v-if="layer.showButton">
@@ -442,15 +442,35 @@
                 // item.fieldDesc = `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
                 // return `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
 
-                let multyList = ['','','>','<']
+               /*  let multyList = ['','','>','<']
                 item.fieldDesc = `${fieldDesc}为${multyList[item.multy - 1]}${valueText}`
-                return `${fieldDesc}为${multyList[item.multy - 1]}${valueText}`
+                return `${fieldDesc}为${multyList[item.multy - 1]}${valueText}` */
+                let result = fillOrAppend(fieldDesc,[valueText],item.multy)
+                item.fieldDesc = result
+                return result
             } else {
                 return ''
             }
         })
     })
 
+    /**
+     * 生成配置内容
+     * @param { string } template 配置文字
+     * @param  values 配置值
+     * @param  multy 比较值
+     */
+    function fillOrAppend(template, values, multy) {
+        let hasPlaceholder = template.includes('?');
+        let multyList = ['','','>','<']
+        if (hasPlaceholder) {
+            let i = 0;
+            return template.replace(/\?/g, () => values ?? '?');
+        } else {
+            return `${template}为${multyList[multy - 1]}${values}`;
+        }
+    }
+
     // #endregion
 
     const gettemplateData = async (templateId) => {