Переглянути джерело

1. 媒体消耗
2. 媒体列表
3. 渠道列表

ith5 6 місяців тому
батько
коміт
5d17b3ccd2

+ 179 - 0
src/views/v1/advert/agenList/addSite.vue

@@ -0,0 +1,179 @@
+<template>
+  <component
+    is="a-modal"
+    :width="tool.getDevice() === 'mobile' ? '100%' : '600px'"
+    v-model:visible="visible"
+    :title="title"
+    :mask-closable="false"
+    :ok-loading="loading"
+    @cancel="close"
+    @before-ok="submit"
+  >
+    <!-- 表单信息 start -->
+    <a-form
+      ref="formRef"
+      :model="formData"
+      :rules="rules"
+      :auto-label-width="true"
+    >
+      <a-form-item label="媒体ID" field="media_id">
+        <a-select
+          v-model="formData.media_id"
+          :options="mediaOptions"
+          placeholder="请选择媒体ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="渠道ID" field="agent_id">
+        <a-select
+          v-model="formData.agent_id"
+          :options="agentOptions"
+          placeholder="请选择渠道ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="负责人ID" field="auth_id">
+        <a-select
+          v-model="formData.auth_id"
+          :options="authOptions"
+          placeholder="请选择负责人ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="广告位名称" field="name">
+        <a-input v-model="formData.name" placeholder="请输入广告位名称" />
+      </a-form-item>
+    </a-form>
+    <!-- 表单信息 end -->
+  </component>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import tool from "@/utils/tool";
+import { Message, Modal } from "@arco-design/web-vue";
+import api from "../../api/advert/agentSite";
+import advertCommonApi from "../../api/advert/common";
+import { useUserStore } from "@/store";
+
+const emit = defineEmits(["success"]);
+// 引用定义
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
+const mode = ref("");
+const userStore = useUserStore();
+const mediaOptions = ref([]);
+const authOptions = ref([]);
+const agentOptions = ref([]);
+
+let title = computed(() => {
+  return "广告位" + (mode.value == "add" ? "-新增" : "-编辑");
+});
+
+// 表单初始值
+const initialFormData = {
+  id: null,
+  media_id: null,
+  agent_id: null,
+  auth_id: null,
+  name: "",
+};
+
+// 表单信息
+const formData = reactive({ ...initialFormData });
+
+// 验证规则
+const rules = {
+  media_id: [{ required: true, message: "媒体ID必需填写" }],
+  agent_id: [{ required: true, message: "渠道ID必需填写" }],
+  auth_id: [{ required: true, message: "负责人ID必需填写" }],
+  name: [{ required: true, message: "广告位名称必需填写" }],
+};
+
+// 获取媒体列表Options
+const getMediaOptions = async () => {
+  const res = await advertCommonApi.getMediaOptionsApi();
+  if (res.code == 200) {
+    mediaOptions.value = res.data;
+  }
+};
+
+// 获取渠道列表Options
+const getAgentOptions = async () => {
+  const res = await advertCommonApi.getAgentOptionsApi();
+  if (res.code == 200) {
+    agentOptions.value = res.data;
+  }
+};
+
+// 获取后台归属人列表
+const getAuthList = async () => {
+  const res = await advertCommonApi.getAuthOptionsApi();
+  if (res.code == 200) {
+    authOptions.value = res.data;
+  }
+};
+
+// 打开弹框
+const open = async (type = "add") => {
+  mode.value = type;
+  // 重置表单数据
+  Object.assign(formData, initialFormData);
+  formRef.value.clearValidate();
+  visible.value = true;
+  if (mode.value === "add") {
+    formData.auth_id = userStore.user.id;
+  }
+  await initPage();
+};
+
+// 初始化页面数据
+const initPage = async () => {
+  await getMediaOptions();
+  await getAgentOptions();
+  await getAuthList();
+};
+
+// 设置数据
+const setFormData = async (data) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      formData[key] = data[key];
+    }
+  }
+};
+
+// 数据保存
+const submit = async (done) => {
+  const validate = await formRef.value?.validate();
+  if (!validate) {
+    loading.value = true;
+    let data = { ...formData };
+    let result = {};
+    if (mode.value === "add") {
+      // 添加数据
+      data.id = undefined;
+      result = await api.save(data);
+    } else {
+      // 修改数据
+      result = await api.update(data.id, data);
+    }
+    if (result.code === 200) {
+      Message.success("操作成功");
+      emit("success");
+      done(true);
+    }
+    // 防止连续点击提交
+    setTimeout(() => {
+      loading.value = false;
+    }, 500);
+  }
+  done(false);
+};
+
+// 关闭弹窗
+const close = () => (visible.value = false);
+
+defineExpose({ open, setFormData });
+</script>

+ 164 - 0
src/views/v1/advert/agenList/edit.vue

@@ -0,0 +1,164 @@
+<template>
+  <component
+    is="a-modal"
+    :width="tool.getDevice() === 'mobile' ? '100%' : '600px'"
+    v-model:visible="visible"
+    :title="title"
+    :mask-closable="false"
+    :ok-loading="loading"
+    @cancel="close"
+    @before-ok="submit"
+  >
+    <!-- 表单信息 start -->
+    <a-form
+      ref="formRef"
+      :model="formData"
+      :rules="rules"
+      :auto-label-width="true"
+    >
+      <a-form-item label="媒体ID" field="media_id">
+        <a-select
+          v-model="formData.media_id"
+          :options="mediaOptions"
+          placeholder="请选择媒体ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="渠道名称" field="name">
+        <a-input v-model="formData.name" placeholder="请输入渠道名称" />
+      </a-form-item>
+      <a-form-item label="后台归属人" field="auth_id">
+        <a-select
+          v-model="formData.auth_id"
+          :options="authOptions"
+          placeholder="请选择后台归属人"
+          allow-clear
+        />
+      </a-form-item>
+    </a-form>
+    <!-- 表单信息 end -->
+  </component>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import tool from "@/utils/tool";
+import { Message, Modal } from "@arco-design/web-vue";
+import api from "../../api/advert/agenList";
+import advertCommonApi from "../../api/advert/common";
+import { useUserStore } from "@/store";
+const emit = defineEmits(["success"]);
+// 引用定义
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
+const mode = ref("");
+const mediaOptions = ref([]);
+const authOptions = ref([]);
+const userStore = useUserStore();
+
+let title = computed(() => {
+  return "渠道管理" + (mode.value == "add" ? "-新增" : "-编辑");
+});
+
+// 表单初始值
+const initialFormData = {
+  id: null,
+  auth_id: null,
+  name: "",
+  media_id: null,
+};
+
+// 表单信息
+const formData = reactive({ ...initialFormData });
+
+// 验证规则
+const rules = {
+  auth_id: [{ required: true, message: "后台归属人必需填写" }],
+  name: [{ required: true, message: "渠道名称必需填写" }],
+  media_id: [{ required: true, message: "媒体ID必需填写" }],
+};
+
+// 打开弹框
+const open = async (type = "add") => {
+  mode.value = type;
+  // 重置表单数据
+  Object.assign(formData, initialFormData);
+  formRef.value.clearValidate();
+  visible.value = true;
+  if (mode.value === "add") {
+    formData.auth_id = userStore.user.id;
+  }
+  await initPage();
+};
+
+// 初始化页面数据
+const initPage = async () => {
+  await getMediaOptions();
+  await getAuthList();
+};
+
+// 获取媒体列表Options
+const getMediaOptions = async () => {
+  const res = await advertCommonApi.getMediaOptionsApi();
+  if (res.code == 200) {
+    mediaOptions.value = res.data;
+  }
+};
+
+// 获取后台归属人列表
+const getAuthList = async () => {
+  const res = await advertCommonApi.getAuthOptionsApi();
+  if (res.code == 200) {
+    authOptions.value = res.data;
+  }
+};
+
+// 从缓存中获取用户的id
+const getUserId = async () => {
+  const userInfo = JSON.parse(localStorage.getItem("userInfo"));
+  userId.value = userInfo.id;
+};
+
+// 设置数据
+const setFormData = async (data) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      formData[key] = data[key];
+    }
+  }
+};
+
+// 数据保存
+const submit = async (done) => {
+  const validate = await formRef.value?.validate();
+  if (!validate) {
+    loading.value = true;
+    let data = { ...formData };
+    let result = {};
+    if (mode.value === "add") {
+      // 添加数据
+      data.id = undefined;
+      result = await api.save(data);
+    } else {
+      // 修改数据
+      result = await api.update(data.id, data);
+    }
+    if (result.code === 200) {
+      Message.success("操作成功");
+      emit("success");
+      done(true);
+    }
+    // 防止连续点击提交
+    setTimeout(() => {
+      loading.value = false;
+    }, 500);
+  }
+  done(false);
+};
+
+// 关闭弹窗
+const close = () => (visible.value = false);
+
+defineExpose({ open, setFormData });
+</script>

+ 124 - 0
src/views/v1/advert/agenList/index.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="ma-content-block">
+    <sa-table
+      ref="crudRef"
+      :options="options"
+      :columns="columns"
+      :searchForm="searchForm"
+    >
+      <!-- 搜索区 tableSearch -->
+      <template #tableSearch>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="后台归属人" field="auth_id">
+            <a-select
+              v-model="searchForm.auth_id"
+              :options="[]"
+              placeholder="请选择后台归属人"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="渠道名称" field="name">
+            <a-input
+              v-model="searchForm.name"
+              placeholder="请输入渠道名称"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+      </template>
+
+      <!-- Table 自定义渲染 -->
+      <template #operationBeforeExtend="{ record }">
+        <a-button type="text" @click="addAdvert(record)">
+          <icon-plus /> 添加广告位
+        </a-button>
+      </template>
+    </sa-table>
+
+    <!-- 编辑表单 -->
+    <edit-form ref="editRef" @success="refresh" />
+
+    <!-- 添加广告位表单 -->
+    <add-site-form ref="addSiteRef" @success="refresh" />
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Message } from "@arco-design/web-vue";
+import EditForm from "./edit.vue";
+import addSiteForm from "./addSite.vue";
+import api from "../../api/advert/agenList";
+
+// 引用定义
+const crudRef = ref();
+const editRef = ref();
+const viewRef = ref();
+const addSiteRef = ref();
+
+// 搜索表单
+const searchForm = ref({
+  auth_id: "",
+  name: "",
+});
+
+// 添加广告位
+const addAdvert = (record) => {
+  addSiteRef.value?.open();
+};
+
+// SaTable 基础配置
+const options = reactive({
+  api: api.getPageList,
+  rowSelection: { showCheckedAll: true },
+  add: {
+    show: true,
+    auth: ["/v1/advert/AgentList/save"],
+    func: async () => {
+      editRef.value?.open();
+    },
+  },
+  edit: {
+    show: true,
+    auth: ["/v1/advert/AgentList/update"],
+    func: async (record) => {
+      editRef.value?.open("edit");
+      editRef.value?.setFormData(record);
+    },
+  },
+  delete: {
+    show: true,
+    auth: ["/v1/advert/AgentList/destroy"],
+    func: async (params) => {
+      const resp = await api.destroy(params);
+      if (resp.code === 200) {
+        Message.success(`删除成功!`);
+        crudRef.value?.refresh();
+      }
+    },
+  },
+});
+
+// SaTable 列配置
+const columns = reactive([
+  { title: "媒体ID", dataIndex: "media_id", width: 180 },
+  { title: "渠道名称", dataIndex: "name", width: 180 },
+  { title: "后台归属人", dataIndex: "auth_name", width: 180 },
+]);
+
+// 页面数据初始化
+const initPage = async () => {};
+
+// SaTable 数据请求
+const refresh = async () => {
+  crudRef.value?.refresh();
+};
+
+// 页面加载完成执行
+onMounted(async () => {
+  initPage();
+  refresh();
+});
+</script>

+ 179 - 0
src/views/v1/advert/agentSite/edit.vue

@@ -0,0 +1,179 @@
+<template>
+  <component
+    is="a-modal"
+    :width="tool.getDevice() === 'mobile' ? '100%' : '600px'"
+    v-model:visible="visible"
+    :title="title"
+    :mask-closable="false"
+    :ok-loading="loading"
+    @cancel="close"
+    @before-ok="submit"
+  >
+    <!-- 表单信息 start -->
+    <a-form
+      ref="formRef"
+      :model="formData"
+      :rules="rules"
+      :auto-label-width="true"
+    >
+      <a-form-item label="媒体ID" field="media_id">
+        <a-select
+          v-model="formData.media_id"
+          :options="mediaOptions"
+          placeholder="请选择媒体ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="渠道ID" field="agent_id">
+        <a-select
+          v-model="formData.agent_id"
+          :options="agentOptions"
+          placeholder="请选择渠道ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="负责人ID" field="auth_id">
+        <a-select
+          v-model="formData.auth_id"
+          :options="authOptions"
+          placeholder="请选择负责人ID"
+          allow-clear
+        />
+      </a-form-item>
+      <a-form-item label="广告位名称" field="name">
+        <a-input v-model="formData.name" placeholder="请输入广告位名称" />
+      </a-form-item>
+    </a-form>
+    <!-- 表单信息 end -->
+  </component>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import tool from "@/utils/tool";
+import { Message, Modal } from "@arco-design/web-vue";
+import api from "../../api/advert/agentSite";
+import advertCommonApi from "../../api/advert/common";
+import { useUserStore } from "@/store";
+
+const emit = defineEmits(["success"]);
+// 引用定义
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
+const mode = ref("");
+const userStore = useUserStore();
+const mediaOptions = ref([]);
+const authOptions = ref([]);
+const agentOptions = ref([]);
+
+let title = computed(() => {
+  return "广告位" + (mode.value == "add" ? "-新增" : "-编辑");
+});
+
+// 表单初始值
+const initialFormData = {
+  id: null,
+  media_id: null,
+  agent_id: null,
+  auth_id: null,
+  name: "",
+};
+
+// 表单信息
+const formData = reactive({ ...initialFormData });
+
+// 验证规则
+const rules = {
+  media_id: [{ required: true, message: "媒体ID必需填写" }],
+  agent_id: [{ required: true, message: "渠道ID必需填写" }],
+  auth_id: [{ required: true, message: "负责人ID必需填写" }],
+  name: [{ required: true, message: "广告位名称必需填写" }],
+};
+
+// 获取媒体列表Options
+const getMediaOptions = async () => {
+  const res = await advertCommonApi.getMediaOptionsApi();
+  if (res.code == 200) {
+    mediaOptions.value = res.data;
+  }
+};
+
+// 获取渠道列表Options
+const getAgentOptions = async () => {
+  const res = await advertCommonApi.getAgentOptionsApi();
+  if (res.code == 200) {
+    agentOptions.value = res.data;
+  }
+};
+
+// 获取后台归属人列表
+const getAuthList = async () => {
+  const res = await advertCommonApi.getAuthOptionsApi();
+  if (res.code == 200) {
+    authOptions.value = res.data;
+  }
+};
+
+// 打开弹框
+const open = async (type = "add") => {
+  mode.value = type;
+  // 重置表单数据
+  Object.assign(formData, initialFormData);
+  formRef.value.clearValidate();
+  visible.value = true;
+  if (mode.value === "add") {
+    formData.auth_id = userStore.user.id;
+  }
+  await initPage();
+};
+
+// 初始化页面数据
+const initPage = async () => {
+  await getMediaOptions();
+  await getAgentOptions();
+  await getAuthList();
+};
+
+// 设置数据
+const setFormData = async (data) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      formData[key] = data[key];
+    }
+  }
+};
+
+// 数据保存
+const submit = async (done) => {
+  const validate = await formRef.value?.validate();
+  if (!validate) {
+    loading.value = true;
+    let data = { ...formData };
+    let result = {};
+    if (mode.value === "add") {
+      // 添加数据
+      data.id = undefined;
+      result = await api.save(data);
+    } else {
+      // 修改数据
+      result = await api.update(data.id, data);
+    }
+    if (result.code === 200) {
+      Message.success("操作成功");
+      emit("success");
+      done(true);
+    }
+    // 防止连续点击提交
+    setTimeout(() => {
+      loading.value = false;
+    }, 500);
+  }
+  done(false);
+};
+
+// 关闭弹窗
+const close = () => (visible.value = false);
+
+defineExpose({ open, setFormData });
+</script>

+ 169 - 0
src/views/v1/advert/agentSite/index.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="ma-content-block">
+    <sa-table
+      ref="crudRef"
+      :options="options"
+      :columns="columns"
+      :searchForm="searchForm"
+    >
+      <!-- 搜索区 tableSearch -->
+      <template #tableSearch>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="媒体ID" field="media_id">
+            <a-select
+              v-model="searchForm.media_id"
+              :options="mediaOptions"
+              placeholder="请选择媒体ID"
+              allow-search
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="渠道ID" field="agent_id">
+            <a-select
+              v-model="searchForm.agent_id"
+              :options="agentOptions"
+              placeholder="请选择渠道ID"
+              allow-search
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="负责人" field="auth_id">
+            <a-select
+              v-model="searchForm.auth_id"
+              :options="authOptions"
+              placeholder="请选择负责人"
+              allow-search
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="广告位名称" field="name">
+            <a-input
+              v-model="searchForm.name"
+              placeholder="请输入广告位名称"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+      </template>
+
+      <!-- Table 自定义渲染 -->
+    </sa-table>
+    <!-- 编辑弹框 -->
+    <edit-form ref="editRef" @success="refresh" />
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Message } from "@arco-design/web-vue";
+import advertCommonApi from "../../api/advert/common";
+import editForm from "./edit.vue";
+
+import api from "../../api/advert/agentSite";
+
+// 引用定义
+const crudRef = ref();
+const viewRef = ref();
+const mediaOptions = ref([]);
+const agentOptions = ref([]);
+const authOptions = ref([]);
+const editRef = ref();
+
+// 搜索表单
+const searchForm = ref({
+  media_id: "",
+  agent_id: "",
+  auth_id: "",
+  name: "",
+});
+
+// SaTable 基础配置
+const options = reactive({
+  api: api.getPageList,
+  rowSelection: { showCheckedAll: true },
+  add: {
+    show: false,
+    auth: ["/v1/advert/AgentSite/save"],
+    func: async () => {
+      editRef.value?.open();
+    },
+  },
+  edit: {
+    show: true,
+    auth: ["/v1/advert/AgentSite/update"],
+    func: async (record) => {
+      editRef.value?.open("edit");
+      editRef.value?.setFormData(record);
+    },
+  },
+  delete: {
+    show: true,
+    auth: ["/v1/advert/AgentSite/destroy"],
+    func: async (params) => {
+      const resp = await api.destroy(params);
+      if (resp.code === 200) {
+        Message.success(`删除成功!`);
+        crudRef.value?.refresh();
+      }
+    },
+  },
+});
+
+// SaTable 列配置
+const columns = reactive([
+  { title: "广告位名称", dataIndex: "name", width: 180 },
+  { title: "媒体ID", dataIndex: "media_id", width: 180 },
+  { title: "媒体名", dataIndex: "media_name", width: 180 },
+  { title: "渠道ID", dataIndex: "agent_id", width: 180 },
+  { title: "渠道名", dataIndex: "agent_name", width: 180 },
+  { title: "负责人", dataIndex: "auth_name", width: 180 },
+]);
+
+// 获取媒体列表Options
+const getMediaOptions = async () => {
+  const res = await advertCommonApi.getMediaOptionsApi();
+  if (res.code == 200) {
+    mediaOptions.value = res.data;
+  }
+};
+
+// 获取渠道列表Options
+const getAgentOptions = async () => {
+  const res = await advertCommonApi.getAgentOptionsApi();
+  if (res.code == 200) {
+    agentOptions.value = res.data;
+  }
+};
+
+// 获取后台归属人列表
+const getAuthList = async () => {
+  const res = await advertCommonApi.getAuthOptionsApi();
+  if (res.code == 200) {
+    authOptions.value = res.data;
+  }
+};
+
+// 页面数据初始化
+const initPage = async () => {
+  await getMediaOptions();
+  await getAgentOptions();
+  await getAuthList();
+};
+
+// SaTable 数据请求
+const refresh = async () => {
+  crudRef.value?.refresh();
+};
+
+// 页面加载完成执行
+onMounted(async () => {
+  initPage();
+  refresh();
+});
+</script>

+ 162 - 0
src/views/v1/advert/mediaCost/edit.vue

@@ -0,0 +1,162 @@
+<template>
+  <component
+    is="a-modal"
+    :width="tool.getDevice() === 'mobile' ? '100%' : '600px'"
+    v-model:visible="visible"
+    :title="title"
+    :mask-closable="false"
+    :ok-loading="loading"
+    @cancel="close"
+    @before-ok="submit"
+  >
+    <!-- 表单信息 start -->
+    <a-form
+      ref="formRef"
+      :model="formData"
+      :rules="rules"
+      :auto-label-width="true"
+    >
+      <a-form-item label="投放游戏" field="game_id">
+        <a-select
+          v-model="formData.game_id"
+          allow-search
+          placeholder="请选择投放游戏"
+        >
+          <a-option
+            v-for="item in gameOptions"
+            :key="item.value"
+            :value="item.value"
+            :label="item.label"
+          />
+        </a-select>
+      </a-form-item>
+      <a-form-item label="广告位ID" field="site_id">
+        <a-input v-model="formData.site_id" placeholder="请输入广告位ID" />
+      </a-form-item>
+      <a-form-item label="消耗日期" field="tdate">
+        <a-date-picker
+          v-model="formData.tdate"
+          :show-time="false"
+          mode="date"
+          placeholder="请选择消耗日期"
+          style="width: 100%"
+        />
+      </a-form-item>
+
+      <a-form-item label="消耗金额" field="money">
+        <a-input v-model="formData.money" placeholder="请输入消耗金额" />
+      </a-form-item>
+      <a-form-item label="备注" field="memo">
+        <a-input v-model="formData.memo" placeholder="请输入备注" />
+      </a-form-item>
+    </a-form>
+    <!-- 表单信息 end -->
+  </component>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import tool from "@/utils/tool";
+import { Message, Modal } from "@arco-design/web-vue";
+import api from "../../api/advert/mediaCost";
+import centerCommonApi from "../../api/center/common";
+
+const emit = defineEmits(["success"]);
+// 引用定义
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
+const mode = ref("");
+const gameOptions = ref([]);
+
+let title = computed(() => {
+  return "媒体消耗" + (mode.value == "add" ? "-新增" : "-编辑");
+});
+
+// 表单初始值
+const initialFormData = {
+  id: null,
+  tdate: "",
+  game_id: null,
+  site_id: null,
+  money: "0.00",
+  memo: "",
+  add_type: 1,
+};
+
+// 表单信息
+const formData = reactive({ ...initialFormData });
+
+// 验证规则
+const rules = {
+  game_id: [{ required: true, message: "投放游戏必需填写" }],
+  site_id: [{ required: true, message: "广告位ID必需填写" }],
+  tdate: [{ required: true, message: "消耗日期必需填写" }],
+  money: [{ required: true, message: "消耗金额必需填写" }],
+};
+
+// 打开弹框
+const open = async (type = "add") => {
+  mode.value = type;
+  // 重置表单数据
+  Object.assign(formData, initialFormData);
+  formRef.value.clearValidate();
+  visible.value = true;
+  await initPage();
+};
+
+// 初始化页面数据
+const initPage = async () => {
+  await getGameOptions();
+};
+
+// 获取投放游戏选项
+const getGameOptions = async () => {
+  const res = await centerCommonApi.getGameOptionsApi();
+  if (res.code === 200) {
+    gameOptions.value = res.data;
+  }
+};
+
+// 设置数据
+const setFormData = async (data) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      formData[key] = data[key];
+    }
+  }
+};
+
+// 数据保存
+const submit = async (done) => {
+  const validate = await formRef.value?.validate();
+  if (!validate) {
+    loading.value = true;
+    let data = { ...formData };
+    let result = {};
+    if (mode.value === "add") {
+      // 添加数据
+      data.id = undefined;
+      result = await api.save({ ...data, add_type: 1 });
+    } else {
+      // 修改数据
+      result = await api.update(data.id, { ...data, add_type: 1 });
+    }
+    if (result.code === 200) {
+      Message.success("操作成功");
+      emit("success");
+      done(true);
+    }
+    // 防止连续点击提交
+    setTimeout(() => {
+      loading.value = false;
+    }, 500);
+  }
+  done(false);
+};
+
+// 关闭弹窗
+const close = () => (visible.value = false);
+
+defineExpose({ open, setFormData });
+</script>

+ 231 - 0
src/views/v1/advert/mediaCost/index.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="ma-content-block">
+    <sa-table
+      ref="crudRef"
+      :options="options"
+      :columns="columns"
+      :searchForm="searchForm"
+    >
+      <!-- 搜索区 tableSearch -->
+      <template #tableSearch>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="结算日期" field="tdate">
+            <a-range-picker
+              v-model="searchForm.tdate"
+              :show-time="false"
+              mode="date"
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="投放游戏" field="game_id">
+            <a-select
+              v-model="searchForm.game_id"
+              placeholder="请选择投放游戏"
+              :options="gameOptions"
+              allow-clear
+              allow-search
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="媒体类型" field="media_id">
+            <a-select
+              v-model="searchForm.media_id"
+              placeholder="请选择媒体类型"
+              :options="mediaOptions"
+              allow-clear
+              allow-search
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="渠道ID" field="agent_id">
+            <a-input
+              v-model="searchForm.agent_id"
+              placeholder="请输入渠道ID"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="广告位ID" field="site_id">
+            <a-input
+              v-model="searchForm.site_id"
+              placeholder="请输入广告位ID"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="负责人" field="auth_id">
+            <sa-select
+              v-model="searchForm.auth_id"
+              :options="authOptions"
+              placeholder="请选择负责人"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="录入方式" field="add_type">
+            <sa-select
+              v-model="searchForm.add_type"
+              dict=""
+              placeholder="请选择录入方式"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="备注" field="memo">
+            <a-input
+              v-model="searchForm.memo"
+              placeholder="请输入备注"
+              allow-clear
+            />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="录入时间" field="create_time">
+            <a-range-picker
+              v-model="searchForm.create_time"
+              :show-time="true"
+              mode="date"
+            />
+          </a-form-item>
+        </a-col>
+      </template>
+
+      <!-- Table 自定义渲染 -->
+    </sa-table>
+
+    <!-- 编辑表单 -->
+    <edit-form ref="editRef" @success="refresh" />
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Message } from "@arco-design/web-vue";
+import EditForm from "./edit.vue";
+import api from "../../api/advert/mediaCost";
+import commonAdvertApi from "../../api/advert/common";
+import commonCenterApi from "../../api/center/common";
+
+// 引用定义
+const crudRef = ref();
+const editRef = ref();
+const viewRef = ref();
+const mediaOptions = ref([]);
+const gameOptions = ref([]);
+const authOptions = ref([]);
+
+// 搜索表单
+const searchForm = ref({
+  tdate: [],
+  game_id: "",
+  media_id: "",
+  agent_id: "",
+  site_id: "",
+  auth_id: "",
+  add_type: "",
+  memo: "",
+  create_time: [],
+});
+
+// SaTable 基础配置
+const options = reactive({
+  api: api.getPageList,
+  rowSelection: { showCheckedAll: true },
+  add: {
+    show: true,
+    auth: ["/v1/advert/MediaCost/save"],
+    func: async () => {
+      editRef.value?.open();
+    },
+  },
+  edit: {
+    show: true,
+    auth: ["/v1/advert/MediaCost/update"],
+    func: async (record) => {
+      editRef.value?.open("edit");
+      editRef.value?.setFormData(record);
+    },
+  },
+  delete: {
+    show: true,
+    auth: ["/v1/advert/MediaCost/destroy"],
+    func: async (params) => {
+      const resp = await api.destroy(params);
+      if (resp.code === 200) {
+        Message.success(`删除成功!`);
+        crudRef.value?.refresh();
+      }
+    },
+  },
+});
+
+// SaTable 列配置
+const columns = reactive([
+  { title: "结算日期", dataIndex: "tdate", width: 120 },
+  { title: "广告位ID", dataIndex: "site_id", width: 120 },
+  { title: "广告位名称", dataIndex: "site_name", width: 120 },
+  { title: "渠道ID", dataIndex: "agent_id", width: 120 },
+  { title: "游戏", dataIndex: "game_name", width: 120 },
+  { title: "原始金额", dataIndex: "ori_money", width: 120 },
+  { title: "结算金额", dataIndex: "money", width: 120 },
+  { title: "录入时间", dataIndex: "create_time", width: 120 },
+  {
+    title: "录入方式",
+    dataIndex: "add_type",
+    type: "dict",
+    dict: "add_type",
+    width: 120,
+  },
+  { title: "备注", dataIndex: "memo", width: 120 },
+  { title: "负责人", dataIndex: "auth_name", width: 120 },
+]);
+
+// 页面数据初始化
+const initPage = async () => {
+  await getMediaOptions();
+  await getGameOptions();
+  await getAuthOptions();
+};
+
+// 获取媒体类型
+const getMediaOptions = async () => {
+  const resp = await commonAdvertApi.getAgentOptionsApi();
+  if (resp.code === 200) {
+    mediaOptions.value = resp.data;
+  }
+};
+
+// 获取负责人
+const getAuthOptions = async () => {
+  const resp = await commonAdvertApi.getAuthOptionsApi();
+  if (resp.code === 200) {
+    authOptions.value = resp.data;
+  }
+};
+
+// 获取投放游戏
+const getGameOptions = async () => {
+  const resp = await commonCenterApi.getGameOptionsApi();
+  if (resp.code === 200) {
+    gameOptions.value = resp.data;
+  }
+};
+
+// SaTable 数据请求
+const refresh = async () => {
+  crudRef.value?.refresh();
+};
+
+// 页面加载完成执行
+onMounted(async () => {
+  initPage();
+  refresh();
+});
+</script>

+ 136 - 0
src/views/v1/advert/mediaList/edit.vue

@@ -0,0 +1,136 @@
+<template>
+  <component
+    is="a-modal"
+    :width="tool.getDevice() === 'mobile' ? '100%' : '600px'"
+    v-model:visible="visible"
+    :title="title"
+    :mask-closable="false"
+    :ok-loading="loading"
+    @cancel="close"
+    @before-ok="submit">
+    <!-- 表单信息 start -->
+    <a-form ref="formRef" :model="formData" :rules="rules" :auto-label-width="true">
+      <a-form-item label="媒体名称" field="name">
+        <a-input v-model="formData.name" placeholder="请输入媒体名称" />
+      </a-form-item>
+      <a-form-item label="媒体渠道简称" field="channel_name">
+        <a-input v-model="formData.channel_name" placeholder="请输入媒体渠道简称" />
+      </a-form-item>
+      <a-form-item label="安卓监测链接" field="andurl">
+        <a-input v-model="formData.andurl" placeholder="请输入安卓监测链接" />
+      </a-form-item>
+      <a-form-item label="ios监测链接" field="iosurl">
+        <a-input v-model="formData.iosurl" placeholder="请输入ios监测链接" />
+      </a-form-item>
+      <a-form-item label="小游戏监测链接" field="xyxurl">
+        <a-input v-model="formData.xyxurl" placeholder="请输入小游戏监测链接" />
+      </a-form-item>
+      <a-form-item label="小游戏路径参数补充" field="appleturl">
+        <a-input v-model="formData.appleturl" placeholder="请输入小游戏路径参数补充" />
+      </a-form-item>
+      <a-form-item label="状态" field="state">
+        <sa-radio v-model="formData.state" dict="nomal_or_stop" />
+      </a-form-item>
+    </a-form>
+    <!-- 表单信息 end -->
+  </component>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue'
+import tool from '@/utils/tool'
+import { Message, Modal } from '@arco-design/web-vue'
+import api from '../../api/advert/mediaList'
+
+const emit = defineEmits(['success'])
+// 引用定义
+const visible = ref(false)
+const loading = ref(false)
+const formRef = ref()
+const mode = ref('')
+
+let title = computed(() => {
+  return '广告媒体表' + (mode.value == 'add' ? '-新增' : '-编辑')
+})
+
+// 表单初始值
+const initialFormData = {
+  id: null,
+  name: '',
+  channel_name: '',
+  andurl: '',
+  iosurl: '',
+  xyxurl: '',
+  appleturl: '',
+  state: 1,
+}
+
+// 表单信息
+const formData = reactive({ ...initialFormData })
+
+// 验证规则
+const rules = {
+  name: [{ required: true, message: '媒体名称必需填写' }],
+  channel_name: [{ required: true, message: '媒体渠道简称必需填写' }],
+  andurl: [{ required: true, message: '安卓监测链接必需填写' }],
+  iosurl: [{ required: true, message: 'ios监测链接必需填写' }],
+  xyxurl: [{ required: true, message: '小游戏监测链接必需填写' }],
+  appleturl: [{ required: true, message: '小游戏路径参数补充必需填写' }],
+  state: [{ required: true, message: '状态必需填写' }],
+}
+
+// 打开弹框
+const open = async (type = 'add') => {
+  mode.value = type
+  // 重置表单数据
+  Object.assign(formData, initialFormData)
+  formRef.value.clearValidate()
+  visible.value = true
+  await initPage()
+}
+
+// 初始化页面数据
+const initPage = async () => {}
+
+// 设置数据
+const setFormData = async (data) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      formData[key] = data[key]
+    }
+  }
+}
+
+// 数据保存
+const submit = async (done) => {
+  const validate = await formRef.value?.validate()
+  if (!validate) {
+    loading.value = true
+    let data = { ...formData }
+    let result = {}
+    if (mode.value === 'add') {
+      // 添加数据
+      data.id = undefined
+      result = await api.save(data)
+    } else {
+      // 修改数据
+      result = await api.update(data.id, data)
+    }
+    if (result.code === 200) {
+      Message.success('操作成功')
+      emit('success')
+      done(true)
+    }
+    // 防止连续点击提交
+    setTimeout(() => {
+      loading.value = false
+    }, 500)
+  }
+  done(false)
+}
+
+// 关闭弹窗
+const close = () => (visible.value = false)
+
+defineExpose({ open, setFormData })
+</script>

+ 107 - 0
src/views/v1/advert/mediaList/index.vue

@@ -0,0 +1,107 @@
+<template>
+  <div class="ma-content-block">
+    <sa-table ref="crudRef" :options="options" :columns="columns" :searchForm="searchForm">
+      <!-- 搜索区 tableSearch -->
+      <template #tableSearch>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="媒体id" field="id">
+            <a-input v-model="searchForm.id" placeholder="请输入媒体id" allow-clear />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="媒体名称" field="name">
+            <a-input v-model="searchForm.name" placeholder="请输入媒体名称" allow-clear />
+          </a-form-item>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <a-form-item label="媒体渠道简称" field="channel_name">
+            <a-input v-model="searchForm.channel_name" placeholder="请输入媒体渠道简称" allow-clear />
+          </a-form-item>
+        </a-col>
+      </template>
+
+      <!-- Table 自定义渲染 -->
+    </sa-table>
+
+    <!-- 编辑表单 -->
+    <edit-form ref="editRef" @success="refresh" />
+
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from 'vue'
+import { Message } from '@arco-design/web-vue'
+import EditForm from './edit.vue'
+import api from '../../api/advert/mediaList'
+
+// 引用定义
+const crudRef = ref()
+const editRef = ref()
+const viewRef = ref()
+
+// 搜索表单
+const searchForm = ref({
+  id: '',
+  name: '',
+  channel_name: '',
+})
+
+// SaTable 基础配置
+const options = reactive({
+  api: api.getPageList,
+  rowSelection: { showCheckedAll: true },
+  add: {
+    show: true,
+    auth: ['/v1/advert/MediaList/save'],
+    func: async () => {
+      editRef.value?.open()
+    },
+  },
+  edit: {
+    show: true,
+    auth: ['/v1/advert/MediaList/update'],
+    func: async (record) => {
+      editRef.value?.open('edit')
+      editRef.value?.setFormData(record)
+    },
+  },
+  delete: {
+    show: true,
+    auth: ['/v1/advert/MediaList/destroy'],
+    func: async (params) => {
+      const resp = await api.destroy(params)
+      if (resp.code === 200) {
+        Message.success(`删除成功!`)
+        crudRef.value?.refresh()
+      }
+    },
+  },
+})
+
+// SaTable 列配置
+const columns = reactive([
+  { title: '媒体id', dataIndex: 'id', width: 180 },
+  { title: '媒体名称', dataIndex: 'name', width: 180 },
+  { title: '媒体渠道简称', dataIndex: 'channel_name', width: 180 },
+  { title: '安卓监测链接', dataIndex: 'andurl', width: 180 },
+  { title: 'ios监测链接', dataIndex: 'iosurl', width: 180 },
+  { title: '小游戏监测链接', dataIndex: 'xyxurl', width: 180 },
+  { title: '小游戏路径参数补充', dataIndex: 'appleturl', width: 180 },
+  { title: '状态', dataIndex: 'state', type: 'dict', dict: 'nomal_or_stop', width: 120 },
+])
+
+// 页面数据初始化
+const initPage = async () => {}
+
+// SaTable 数据请求
+const refresh = async () => {
+  crudRef.value?.refresh()
+}
+
+// 页面加载完成执行
+onMounted(async () => {
+  initPage()
+  refresh()
+})
+</script>

+ 67 - 0
src/views/v1/api/advert/agenList.js

@@ -0,0 +1,67 @@
+import { request } from '@/utils/request.js'
+
+/**
+ * 渠道管理 API接口
+ */
+export default {
+
+  /**
+   * 数据列表
+   * @returns
+   */
+  getPageList(params = {}) {
+    return request({
+      url: '/v1/advert/AgentList/index',
+      method: 'get',
+      params
+    })
+  },
+
+  /**
+   * 添加数据
+   * @returns
+   */
+  save(params = {}) {
+    return request({
+      url: '/v1/advert/AgentList/save',
+      method: 'post',
+      data: params
+    })
+  },
+
+  /**
+   * 更新数据
+   * @returns
+   */
+  update(id, data = {}) {
+    return request({
+      url: '/v1/advert/AgentList/update?id=' + id,
+      method: 'put',
+      data
+    })
+  },
+
+  /**
+   * 读取数据
+   * @returns
+   */
+  read(id) {
+    return request({
+      url: '/v1/advert/AgentList/read?id=' + id,
+      method: 'get'
+    })
+  },
+
+  /**
+   * 删除数据
+   * @returns
+   */
+  destroy(data) {
+    return request({
+      url: '/v1/advert/AgentList/destroy',
+      method: 'delete',
+      data
+    })
+  },
+
+}

+ 67 - 0
src/views/v1/api/advert/agentSite.js

@@ -0,0 +1,67 @@
+import { request } from '@/utils/request.js'
+
+/**
+ * 广告位列表 API接口
+ */
+export default {
+
+  /**
+   * 数据列表
+   * @returns
+   */
+  getPageList(params = {}) {
+    return request({
+      url: '/v1/advert/AgentSite/index',
+      method: 'get',
+      params
+    })
+  },
+
+  /**
+   * 添加数据
+   * @returns
+   */
+  save(params = {}) {
+    return request({
+      url: '/v1/advert/AgentSite/save',
+      method: 'post',
+      data: params
+    })
+  },
+
+  /**
+   * 更新数据
+   * @returns
+   */
+  update(id, data = {}) {
+    return request({
+      url: '/v1/advert/AgentSite/update?id=' + id,
+      method: 'put',
+      data
+    })
+  },
+
+  /**
+   * 读取数据
+   * @returns
+   */
+  read(id) {
+    return request({
+      url: '/v1/advert/AgentSite/read?id=' + id,
+      method: 'get'
+    })
+  },
+
+  /**
+   * 删除数据
+   * @returns
+   */
+  destroy(data) {
+    return request({
+      url: '/v1/advert/AgentSite/destroy',
+      method: 'delete',
+      data
+    })
+  },
+
+}

+ 42 - 0
src/views/v1/api/advert/common.js

@@ -0,0 +1,42 @@
+import { request } from "@/utils/request.js";
+
+/**
+ * 公共接口 API接口
+ */
+export default {
+  /**
+   * 获取媒体列表options
+   * @returns
+   */
+  getMediaOptionsApi(params = {}) {
+    return request({
+      url: "/v1/common/getMediaOptions",
+      method: "get",
+      params,
+    });
+  },
+
+  /**
+   * 获取渠道列表options
+   * @returns
+   */
+  getAgentOptionsApi(params = {}) {
+    return request({
+      url: "/v1/common/getAgentOptions",
+      method: "get",
+      params,
+    });
+  },
+
+  /**
+   * 获取后台归属人列表
+   * @returns
+   */
+  getAuthOptionsApi(params = {}) {
+    return request({
+      url: "/v1/common/getAuthOptions",
+      method: "get",
+      params,
+    });
+  },
+};

+ 67 - 0
src/views/v1/api/advert/mediaCost.js

@@ -0,0 +1,67 @@
+import { request } from '@/utils/request.js'
+
+/**
+ * 媒体消耗 API接口
+ */
+export default {
+
+  /**
+   * 数据列表
+   * @returns
+   */
+  getPageList(params = {}) {
+    return request({
+      url: '/v1/advert/MediaCost/index',
+      method: 'get',
+      params
+    })
+  },
+
+  /**
+   * 添加数据
+   * @returns
+   */
+  save(params = {}) {
+    return request({
+      url: '/v1/advert/MediaCost/save',
+      method: 'post',
+      data: params
+    })
+  },
+
+  /**
+   * 更新数据
+   * @returns
+   */
+  update(id, data = {}) {
+    return request({
+      url: '/v1/advert/MediaCost/update?id=' + id,
+      method: 'put',
+      data
+    })
+  },
+
+  /**
+   * 读取数据
+   * @returns
+   */
+  read(id) {
+    return request({
+      url: '/v1/advert/MediaCost/read?id=' + id,
+      method: 'get'
+    })
+  },
+
+  /**
+   * 删除数据
+   * @returns
+   */
+  destroy(data) {
+    return request({
+      url: '/v1/advert/MediaCost/destroy',
+      method: 'delete',
+      data
+    })
+  },
+
+}

+ 67 - 0
src/views/v1/api/advert/mediaList.js

@@ -0,0 +1,67 @@
+import { request } from '@/utils/request.js'
+
+/**
+ * 广告媒体表 API接口
+ */
+export default {
+
+  /**
+   * 数据列表
+   * @returns
+   */
+  getPageList(params = {}) {
+    return request({
+      url: '/v1/advert/MediaList/index',
+      method: 'get',
+      params
+    })
+  },
+
+  /**
+   * 添加数据
+   * @returns
+   */
+  save(params = {}) {
+    return request({
+      url: '/v1/advert/MediaList/save',
+      method: 'post',
+      data: params
+    })
+  },
+
+  /**
+   * 更新数据
+   * @returns
+   */
+  update(id, data = {}) {
+    return request({
+      url: '/v1/advert/MediaList/update?id=' + id,
+      method: 'put',
+      data
+    })
+  },
+
+  /**
+   * 读取数据
+   * @returns
+   */
+  read(id) {
+    return request({
+      url: '/v1/advert/MediaList/read?id=' + id,
+      method: 'get'
+    })
+  },
+
+  /**
+   * 删除数据
+   * @returns
+   */
+  destroy(data) {
+    return request({
+      url: '/v1/advert/MediaList/destroy',
+      method: 'delete',
+      data
+    })
+  },
+
+}

+ 3 - 3
src/views/v1/api/center/common.js

@@ -10,7 +10,7 @@ export default {
    */
   getMainGameOptionsApi(params = {}) {
     return request({
-      url: "/v1/center/common/getMainGameOptions",
+      url: "/v1/common/getMainGameOptions",
       method: "get",
       params,
     });
@@ -23,7 +23,7 @@ export default {
    */
   getGameOptionsApi(params = {}) {
     return request({
-      url: "/v1/center/common/getGameOptions",
+      url: "/v1/common/getGameOptions",
       method: "get",
       params,
     });
@@ -36,7 +36,7 @@ export default {
    */
   getTreeGameOptionsApi(params = {}) {
     return request({
-      url: "/v1/center/common/getTreeGameOptions",
+      url: "/v1/common/getTreeGameOptions",
       method: "get",
       params,
     });