Browse Source

RING:阅文快应用列表

ringcode 3 years ago
parent
commit
7ff3f3ccd7

+ 61 - 0
src/api/index.ts

@@ -725,3 +725,64 @@ export const getFinanceSum = (
 ): any => {
   return axios("/ad/adFinanceStatSum", { params: query });
 };
+
+/**
+ * 获取推广链接列表
+ * @returns
+ */
+export const getPromotionList = (data: {
+  book_name: string;
+  channel_name: string;
+  channel_id: string | number;
+  page: number
+}) => {
+  // return axios("/yuewen/promotions", { params: data });
+  return axios(`/yuewen/promotions?book_name=${data.book_name}&channel_name=${data.channel_name}&channel_id=${data.channel_id}&page=${data.page}`);
+};
+
+/**
+ *  删除推广信息
+ * @param channel_id
+ */
+export const deletePromotion = (
+  query: { channel_id: number }
+): any => {
+  return axios("yuewen/deletePromotion", { params: query });
+};
+
+//添加推广链接
+export const addPromotionLInk = (data: {
+  channel_id: string | number;
+  channel_name: string;
+  book_name: string;
+}) => {
+  return axios.post("/yuewen/createPromotion", data);
+};
+
+//修改回传配置
+export const updateReportConfig = (data: {
+  channel_id: string | number;
+  rate: number
+}) => {
+  return axios.post("/yuewen/updateReportConfig", data);
+};
+
+/**
+ * 获取用户数据
+ * @param channel_id
+ */
+export const getUserData = (
+  query: { channel_id: number | string, page: number, is_paid?: number }
+): any => {
+  return axios("yuewen/registerUsers", { params: query });
+};
+
+/**
+ *  用户数据强制回传
+ * @param uid
+ */
+export const forceReport = (
+  query: { uid: number | string }
+): any => {
+  return axios("yuewen/forceReport", { params: query });
+};

+ 11 - 1
src/router/async.ts

@@ -154,6 +154,16 @@ export const Financial: RouteConfig = {
   component: () => import("@/views/financial/index.vue")
 };
 
+export const QuickApp: RouteConfig = {
+  name: "QuickApp",
+  path: "/quickapp",
+  icon: "ProjectOutlined",
+  meta: {
+    title: "阅文快应用"
+  },
+  component: () => import("@/views/read/quick-app.vue")
+};
+
 export const ForgetPwd: RouteConfig = {
   name: "ForgetPwd",
   path: "/forgetpwd",
@@ -166,6 +176,6 @@ export const ForgetPwd: RouteConfig = {
 
 
 
-const asyncRoutes: RouteConfig[] = [AccountManager, PutManager, Financial,ForgetPwd];
+const asyncRoutes: RouteConfig[] = [AccountManager, PutManager, Financial, QuickApp, ForgetPwd];
 
 export default asyncRoutes;

+ 1 - 1
src/views/_pageOptions/table-put.ts

@@ -445,7 +445,7 @@ export const TableColumnOfPutAdPlan = [
   },
   {
     fixed: "left",
-    title: "广告名",
+    title: "计划名称",
     dataIndex: "ad_name",
     slots: {
       customRender: "ad_name",

+ 55 - 0
src/views/_pageOptions/table_yuewen.ts

@@ -0,0 +1,55 @@
+// 阅文快应用列表
+export const TableColumnOfYuewen = [
+  {
+    title: '渠道名称',
+    dataIndex: 'channel_name',
+  },
+  {
+    title: '链接ID',
+    dataIndex: 'channel_id',
+  },
+  {
+    title: '推广作品',
+    dataIndex: 'book_name',
+  },
+  {
+    title: '回传比例(%)',
+    dataIndex: 'rate',
+  },
+  {
+    title: '操作',
+    dataIndex: 'operation',
+    slots: { customRender: 'operation' },
+  },
+]
+
+// 用户数据
+export const TableColumnOfUserData = [
+  {
+    title: 'uuid',
+    dataIndex: 'uid',
+  },
+  {
+    title: '注册时间',
+    dataIndex: 'register_at',
+  },
+  {
+    title: '推广计划ID',
+    dataIndex: 'aid',
+  },
+  {
+    title: '计划平台',
+    dataIndex: 'platform',
+    slots: { customRender: 'platform' },
+  },
+  {
+    title: '付费状态',
+    dataIndex: 'is_paid',
+    slots: { customRender: 'is_paid' },
+  },
+  {
+    title: '操作',
+    dataIndex: 'operation',
+    slots: { customRender: 'operation' },
+  },
+]

+ 95 - 0
src/views/read/components/user-data.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="user-data">
+    <div class="table">
+      <a-radio-group
+        v-model:value="is_paid"
+        button-style="solid"
+        @change="getList({ current: 1 })"
+        style="margin-bottom: 10px"
+      >
+        <a-radio-button value="">全部</a-radio-button>
+        <a-radio-button :value="1">付费</a-radio-button>
+        <a-radio-button :value="0">未付费</a-radio-button>
+      </a-radio-group>
+      <a-table
+        bordered
+        :data-source="list"
+        :columns="columns"
+        @change="getList"
+        rowKey="uid"
+        :loading="loading"
+      >
+        <template #platform="{}">头条</template>
+        <template #is_paid="{ record }">
+          <span v-show="record.is_paid">付费</span>
+          <span v-show="!record.is_paid">未付费</span>
+        </template>
+        <template #operation="{ record }">
+          <a v-show="!record.is_reported" @click="onForceReport(record.uid)"
+            >强制回传</a
+          >
+          <span v-show="record.is_reported" style="color: rgb(190, 190, 190)"
+            >已上报</span
+          >
+        </template>
+      </a-table>
+      <span style="color: rgb(200, 200, 200)">总共{{ meta.total }}个项目</span>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import useApp from "@/hooks/useApp";
+import { defineComponent, reactive, toRefs, ref } from "vue";
+//getPromotionList
+import { getUserData, forceReport } from "@/api";
+import { message } from "ant-design-vue";
+import { TableColumnOfUserData } from "@/views/_pageOptions/table_yuewen";
+
+const UserData = defineComponent({
+  props: ["channelId"],
+  setup(props) {
+    const state = reactive({
+      id: "",
+      columns: TableColumnOfUserData,
+      list: ref<any[]>([]),
+      meta: {},
+      is_paid: "",
+      loading: false,
+    });
+    return { ...toRefs(state) };
+  },
+  mounted() {
+    this.id = this.$props.channelId;
+    this.getList({ current: 1 });
+  },
+  methods: {
+    async getList(page?: any) {
+      this.loading = true;
+      try {
+        let param: any = { channel_id: this.id, page: page.current };
+        if (this.is_paid !== "") param.is_paid = this.is_paid;
+        let { data } = await getUserData(param);
+        this.loading = false;
+        this.list = data.list;
+        this.meta = data.meta;
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    async onForceReport(uid: number) {
+      try {
+        await forceReport({ uid });
+        message.success("强制回传成功");
+        this.getList({ current: 1 });
+      } catch (err) {
+        console.log(err);
+      }
+    },
+  },
+});
+
+export default UserData;
+</script>
+<style lang="scss" scoped>
+</style>

+ 308 - 0
src/views/read/quick-app.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="quick-app">
+    <div class="title-box">
+      <h3>阅文快应用</h3>
+      <a-button type="primary" @click="onAddLink">添加</a-button>
+    </div>
+    <div class="padding-box">
+      <div class="search-box">
+        <a-form layout="inline" :model="search">
+          <a-form-item label="渠道名称">
+            <a-input
+              v-model:value="search.channel_name"
+              placeholder="请输入渠道名称"
+            >
+            </a-input>
+          </a-form-item>
+          <a-form-item label="链接ID">
+            <a-input
+              v-model:value="search.channel_id"
+              placeholder="请输入链接ID"
+            >
+            </a-input>
+          </a-form-item>
+          <a-form-item label="推广作品">
+            <a-input
+              v-model:value="search.book_name"
+              placeholder="请输入推广作品名"
+            >
+            </a-input>
+          </a-form-item>
+          <a-form-item>
+            <a-button type="primary" @click="getList({ current: 1 })">
+              搜索
+            </a-button>
+            <a-button @click="resetSearch"> 重置 </a-button>
+          </a-form-item>
+        </a-form>
+      </div>
+      <div class="table-box">
+        <a-table
+          bordered
+          :data-source="list"
+          :columns="columns"
+          @change="getList"
+          rowKey="id"
+          :loading="loading"
+        >
+          <template #operation="{ record }">
+            <a @click="onRateConfig(record)">回传配置</a>&nbsp;
+            <a @click="openUserDrawer(record)">注册用户</a>&nbsp;
+            <a-popconfirm @confirm="onDelete(record)">
+              <template #title>
+                <p>确认删除#{{ record.channel_name }}#吗</p>
+                <p style="color: gray">
+                  删除后该链接下的注册付费用户将 <br />
+                  按100%回传
+                </p>
+              </template>
+              <a>删除</a>
+            </a-popconfirm>
+          </template>
+        </a-table>
+      </div>
+    </div>
+    <a-modal
+      title="添加派单链接"
+      v-model:visible="visible"
+      :confirm-loading="confirmLoading"
+      @ok="onEmitLink"
+    >
+      <a-form
+        v-if="visible"
+        v-bind="{
+          labelCol: { span: 4 },
+          wrapperCol: { span: 14 },
+        }"
+        labelAlign="right"
+        :model="addLink"
+        :rules="rules"
+        ref="formRef"
+      >
+        <a-form-item label="渠道名称" name="channel_name">
+          <a-input
+            v-model:value="addLink.channel_name"
+            placeholder="请复制阅文作品推广中的渠道名称至此处"
+          >
+          </a-input>
+        </a-form-item>
+        <a-form-item label="链接ID" name="channel_id">
+          <a-input
+            v-model:value="addLink.channel_id"
+            placeholder="请复制阅文作品推广中的链接ID至此处"
+          >
+          </a-input>
+        </a-form-item>
+        <a-form-item label="推广作品" name="book_name">
+          <a-input
+            v-model:value="addLink.book_name"
+            placeholder="请复制阅文作品推广中的推广作品至此处"
+          >
+          </a-input>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+    <a-modal title="回传配置" v-model:visible="rateVisible" @ok="onEmitRate">
+      <a-form
+        v-bind="{
+          labelCol: { span: 4 },
+          wrapperCol: { span: 8 },
+        }"
+        labelAlign="right"
+      >
+        <a-form-item label="回传比例">
+          <a-input
+            type="number"
+            v-model:value="rate"
+            placeholder="请输入回传比例"
+            suffix="%"
+            :max="100"
+            :min="0"
+          >
+          </a-input>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+    <a-drawer
+      title="注册用户数据"
+      width="70%"
+      placement="right"
+      :closable="false"
+      v-model:visible="drawerVisible"
+    >
+      <user-data v-if="drawerVisible" :channelId="channelId"></user-data>
+    </a-drawer>
+  </div>
+</template>
+
+<script lang="ts">
+import useApp from "@/hooks/useApp";
+import { defineComponent, reactive, toRefs, ref } from "vue";
+import { onBeforeRouteUpdate } from "vue-router";
+import { TableColumnOfYuewen } from "../_pageOptions/table_yuewen";
+//getPromotionList
+import {
+  getPromotionList,
+  addPromotionLInk,
+  updateReportConfig,
+  deletePromotion,
+} from "@/api";
+import { message } from "ant-design-vue";
+import UserData from "./components/user-data.vue";
+const PutDataIndex = defineComponent({
+  components: { UserData },
+  setup() {
+    const formRef = ref();
+    const state = reactive({
+      search: {
+        book_name: "", // 作品名
+        channel_name: "", // 渠道名
+        channel_id: "", // 链接id
+      },
+      addLink: {
+        channel_id: "", // 推广链接id
+        channel_name: "", // 渠道名
+        book_name: "", // 作品名
+      },
+      list: ref<any[]>([]),
+      visible: false, // 添加派单链接dialog
+      rateVisible: false, // 添加派单链接dialog
+      drawerVisible: false,
+      confirmLoading: false, // 提交链接loading
+      columns: TableColumnOfYuewen,
+      rate: 0, // 设置回传配置
+      channelId: "",
+      loading: false,
+      rules: {
+        channel_id: [
+          { required: true, message: "请输入推广链接ID", trigger: "change" },
+        ],
+        channel_name: [
+          { required: true, message: "请输入渠道名", trigger: "change" },
+        ],
+        book_name: [
+          { required: true, message: "请输入作品名", trigger: "change" },
+        ],
+      },
+    });
+    return { ...toRefs(state), formRef };
+  },
+  mounted() {
+    this.getList({ current: 1 });
+  },
+  methods: {
+    // 重置搜索条件
+    resetSearch() {
+      this.search.book_name = "";
+      this.search.channel_name = "";
+      this.search.channel_id = "";
+    },
+    // 获取推广链接数据
+    async getList(page?: any) {
+      this.loading = true;
+      let { data } = await getPromotionList({
+        page: page ? page.current : 1,
+        ...this.search,
+      });
+      this.loading = false;
+      this.list = data.list;
+    },
+    // 点击添加链接
+    onAddLink() {
+      this.addLink.channel_id = "";
+      this.addLink.channel_name = "";
+      this.addLink.book_name = "";
+      this.visible = true;
+    },
+    // 确认增加派单链接
+    async onEmitLink() {
+      this.formRef.validate().then(() => {
+      });
+      if (!this.addLink.channel_name) return message.warn("请输入渠道名称");
+      if (!this.addLink.channel_id) return message.warn("请输入链接ID");
+      if (!this.addLink.book_name) return message.warn("请输入推广作品");
+      try {
+        await addPromotionLInk(this.addLink);
+        message.success("新增成功");
+        this.getList({ current: 1 });
+        this.visible = false;
+      } catch (err) {
+        console.log("ERROR:", err);
+      }
+    },
+    // 删除
+    async onDelete(val: any) {
+      try {
+        await deletePromotion({ channel_id: val.channel_id });
+        this.getList({ current: 1 });
+        message.success("删除成功");
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    // 点击回传配置
+    onRateConfig(val: any) {
+      this.channelId = val.channel_id;
+      this.rateVisible = true;
+      this.rate = val.rate;
+    },
+    // 提交回传配置
+    async onEmitRate() {
+      if (this.rate > 100 || this.rate < 0)
+        return message.error("回传比例应在0~100之间");
+      try {
+        await updateReportConfig({
+          channel_id: this.channelId,
+          rate: this.rate,
+        });
+        message.success("修改成功");
+        this.getList({ current: 1 });
+        this.rateVisible = false;
+      } catch (err) {
+        console.log(err);
+      }
+    },
+    // 查看注册用户
+    openUserDrawer(val: any) {
+      this.channelId = val.channel_id;
+      this.drawerVisible = true;
+    },
+  },
+});
+
+export default PutDataIndex;
+</script>
+<style lang="scss" scoped>
+.quick-app {
+  .title-box {
+    width: 100%;
+    height: 70px;
+    padding: 20px 40px 0 30px;
+    background: white;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    h3 {
+      font-weight: bold;
+    }
+  }
+  .padding-box {
+    padding: 20px 20px 0;
+    .search-box {
+      height: 70px;
+      border-bottom: 1px solid rgb(214, 211, 211);
+      background: white;
+      display: flex;
+      align-items: center;
+      .ant-form-item,
+      .ant-btn {
+        margin-left: 20px;
+      }
+    }
+    .table-box {
+      padding-top: 20px;
+      background: white;
+    }
+  }
+}
+</style>