Sfoglia il codice sorgente

新建广告源管理、修改其他页面

wangzhiqiang 4 mesi fa
parent
commit
7ce4c1d142

+ 2 - 2
.env.development

@@ -2,9 +2,9 @@ ENV = 'development'
 
 # 线上测试
 # VITE_BASE_URL = 'http://advise.ytmdm.com/yt-gateway'
-# VITE_BASE_URL = 'http://119.45.71.139:25001'
+VITE_BASE_URL = 'http://119.45.71.139:25001'
 
 # 本地 
 # VITE_BASE_URL = 'http://192.168.1.9:25001'
-VITE_BASE_URL = 'http://192.168.1.159:25001'
+# VITE_BASE_URL = 'http://192.168.1.159:25001'
 

+ 38 - 0
src/api/formworkErection.js

@@ -115,5 +115,43 @@ export function channelDeleteOne(params) {
     })
 }
 
+// 获取广告源列表
+export function adSourceList(data) {
+    return request({
+        url: '/agent-service/adSource/list',
+        method: 'post',
+        data
+    })
+}
+
+// 新增广告源
+export function adSourceAddOne(data) {
+    return request({
+        url: '/agent-service/adSource/addOne',
+        method: 'post',
+        data
+    })
+}
+
+// 修改广告源
+export function adSourceUpdateOne(data) {
+    return request({
+        url: '/agent-service/adSource/updateOne',
+        method: 'post',
+        data
+    })
+}
+
+// 删除广告源
+export function adSourceDeleteOne(params) {
+    return request({
+        url: '/agent-service/adSource/deleteOne',
+        method: 'get',
+        params
+    })
+}
+
+
+
 
 

+ 9 - 0
src/api/userModule.js

@@ -43,4 +43,13 @@ export function getEnabledList(params) {
         method: 'get',
         params
     })
+}
+
+// 查询用户ecpm数据
+export function appUserEcpm(params) {
+    return request({
+        url: '/agent-service/appUser/ecpm',
+        method: 'get',
+        params
+    })
 }

+ 6 - 0
src/router/modules/formworkErection.js

@@ -26,6 +26,12 @@ const route = [
                 component: createNameComponent(() => import('@/views/main/formworkErection/channelAdmin.vue')),
                 meta: { title: '广告渠道管理' },
             },
+            /* {
+                path: 'adSourceAdmin/index',
+                name: 'adSourceAdmin',
+                component: createNameComponent(() => import('@/views/main/formworkErection/adSourceAdmin.vue')),
+                meta: { title: '广告源管理' },
+            }, */
         ],
     }
 ]

+ 1 - 0
src/router/permission/backConfig.js

@@ -10,6 +10,7 @@ const formworkErection = {
   appAdmin: createNameComponent(() => import('@/views/main/formworkErection/appAdmin.vue')),
   placementAdmin: createNameComponent(() => import('@/views/main/formworkErection/placementAdmin.vue')),
   channelAdmin: createNameComponent(() => import('@/views/main/formworkErection/channelAdmin.vue')),
+  // adSourceAdmin: createNameComponent(() => import('@/views/main/formworkErection/adSourceAdmin.vue')),
 }
 
 const userModule = {

+ 352 - 0
src/views/main/formworkErection/adSourceAdmin.vue

@@ -0,0 +1,352 @@
+<template>
+    <div class="layout-container">
+        <!-- 菜单栏 -->
+        <From :form-items="dynamicFormItems" @formSubmitted="handleFormSubmitted" @formReset="handleFormReset"
+            is_add_button="新增" @addForm="edit" />
+
+        <!-- 表格 -->
+        <div class="layout-container">
+            <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
+                @selection-change="handleSelectionChange">
+                <el-table-column prop="adSourceId" label="广告源ID" />
+                <el-table-column prop="name" label="广告源名称" />
+                <el-table-column prop="type" label="广告源类型" />
+                <el-table-column prop="placementName" label="广告位名称" />
+                <el-table-column prop="placementId" label="广告位ID" />
+                <el-table-column prop="mix_format" label="混合类型">
+                    <template #default="scope">
+                        {{ scope.row.mix_format }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" width="200" fixed="right">
+                    <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="removeItem(scope.row)">
+                                <template #reference>
+                                    <el-button class="button-item" style="margin-bottom: 5px;"
+                                        type="danger">删除</el-button>
+                                </template>
+                            </el-popconfirm>
+                        </div>
+                    </template>
+                </el-table-column>
+            </Table>
+        </div>
+
+        <!-- 操作弹窗 -->
+        <Layer :layer="layer" @confirm="submit(ruleForm)" @close="layer.show = false">
+            <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="120px" style="margin-right:30px;">
+                <el-row :gutter="5">
+                    <el-col :span="10">
+                        <el-form-item required label="广告源名称" prop="name">
+                            <el-input v-model="formEdit.name" placeholder="请输入" clearable />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="2"></el-col>
+                    <el-col :span="10">
+                        <el-form-item required label="广告位" prop="placementId">
+                            <el-select v-model="formEdit.placementId">
+                                <el-option v-for="item in placementListData" :value="item.placementId"
+                                    :label="item.placementName" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="5">
+                    <el-col :span="10">
+                        <el-form-item required label="广告源类型" prop="type">
+                            <el-select v-model="formEdit.type">
+                                <el-option :value="2" label="常规广告源" />
+                                <el-option :value="10" label="兜底广告源" />
+                                <el-option :value="12" label="客户端竞价广告源" />
+                                <el-option :value="13" label="服务端竞价广告源" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="2"></el-col>
+                    <el-col :span="10">
+                        <el-form-item required label="混合类型" prop="mix_format">
+                            <el-select v-model="formEdit.mix_format">
+                                <el-option :value="-1" label="非混合类型" />
+                                <el-option :value="0" label="混合native类型" />
+                                <el-option :value="1" label="混合rewarded_video类型" />
+                                <el-option :value="2" label="混合banner类型" />
+                                <el-option :value="3" label="混合interstitial类型" />
+                                <el-option :value="4" label="混合splash类型" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <!-- <el-row :gutter="5">
+                    <el-col :span="10" v-if="formEdit.appId">
+
+                    </el-col>
+                    <el-col :span="2" v-if="formEdit.appId"></el-col>
+                    <el-col :span="10">
+
+                    </el-col>
+                </el-row> -->
+            </el-form>
+        </Layer>
+    </div>
+</template>
+
+<script setup>
+import { onBeforeMount, ref, reactive } from "vue";
+import From from "@/components/from/index.vue";
+import Table from "@/components/table/index.vue";
+import { useGetDictList } from '@/hooks/useGetDictList.js'
+import { useStore } from 'vuex'
+import { placementList, adSourceList, adSourceAddOne, adSourceUpdateOne, adSourceDeleteOne } from "@/api/formworkErection";
+import Layer from "@/components/layer/index.vue";
+import { ElMessage } from "element-plus";
+
+const store = useStore()
+const { dictData, loadDictData, getOptions, getDictionaryName } = useGetDictList();
+const form = ref(null);
+const tableData = ref([]);
+
+// 分页参数, 供table使用
+const page = reactive({
+    pageNum: 1,
+    pageSize: 20,
+    limit: 20,
+    total: 0,
+});
+
+const formSearch = ref({
+    limit: 20,// 当前页数量(查询量)
+    page: 1,// 当前页码
+    pageSizes: 20,// 总页数
+    total: null,// 总条数
+    name: null,//名称
+    placementId: null,//广告位id
+});
+
+const dynamicFormItems = ref([])
+
+onBeforeMount(() => {
+    settingData()
+    getList();
+    getPlacementList()
+});
+
+// 获取缓存数据设置筛选数据
+const settingData = () => {
+    loadDictData().then(() => {
+        dynamicFormItems.value = [
+            {
+                label: '广告源ID',
+                prop: 'nickName',
+                type: 'input',
+            },
+            {
+                label: '广告位名称',
+                prop: 'channelType',
+                type: 'select',
+                options: [
+                    {
+                        label: "全部",
+                        value: null,
+                    },
+                    {
+                        label: "正常",
+                        value: 0,
+                    },
+                    {
+                        label: "锁定",
+                        value: 1,
+                    }
+                ]
+            },
+            {
+                label: '应用名称',
+                prop: 'loginType',
+                type: 'select',
+                options: [
+                    {
+                        label: "全部",
+                        value: null,
+                    },
+                    {
+                        label: "账号密码",
+                        value: 0,
+                    },
+                    {
+                        label: "微信",
+                        value: 1,
+                    }
+                ]
+            },
+        ]
+    })
+}
+
+// 分页数据
+const getList = async () => {
+    let res = await adSourceList({ ...formSearch.value });
+    tableData.value = res.data;
+    page.total = res.pageMeta.total;
+};
+
+const changeTableData = () => {
+    formSearch.value.pageNum = page.pageNum;
+    formSearch.value.pageSize = page.pageSize;
+    formSearch.value.limit = page.limit;
+    // 分页切换
+    getList();
+};
+
+// 搜索
+const handleFormSubmitted = (formData) => {
+    // console.log("接收到子组件传递的数据", formData);
+    formSearch.value.page = 1;
+    formSearch.value.pageSizes = 20;
+    formSearch.value.total = page.total;
+    formSearch.value.limit = 20;
+    getList();
+};
+
+// 表单重置
+const handleFormReset = () => {
+    formSearch.value = {
+        limit: 20,// 当前页数量(查询量)
+        page: 1,// 当前页码
+        pageSizes: 20,// 总页数
+        total: null,// 总条数
+        name: null,//名称
+        placementId: null,//广告位id
+    };
+    getList();
+};
+
+// 选择监听器
+const handleSelectionChange = (val) => {
+    context.emit("selection-change", val)
+}
+
+
+// 获取广告位列表
+const placementListData = ref([])
+const getPlacementList = async () => {
+    let res = await placementList({
+        limit: 999,
+        page: 1,
+        pageSizes: 999,
+    })
+    placementListData.value = res.data
+
+}
+
+// 弹窗
+const layer = ref({
+    show: false,
+    title: "新增广告渠道",
+    showButton: true,
+    width: '50vw',
+    edit: false,
+});
+
+const formEdit = ref({
+    adSourceId: undefined,
+    mix_format: '',//混合类型
+    name: '', //广告源名称
+    network_id: '1210971759',//Taku广告平台账号ID
+    placementId: '',//广告位id
+    type: '',//广告源类型
+})
+
+const edit = (row) => {
+    ruleForm.value?.resetFields()
+    if (row) {
+        formEdit.value = row
+        layer.value.edit = true;
+        layer.value.title = '编辑广告源'
+    } else {
+        formEdit.value = {
+            adSourceId: undefined,
+            mix_format: '',//混合类型
+            name: '', //广告源名称
+            network_id: '1210971759',//Taku广告平台账号ID
+            placementId: '',//广告位id
+            type: '',//广告源类型
+        }
+        layer.value.edit = false;
+        layer.value.title = '新增广告源'
+    }
+    layer.value.show = true
+}
+
+const ruleForm = ref(null);
+
+const rules = reactive({
+    name: [
+        { required: true, message: "请输入广告源名称", trigger: "blur" },
+    ],
+    placementId: [
+        { required: true, message: "请选择广告位", trigger: "change" },
+    ],
+    type: [
+        { required: true, message: "请选择广告源类型", trigger: "change" },
+    ],
+    mix_format: [
+        { required: true, message: "请选择混合类型", trigger: "change" },
+    ],
+});
+
+const submit = async (formEl) => {
+    await formEl.validate(async (valid, fields) => {
+        if (valid) {
+            // 提交内容
+            console.log('提交内容', formEdit.value)
+
+            // 编辑
+            if (layer.value.edit) {
+                await adSourceUpdateOne({ ...formEdit.value }).then((res) => {
+                    ElMessage.success('保存成功')
+                    getList();
+                })
+            } else {
+                await adSourceAddOne({ ...formEdit.value }).then((res) => {
+                    ElMessage.success('新增成功');
+                    getList()
+                })
+            }
+
+            layer.value.show = false
+        } else {
+            console.log("error submit!", fields);
+        }
+    });
+};
+
+
+// 删除
+const removeItem = async (row) => {
+    console.log('删除', row)
+    await adSourceDeleteOne({ adSourceId: row.adSourceId }).then((res) => {
+        ElMessage.success("删除成功");
+        handleFormSubmitted();
+    });
+}
+
+
+
+</script>
+
+<style scoped lang="scss">
+.layout-container {
+    .button {
+        display: flex;
+        flex-direction: column;
+
+        .button-item {
+            margin: 4px;
+        }
+    }
+}
+</style>

+ 18 - 6
src/views/main/formworkErection/appAdmin.vue

@@ -44,7 +44,7 @@
         <el-table-column prop="qrCode" min-width="150" label="二维码">
           <template #default="scope">
             <el-image style="width: 100px; height: 100px;" :z-index="99999" :src="scope.row.qrCode" fit="fill"
-              :preview-src-list="[scope.row.qrCode]" />
+              :preview-src-list="[scope.row.qrCode]" preview-teleported="true" />
           </template>
         </el-table-column>
         <el-table-column prop="request" label="广告源请求数" />
@@ -87,13 +87,12 @@
       <el-radio-group style="width: 100%;" v-model="selectedChannelId" @change="handleRadioChange">
         <Table style="width: 100%;" @getTableData="getChanelData" v-model:page="channelPage" ref="channelTable"
           :data="channelData">
-          <el-table-column label="渠道ID" width="300">
+          <el-table-column width="50">
             <template #default="{ row }">
-              <el-radio :label="row.channelId" />
+              <el-radio :label="row.channelId">&nbsp;</el-radio>
             </template>
           </el-table-column>
-
-          <!-- <el-table-column prop="channelId" label="渠道ID" /> -->
+          <el-table-column prop="channelId" label="渠道ID" />
           <el-table-column prop="channelName" label="渠道名称" />
           <el-table-column prop="loginType" label="登录类型">
             <template #default="{ row }">
@@ -246,7 +245,7 @@
               <el-upload class="avatar-uploader" accept="image/jpg,image/jpeg,image/png,image/webp" action="#"
                 :show-file-list="false" :before-upload="beforeAvatarUpload" :http-request="selfUpload">
                 <el-image v-if="formEdit.qrCode" style="width: 100px; height: 100px" :src="formEdit.qrCode" fit="fill"
-                  :preview-src-list="[formEdit.qrCode]" />
+                   />
                 <el-icon v-else class="avatar-uploader-icon">
                   <Plus />
                 </el-icon>
@@ -444,6 +443,19 @@ function handleRadioChange(val) {
   console.log(selectRow.value)
 }
 
+const selectedRow = ref(null); // 存储选中的行
+
+// 选中行的方法
+const selectRowClick = (row) => {
+  // 如果点击已选中的行,则取消选中;否则选中新行
+  selectedRow.value = selectedRow.value === row ? null : row;
+};
+
+// 行点击事件(点击行任意位置选中)
+const handleRowClick = (row) => {
+  selectRow(row);
+};
+
 // 弹窗
 const layer = ref({
   show: false,

+ 11 - 24
src/views/main/formworkErection/placementAdmin.vue

@@ -196,38 +196,25 @@ const settingData = () => {
   loadDictData().then(() => {
     dynamicFormItems.value = [
       {
-        label: '渠道类型',
-        prop: 'nickName',
+        label: '广告位ID',
+        prop: 'placementId',
         type: 'input',
       },
       {
-        label: '所属代理',
-        prop: 'channelType',
-        type: 'select',
-        options: [
-          {
-            label: "全部",
-            value: null,
-          },
-          {
-            label: "是",
-            value: 0,
-          },
-          {
-            label: "否",
-            value: 1,
-          }
-        ]
+        label: '广告位名称',
+        prop: 'placementName',
+        type: 'input',
       },
       {
-        label: '客服QQ号',
-        prop: 'name',
+        label: '平台应用',
+        prop: 'appName',
         type: 'input',
       },
       {
-        label: 'QQ群号',
-        prop: 'nickName1',
-        type: 'input',
+        label: '广告位状态',
+        prop: 'channelType',
+        type: 'select',
+        options: getOptions('placement_status')
       },
       // { label: '登录日期', prop: 'loginTime', type: 'daterange' },
     ]

+ 6 - 2
src/views/main/riskModule/components/configForm.vue

@@ -438,8 +438,12 @@
             }
             if (fieldDesc && valueText && valueText.length > 0) {
                 // getOptions('multy')[item.multy - 1].label
-                item.fieldDesc = `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
-                return `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
+                // item.fieldDesc = `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
+                // return `${fieldDesc}为${getOptions('multy')[item.multy - 1].label}${valueText}`
+
+                let multyList = ['','','>','<']
+                item.fieldDesc = `${fieldDesc}为${multyList[item.multy - 1]}${valueText}`
+                return `${fieldDesc}为${multyList[item.multy - 1]}${valueText}`
             } else {
                 return ''
             }

+ 55 - 1
src/views/main/userModule/userList.vue

@@ -7,6 +7,11 @@
     <div class="layout-container">
       <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
         @selection-change="handleSelectionChange">
+        <el-table-column prop="userId" label="查看ECPM" width="130" fixed="left">
+          <template #default="scope">
+            <el-button type="primary" @click="lookEcpm(scope.row.userId)">查看ECPM</el-button>
+          </template>
+        </el-table-column>
         <el-table-column prop="userId" label="用户ID" width="280" />
         <el-table-column prop="nickName" label="用户昵称" width="90" />
         <el-table-column prop="userStatus" label="用户状态" width="90">
@@ -91,6 +96,37 @@
       </el-form>
     </Layer>
 
+    <Layer :layer="ecpmLayer" @confirm="ecpmLayer.show = false" @close="ecpmLayer.show = false">
+        <Table :showPage="false" ref="ecpmTable" :data="ecpmData">
+          <el-table-column prop="userId" label="用户ID" width="100" />
+          <el-table-column prop="adSourceId" label="广告源ID" width="100" />
+          <el-table-column prop="beginTime" label="开始时间" width="100">
+            <template #default="scope">
+              {{ convertUTCToBeijing(scope.row.beginTime) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="click" label="点击数" />
+          <el-table-column prop="click_api" label="三方广告平台的点击数" width="180" />
+          <el-table-column prop="ecpm" label="ECPM" width="100" />
+          <el-table-column prop="ecpm_api" label="三方广告平台的ECPM" width="180" />
+          <el-table-column prop="fillrate" label="广告源填充率" width="120" />
+          <el-table-column prop="finishTime" label="完成时间" width="100">
+            <template #default="scope">
+              {{ convertUTCToBeijing(scope.row.finishTime) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="impression" label="展示数" width="100" />
+          <el-table-column prop="impression_api" label="三方广告平台的展示数" width="180" />
+          <el-table-column prop="networkFormId" label="广告平台ID" width="100" />
+          <el-table-column prop="networkName" label="广告平台名称" width="120" />
+          <el-table-column prop="networkPlacementId" label="广告平台广告位ID" width="160" />
+          <el-table-column prop="nickName" label="用户昵称" width="100" />
+          <el-table-column prop="placementId" label="广告位ID" width="100" />
+          <el-table-column prop="recordId" label="广告记录ID" width="100" />
+          <el-table-column prop="request" label="广告源请求数" width="120" />
+          <el-table-column prop="revenue" label="收益" width="100" />
+        </Table>
+    </Layer>
   </div>
 </template>
 
@@ -101,7 +137,7 @@
   import Layer from '@/components/layer/index.vue'
   import Card from './components/card/index.vue'
   import { ElMessage } from 'element-plus'
-  import { getUserList, getStaticList, riskBannedUser, riskLockUser } from '@/api/userModule.js'
+  import { getUserList, getStaticList, riskBannedUser, riskLockUser, appUserEcpm } from '@/api/userModule.js'
   import { riskChangeUserStatus } from '@/api/riskModule.js'
   import { convertUTCToBeijing } from '@/utils/index.js'
   import { useGetDictList } from '@/hooks/useGetDictList.js'
@@ -356,6 +392,24 @@
     })
   }
 
+  // 查看ECPM
+  const ecpmLayer = ref({
+    show: false,
+    title: "查看ECPM",
+    showButton: true,
+    width: '80vw'
+  });
+
+  const ecpmTable = ref(null)
+  const ecpmData = ref([])
+
+  const lookEcpm = async(userId)=> {
+    ecpmData.value = []
+    let res = await appUserEcpm({userId})
+    ecpmData.value = res.data
+    ecpmLayer.value.show = true
+  }
+
 </script>
 
 <style scoped lang="scss">