Sfoglia il codice sorgente

增加 cps账号池;

dodo hold 2 anni fa
parent
commit
1512a4e084

+ 83 - 0
src/api/pdd.ts

@@ -0,0 +1,83 @@
+import axios from 'axios';
+import type { ListRes } from './base';
+
+export interface FormRes {
+    msg: string;
+    code: number;
+    success: boolean;
+}
+
+export interface PddUpdateAccountModel {
+    id: number;
+    name: string;
+    val: any;
+}
+
+export function PddUpdateAccount(data: PddUpdateAccountModel) {
+    return axios.post<FormRes>('/api/PddUnion/update', data);
+}
+
+export interface UpdateCookieModel {
+    cookie: string;
+}
+
+export function updateCookies(data: UpdateCookieModel) {
+    return axios.post<FormRes>('/api/PddUnion/updateCookies', data);
+}
+
+// list
+export interface PddPoolRecord {
+    id: number;
+    pin: string;
+    name: string;
+    company: string;
+    phone: string;
+    create_time: Date;
+
+    daily_income_limit: number;
+    current_amt: number;
+
+    daily_calls_limit: number;
+    current_hourly_calls: number;
+
+    hourly_calls_limit: number;
+    current_daily_calls: number;
+
+    draw_balance: number;
+
+    description: string;
+    floorId: string;
+    last_time: Date;
+    login_time: Date;
+    refpid: string;
+    status: boolean;
+    work_mode: boolean;
+    end_point: string;
+    nodeName: string;
+    enable_parse: boolean;
+    enable_coupon: boolean;
+    enable_sync_order: boolean;
+    site_id: number;
+    unionid: string;
+    app_key: string;
+    app_secret: string;
+    user_agent: string;
+    cookies: string;
+    time_range: number;
+}
+
+export interface PddPoolParams extends Partial<PddPoolRecord> {
+    current: number;
+    pageSize: number;
+    sort?: string;
+    order?: string;
+    getTotal: boolean;
+}
+
+export interface PddPoolRes extends ListRes {
+    list: PddPoolRecord[];
+}
+
+export function queryPddPool(data: PddPoolParams) {
+    return axios.post<PddPoolRes>('/api/PddUnion/list', data);
+}

+ 4 - 0
src/api/taobao.ts

@@ -26,6 +26,10 @@ export interface UpdateConfigModel {
     
     cpsIgnorePercentageCity: string;
     cps_limit_per_ip_24h: number;
+    
+    pdd_limit_per_ip_24h:number;
+    pddIgnorePercentageCity: string;
+    pddIgnorePercentage: number;
 }
 
 

+ 6 - 0
src/locale/en-US/taoke.ts

@@ -1,10 +1,16 @@
 export default {
     'menu.settings': 'Settings',
     'menu.settings.config': 'System Config',
+    
     'menu.jd': 'JD Union',
     'menu.jd.updateCookies': 'Update JD Cookies',
     'menu.jd.list': 'Union Account',
 
+    
+    'menu.pdd': 'Pdd Union',
+    'menu.pdd.updateCookies': 'Update Pdd Cookies',
+    'menu.pdd.list': 'Union Account',
+
     'menu.taobao': 'Taobao Union',
     'menu.taobaoCoupon': 'Taobao Coupon',
     'menu.taobao.updateCookies': 'Update Cookies',

+ 7 - 0
src/locale/zh-CN/taoke.ts

@@ -1,11 +1,18 @@
 export default {
   'menu.settings': '系统设置',
   'menu.settings.config': '全局配置',
+
   'menu.jd': '京东联盟',
   'menu.jd.updateCookies': '更新 JD Cookies',
   'menu.jd.list': '联盟账号管理',
 
 
+  
+  'menu.pdd': '多多联盟',
+  'menu.pdd.updateCookies': '更新 PDD Cookies',
+  'menu.pdd.list': '联盟账号管理',
+
+
   'menu.taobao': '口令',
   'menu.taobaoCoupon': '优惠券',
   'menu.taobao.updateCookies': '更新Cookies',

+ 1 - 1
src/router/routes/modules/jd.ts

@@ -9,7 +9,7 @@ const TBCOUPON: AppRouteRecordRaw = {
         locale: 'menu.jd',
         requiresAuth: true,
         icon: 'icon-menu',
-        order: 0,
+        order: 1,
     },
     children: [
         {

+ 38 - 0
src/router/routes/modules/pdd.ts

@@ -0,0 +1,38 @@
+import { DEFAULT_LAYOUT } from '../base';
+import { AppRouteRecordRaw } from '../types';
+
+const pdd: AppRouteRecordRaw = {
+    path: '/pdd',
+    name: 'pdd',
+    component: DEFAULT_LAYOUT,
+    meta: {
+        locale: 'menu.pdd',
+        requiresAuth: true,
+        icon: 'icon-menu',
+        order: 2,
+    },
+    children: [
+        {
+            path: 'updateCookies',
+            name: 'pdd_UpdateCookies',
+            component: () => import('@/views/pdd/updateCookies.vue'),
+            meta: {
+                locale: 'menu.pdd.updateCookies',
+                requiresAuth: true,
+                roles: ['*'],
+            },
+        },
+        {
+            path: 'list',
+            name: 'pdd_list',
+            component: () => import('@/views/pdd/list.vue'),
+            meta: {
+                locale: 'menu.pdd.list',
+                requiresAuth: true,
+                roles: ['*'],
+            },
+        },
+    ],
+};
+
+export default pdd;

+ 26 - 10
src/views/dashboard/dailyLog/components/categories-percent.vue

@@ -1,22 +1,18 @@
 <template>
     <a-spin :loading="loading" style="width: 400px">
         <a-card class="general-card" :header-style="{ paddingBottom: '0' }">
-
             <div>
                 <template v-if="record.accountName !== ''">
                     {{ record.accountName }}
                 </template>
                 API调用记录 -
-                {{
-                    dayjs(record.report_date).format(
-                        record.isLeaf ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD'
-                    )
-                }}
+                {{ dayjs(record.report_date).format(record.isLeaf ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD') }}
             </div>
             <a-radio-group v-model:model-value="showTable" type="button" @change="showTableChange as any"
                 style="margin-bottom:5px">
                 <a-radio value="message"> 响应类型 </a-radio>
                 <a-radio value="reason"> 放弃明细 </a-radio>
+                <a-radio value="deeplink"> deeplink </a-radio>
             </a-radio-group>
             <a-table v-if="showTable === 'message'" size="mini" :data="renderList" :scrollbar="scrollbar"
                 :scroll="scroll" :pagination="false" :bordered="false">
@@ -39,15 +35,33 @@
                     </a-table-column>
                 </template>
             </a-table>
-
             <a-table v-if="showTable === 'reason'" size="mini" :data="renderList2" :scrollbar="scrollbar"
                 :scroll="scroll" :pagination="false" :bordered="false">
                 <template #columns>
                     <a-table-column title="错误原因" data-index="title">
                         <template #cell="{ record }">
-                            <a-typography-paragraph :ellipsis="{
-                                rows: 1,
-                            }">
+                            <a-typography-paragraph :ellipsis="{ rows: 1 }">
+                                {{ record.name }}
+                            </a-typography-paragraph>
+                        </template>
+                    </a-table-column>
+                    <a-table-column title="次数" data-index="value">
+                    </a-table-column>
+                    <a-table-column title="百分比" data-index="increases">
+                        <template #cell="{ record }">
+                            <div class="increases-cell">
+                                <span>{{ record.increases }}%</span>
+                            </div>
+                        </template>
+                    </a-table-column>
+                </template>
+            </a-table>
+            <a-table v-if="showTable === 'deeplink'" size="mini" :data="renderList3" :scrollbar="scrollbar"
+                :scroll="scroll" :pagination="false" :bordered="false">
+                <template #columns>
+                    <a-table-column title="分类" data-index="title">
+                        <template #cell="{ record }">
+                            <a-typography-paragraph :ellipsis="{ rows: 1 }">
                                 {{ record.name }}
                             </a-typography-paragraph>
                         </template>
@@ -90,6 +104,7 @@ const showTable = ref('message');
 const { loading, setLoading } = useLoading(true);
 const renderList = ref<ChartDataResponse[]>();
 const renderList2 = ref<ChartDataResponse[]>();
+const renderList3 = ref<ChartDataResponse[]>();
 
 const fetchData = async (
     params: ReportParams = {
@@ -103,6 +118,7 @@ const fetchData = async (
         const res = await queryReportChartData(params);
         renderList.value = res.data;
         renderList2.value = res.data2;
+        renderList3.value = res.data3;
     } catch (err) {
         console.log(err);
     } finally {

+ 156 - 0
src/views/pdd/components/WorkHourModel.vue

@@ -0,0 +1,156 @@
+<template>
+    <a-link type="text" @click="onClickSetWorkHour"> {{ formatWorkHours(record.time_range) }}</a-link>
+    <a-modal v-model:visible="showModel" title="设置工作时间" @cancel="handleCancel" @ok="handleOk">
+
+        <div style="margin-bottom:20px;">
+            <a-checkbox :model-value="checkedAll" :indeterminate="indeterminate" @change="handleChangeAll">全选
+            </a-checkbox>
+        </div>
+        <a-checkbox-group v-model="currentData" @change="handleChange">
+            <a-checkbox v-bind:key="h" v-for="h in defaultCheckedList" :value="h">{{ h }}</a-checkbox>
+        </a-checkbox-group>
+
+
+    </a-modal>
+</template>
+
+
+<script lang="ts" setup>
+/* eslint-disable no-bitwise, no-plusplus */
+
+import useLoading from '@/hooks/loading';
+import { defineProps, ref, reactive, defineEmits } from 'vue';
+import { PddUpdateAccountModel, PddUpdateAccount } from '@/api/pdd';
+import { Message } from '@arco-design/web-vue';
+
+const { loading, setLoading } = useLoading(true);
+
+const props = defineProps<{
+    record: any;
+}>();
+
+const emits = defineEmits(['change']);
+
+
+const showModel = ref(false);
+
+const indeterminate = ref(false)
+const checkedAll = ref(false)
+const currentData = ref<string[]>([])
+
+const form = reactive({
+    id: 0,
+    tiem_range: 0
+});
+
+const defaultCheckedList = ref<string[]>(['00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
+    '10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
+    '20', '21', '22', '23',
+]);
+
+const handleChangeAll = (value: any) => {
+    console.log(value)
+    indeterminate.value = false;
+    if (value) {
+        checkedAll.value = true;
+        currentData.value = defaultCheckedList.value
+    } else {
+        checkedAll.value = false;
+        currentData.value = []
+    }
+}
+
+const handleChange = (values: any[]) => {
+    if (values.length === 3) {
+        checkedAll.value = true
+        indeterminate.value = false;
+    } else if (values.length === 0) {
+        checkedAll.value = false
+        indeterminate.value = false;
+    } else {
+        checkedAll.value = false
+        indeterminate.value = true;
+    }
+}
+
+
+const formatWorkHours = (workHours: number): string => {
+    if (workHours === 0) {
+        return '-';
+    }
+
+    if (workHours === (1 << 24) - 1) {
+        return '全天';
+    }
+
+    const hours: number[] = [];
+    for (let i = 0; i < 24; i++) {
+        if (workHours & (1 << i)) {
+            hours.push(i);
+        }
+    }
+
+    return hours.join(', ');
+};
+
+const onClickSetWorkHour = () => {
+    showModel.value = true
+};
+
+const handleCancel = () => {
+    showModel.value = true
+};
+
+
+const GetWorkHours = () => {
+    let hours = 0;
+    currentData.value.forEach(hour => {
+        const hourInt = parseInt(hour, 10);
+        hours |= (1 << hourInt);
+    });
+    return hours;
+}
+
+// 将工作时间的整数表示转换为小时字符串数组的函数
+const GenerateData = (hours: number): string[] => {
+    const generatedData: string[] = [];
+    for (let i = 0; i < 24; i++) {
+        if (hours & (1 << i)) {
+            generatedData.push(i.toString().padStart(2, '0'));
+        }
+    }
+    return generatedData;
+};
+currentData.value = GenerateData(props.record.time_range);
+handleChange(currentData.value)
+
+const handleOk = async () => {
+    console.log(currentData.value, GetWorkHours())
+    const timeRange = GetWorkHours()
+    const args = {
+        id: props.record.id,
+        name: "time_range",
+        val: timeRange
+    } as PddUpdateAccountModel;
+
+    setLoading(true);
+    try {
+
+        const { data } = await PddUpdateAccount(args);
+        console.log(data, data.msg);
+        const msg = data.msg || '更新成功!';
+        if (data.success) {
+            Message.success(msg);
+            showModel.value = false
+            emits('change', null);
+        } else {
+            Message.error(data.msg);
+        }
+    } catch (e) { console.log(e) }
+    setLoading(false);
+};
+
+
+
+
+</script>

+ 608 - 0
src/views/pdd/list.vue

@@ -0,0 +1,608 @@
+<template>
+    <div class="container">
+        <Breadcrumb :items="['menu.pdd', 'menu.pdd.list']" />
+        <a-card class="general-card" :title="$t('menu.pdd.list')">
+            <a-row>
+                <a-col :flex="1">
+                    <a-form :model="formModel" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
+                        label-align="left">
+                        <a-row :gutter="16">
+                            <a-col :span="8">
+                                <a-form-item field="name" label="账号名">
+                                    <a-input v-model="formModel.name" placeholder="输入关键词搜索" />
+                                </a-form-item>
+                            </a-col>
+                            <a-col :span="8">
+                                <a-form-item field="lastTime" :label="$t('searchTable.form.lastTime')">
+                                    <a-range-picker v-model="formModel.lastTime" style="width: 100%" />
+                                </a-form-item>
+                            </a-col>
+                            <a-col :span="8">
+                                <a-form-item field="status" :label="$t('searchTable.form.status')">
+                                    <a-select v-model="formModel.status" :options="statusOptions" :placeholder="$t('searchTable.form.selectDefault')
+                                        " />
+                                </a-form-item>
+                            </a-col>
+                        </a-row>
+                    </a-form>
+                </a-col>
+                <a-divider style="height: 38px" direction="vertical" />
+                <a-col :flex="'86px'" style="text-align: right">
+                    <a-space direction="vertical" :size="18">
+                        <a-button type="primary" @click="search">
+                            <template #icon>
+                                <icon-search />
+                            </template>
+                            {{ $t('searchTable.form.search') }}
+                        </a-button>
+                    </a-space>
+                </a-col>
+            </a-row>
+            <a-divider style="margin-top: 0" />
+            <a-row style="margin-bottom: 16px">
+                <a-col :span="12">
+                    <a-space>
+                        <a-button type="primary">
+                            <template #icon>
+                                <icon-plus />
+                            </template>
+                            {{ $t('searchTable.operation.create') }}
+                        </a-button>
+                    </a-space>
+                </a-col>
+                <a-col :span="12" style="
+                        display: flex;
+                        align-items: center;
+                        justify-content: end;
+                    ">
+                    <a-tooltip :content="$t('searchTable.actions.refresh')">
+                        <div class="action-icon" @click="search"><icon-refresh size="18" /></div>
+                    </a-tooltip>
+                    <a-dropdown @select="handleSelectDensity">
+                        <a-tooltip :content="$t('searchTable.actions.density')">
+                            <div class="action-icon"><icon-line-height size="18" /></div>
+                        </a-tooltip>
+                        <template #content>
+                            <a-doption v-for="item in densityList" :key="item.value" :value="item.value"
+                                :class="{ active: item.value === size }">
+                                <span>{{ item.name }}</span>
+                            </a-doption>
+                        </template>
+                    </a-dropdown>
+                    <a-tooltip :content="$t('searchTable.actions.columnSetting')">
+                        <a-popover trigger="click" position="bl" @popup-visible-change="popupVisibleChange">
+                            <div class="action-icon"><icon-settings size="18" /></div>
+                            <template #content>
+                                <div id="tableSetting">
+                                    <div v-for="(item, index) in showColumns" :key="item.dataIndex" class="setting">
+                                        <div style="
+                                                margin-right: 4px;
+                                                cursor: move;
+                                            ">
+                                            <icon-drag-arrow />
+                                        </div>
+                                        <div>
+                                            <a-checkbox v-model="item.checked" @change="
+                                                handleChange(
+                                                    $event,
+                                                    item as TableColumnData,
+                                                    index
+                                                )
+                                                ">
+                                            </a-checkbox>
+                                        </div>
+                                        <div class="title">
+                                            {{
+                                                item.title === '#'
+                                                    ? '序列号'
+                                                    : item.title
+                                            }}
+                                        </div>
+                                    </div>
+                                </div>
+                            </template>
+                        </a-popover>
+                    </a-tooltip>
+                </a-col>
+            </a-row>
+
+            <a-table row-key="id" :loading="loading" :pagination="pagination" :summary="true" summary-text="汇总"
+                :columns="(cloneColumns as TableColumnData[])" :data="renderData" :bordered="{ headerCell: true }"
+                :size="size" @page-change="onPageChange">
+                <template #index="{ record }">
+                    {{ record.id }}
+                </template>
+                <template #name="{ record }">
+                    <a-list-item-meta>
+                        <template #title>
+                            {{ record.company }}
+                            <a-tag color="blue" v-if="record.work_mode == 1">网站推广</a-tag>
+                            <a-tag color="orange" v-else-if="record.work_mode == 2">媒体导购</a-tag>
+                            <a-tag color="purple" v-else>爬虫</a-tag>
+                        </template>
+                        <template #description>
+                            {{ record.description }}
+                        </template>
+                    </a-list-item-meta>
+                </template>
+                <template #hourly_calls_limit="{ record }">
+                    <a-tag bordered
+                        :color="record.current_hourly_calls > record.hourly_calls_limit && record.hourly_calls_limit > 0 ? 'red' : ''">
+                        {{ record.current_hourly_calls }} /
+                        {{ record.hourly_calls_limit }}
+                    </a-tag>
+                </template>
+
+                <template #daily_calls_limit="{ record }">
+                    <a-tag bordered
+                        :color="record.current_daily_calls > record.daily_calls_limit && record.daily_calls_limit > 0 ? 'red' : ''">
+                        {{ record.current_daily_calls }} /
+                        {{ record.daily_calls_limit }}
+                    </a-tag>
+                </template>
+                <template #nodeName="{ record }">
+                    <a-tag color="gray">{{ record.end_point }} - {{ record.nodeName }} </a-tag>
+                </template>
+
+                <template #status="{ record }">
+                    <a-tag v-if="record.status" bordered color="green" @click="changeStatus(record.id, false)">
+                        <template #icon>
+                            <icon-check />
+                        </template>
+                        在线
+                    </a-tag>
+                    <a-tag v-else bordered color="" @click="changeStatus(record.id, true)">
+                        <template #icon>
+                            <icon-stop />
+                        </template>
+                        下线
+                    </a-tag>
+                </template>
+                <template #actions="{ record }">
+                    <a-tag v-if="record.enable_parse" size="small" bordered color="red"
+                        @click="changeAttr(record.id, 'enable_parse', false)">
+                        转链
+                    </a-tag>
+                    <a-tag v-else size="small" bordered color="" @click="changeAttr(record.id, 'enable_parse', true)">
+                        转链
+                    </a-tag>
+                    <span style="margin: 5px;">
+                        <a-tag v-if="record.enable_coupon" size="small" bordered color="orange"
+                            @click="changeAttr(record.id, 'enable_coupon', false)">
+                            优惠券
+                        </a-tag>
+                        <a-tag v-else size="small" bordered color=""
+                            @click="changeAttr(record.id, 'enable_coupon', true)">
+                            优惠券
+                        </a-tag>
+                    </span>
+                </template>
+                <template #time="{ record }">
+                    <div style="color:gray;">
+                        <div>注册:{{ dayjs(record.create_time).format('MM-DD HH:mm') }}</div>
+                        <div>更新:{{ dayjs(record.last_time).format('MM-DD HH:mm') }}</div>
+                        <div v-if="dayjs().diff(dayjs(record.login_time), 'hours') < 48">
+                            登录:{{ dayjs(record.login_time).format('MM-DD HH:mm') }}</div>
+                    </div>
+                </template>
+                <template #summary-cell="{ column, record }">
+                    <div style="margin:10px auto" v-if="column.slotName == 'hourly_calls_limit'">
+                        {{ numberFormat(record.current_hourly_calls) }}
+                    </div>
+                    <div style="margin:10px auto" v-if="column.slotName == 'daily_calls_limit'">
+                        {{ numberFormat(record.current_daily_calls) }}
+                    </div>
+
+
+                    <template v-if="column.dataIndex == 'today_clickNum' ||
+                        column.dataIndex == 'today_orderNum' ||
+                        column.dataIndex == 'today_finishOrderNum' ||
+                        column.dataIndex == 'today_finishCosPrice'">
+
+                        <div>{{ numberFormat(record[column.dataIndex]) }}</div>
+                    </template>
+
+
+
+                    <template v-if="column.dataIndex == 'today_cosPrice' ||
+                        column.dataIndex == 'today_finishCosFee' ||
+                        column.dataIndex == 'today_cosFee'">
+
+                        <div>{{ amountFormat(record[column.dataIndex]) }}</div>
+                    </template>
+
+
+
+                </template>
+                <template #time_range="{ record }">
+                    <WorkHourModel :record="record" @change="search" />
+                </template>
+
+            </a-table>
+        </a-card>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { useRouter } from 'vue-router';
+import { computed, ref, reactive, watch, nextTick } from 'vue';
+import { useI18n } from 'vue-i18n';
+import dayjs from 'dayjs';
+import useLoading from '@/hooks/loading';
+import { queryPddPool, PddPoolRecord, PddPoolParams, PddUpdateAccountModel, PddUpdateAccount } from '@/api/pdd';
+import { Pagination } from '@/types/global';
+import { Message } from '@arco-design/web-vue';
+import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
+import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
+import cloneDeep from 'lodash/cloneDeep';
+import Sortable from 'sortablejs';
+import { numberFormat, amountFormat } from '@/utils/util';
+import WorkHourModel from './components/WorkHourModel.vue';
+
+type SizeProps = 'mini' | 'small' | 'medium' | 'large';
+type Column = TableColumnData & { checked?: true };
+
+const generateFormModel = () => {
+    return {
+        name: '',
+        lastTime: [],
+        status: '',
+        sort: 'status',
+        order: 'descending',
+    };
+};
+const router = useRouter();
+
+const { loading, setLoading } = useLoading(true);
+const { t } = useI18n();
+const renderData = ref<PddPoolRecord[]>([]);
+const formModel = ref(generateFormModel());
+const cloneColumns = ref<Column[]>([]);
+const showColumns = ref<Column[]>([]);
+
+const size = ref<SizeProps>('small');
+
+const basePagination: Pagination = {
+    current: 1,
+    pageSize: 50,
+};
+const pagination = reactive({
+    ...basePagination,
+});
+const densityList = computed(() => [
+    {
+        name: t('searchTable.size.mini'),
+        value: 'mini',
+    },
+    {
+        name: t('searchTable.size.small'),
+        value: 'small',
+    },
+    {
+        name: t('searchTable.size.medium'),
+        value: 'medium',
+    },
+    {
+        name: t('searchTable.size.large'),
+        value: 'large',
+    },
+]);
+
+const columns = computed<TableColumnData[]>(() => [
+    {
+        title: '#',
+        dataIndex: 'index',
+        slotName: 'index',
+        width: 50,
+    },
+    {
+        title: '账号名',
+        dataIndex: 'name',
+        slotName: 'name',
+        width: 250,
+    },
+    {
+        title: '工作时间',
+        dataIndex: 'time_range',
+        slotName: 'time_range',
+        align: 'right',
+        width: 200,
+    },
+    // {
+    //     title: '当日推广效果',
+    //     children: [
+    //         {
+    //             title: '点击量',
+    //             dataIndex: 'today_clickNum',
+    //             width: 100,
+    //             align: 'right',
+    //             render: (e: any) => numberFormat(e.record.today_clickNum)
+    //         },
+    //         {
+    //             title: '有效订单',
+    //             dataIndex: 'today_orderNum',
+    //             width: 100,
+    //             align: 'right',
+    //             render: (e: any) => numberFormat(e.record.today_orderNum)
+    //         },
+    //         {
+    //             title: '订单金额',
+    //             dataIndex: 'today_cosPrice',
+    //             width: 150,
+    //             align: 'right',
+    //             render: (e: any) => amountFormat(e.record.today_cosPrice)
+    //         },
+    //         {
+    //             title: '预估收入',
+    //             dataIndex: 'today_cosFee',
+    //             width: 150,
+    //             align: 'right',
+    //             render: (e: any) => amountFormat(e.record.today_cosFee)
+    //         },
+
+    //         // 
+
+    //     ]
+    // },
+    {
+        title: '小时调用',
+        slotName: 'hourly_calls_limit',
+        dataIndex: 'current_hourly_calls',
+        align: 'right',
+        width: 120,
+    },
+    {
+        title: '当日调用',
+        slotName: 'daily_calls_limit',
+        dataIndex: 'current_daily_calls',
+        align: 'right',
+        width: 150,
+    },
+    {
+        title: '运行节点',
+        slotName: 'nodeName',
+        width: 120,
+    },
+    {
+        title: '状态',
+        slotName: 'status',
+        width: 100,
+    },
+    {
+        title: '分类',
+        slotName: 'actions',
+        width: 200,
+        align: 'center',
+    },
+    {
+        title: '时间',
+        slotName: 'time',
+        width: 170,
+    },
+]);
+
+const statusOptions = computed<SelectOptionData[]>(() => [
+    {
+        label: '全部',
+        value: '',
+    },
+    {
+        label: '在线',
+        value: 'online',
+    },
+    {
+        label: '下线',
+        value: 'offline',
+    },
+]);
+
+const fetchData = async (
+    params: PddPoolParams = {
+        current: 1,
+        pageSize: 50,
+        sort: 'status',
+        order: 'descending',
+        getTotal: true,
+    }
+) => {
+    setLoading(true);
+    try {
+        const { data } = await queryPddPool(params);
+        if (!data) return;
+        // const { data } = await queryPddPool(params);
+        renderData.value = data.list;
+        pagination.current = data.page;
+        pagination.total = data.count;
+    } catch (err) {
+        console.log(err);
+        // you can report use errorHandler or other
+    } finally {
+        setLoading(false);
+    }
+};
+
+const changeItem = async (data: PddPoolRecord) => {
+    router.push({ name: 'updateCookies' });
+};
+
+const billView = async (data: PddPoolRecord) => {
+    router.push({ name: 'taobao_bill_dailys', query: { name: data.company } });
+};
+
+
+const changeStatus = async (id: number, val: any) => {
+    const args = {
+        id,
+        name: 'status',
+        val
+    } as PddUpdateAccountModel;
+
+    setLoading(true);
+
+    try {
+        const { data } = await PddUpdateAccount(args);
+        console.log(data, data.msg);
+        const msg = data.msg || '更新成功!';
+        if (data.success) {
+            Message.success(msg);
+            fetchData();
+        } else {
+            Message.error(data.msg);
+        }
+
+    } catch (e) { console.log(e) }
+    setLoading(false);
+};
+
+
+const changeAttr = async (id: number, name: string, val: any) => {
+    const args = {
+        id,
+        name,
+        val
+    } as PddUpdateAccountModel;
+
+    setLoading(true);
+    try {
+
+        const { data } = await PddUpdateAccount(args);
+        console.log(data, data.msg);
+        const msg = data.msg || '更新成功!';
+        if (data.success) {
+            Message.success(msg);
+            fetchData();
+        } else {
+            Message.error(data.msg);
+        }
+    } catch (e) { console.log(e) }
+    setLoading(false);
+};
+
+
+
+
+
+const search = () => {
+    fetchData({
+        ...basePagination,
+        ...formModel.value,
+    } as unknown as PddPoolParams);
+};
+const onPageChange = (current: number) => {
+    fetchData({ ...basePagination, current });
+};
+
+fetchData();
+const reset = () => {
+    formModel.value = generateFormModel();
+};
+
+const handleSelectDensity = (
+    val: string | number | Record<string, any> | undefined,
+    e: Event
+) => {
+    size.value = val as SizeProps;
+};
+
+const handleChange = (
+    checked: boolean | (string | boolean | number)[],
+    column: Column,
+    index: number
+) => {
+    if (!checked) {
+        cloneColumns.value = showColumns.value.filter(
+            (item) => item.dataIndex !== column.dataIndex
+        );
+    } else {
+        cloneColumns.value.splice(index, 0, column);
+    }
+};
+
+const exchangeArray = <T extends Array<any>>(
+    array: T,
+    beforeIdx: number,
+    newIdx: number,
+    isDeep = false
+): T => {
+    const newArray = isDeep ? cloneDeep(array) : array;
+    if (beforeIdx > -1 && newIdx > -1) {
+        // 先替换后面的,然后拿到替换的结果替换前面的
+        newArray.splice(
+            beforeIdx,
+            1,
+            newArray.splice(newIdx, 1, newArray[beforeIdx]).pop()
+        );
+    }
+    return newArray;
+};
+
+const popupVisibleChange = (val: boolean) => {
+    if (val) {
+        nextTick(() => {
+            const el = document.getElementById(
+                'tableSetting'
+            ) as HTMLElement;
+            const sortable = new Sortable(el, {
+                onEnd(e: any) {
+                    const { oldIndex, newIndex } = e;
+                    exchangeArray(cloneColumns.value, oldIndex, newIndex);
+                    exchangeArray(showColumns.value, oldIndex, newIndex);
+                },
+            });
+        });
+    }
+};
+
+watch(
+    () => columns.value,
+    (val) => {
+        cloneColumns.value = cloneDeep(val);
+        cloneColumns.value.forEach((item, index) => {
+            item.checked = true;
+        });
+        showColumns.value = cloneDeep(cloneColumns.value);
+    },
+    { deep: true, immediate: true }
+);
+</script>
+
+<script lang="ts">
+export default {
+    name: 'SearchTable',
+};
+</script>
+
+<style scoped lang="less">
+.container {
+    padding: 0 20px 20px 20px;
+}
+
+:deep(.arco-table-th) {
+    &:last-child {
+        .arco-table-th-item-title {
+            margin-left: 16px;
+        }
+    }
+}
+
+.action-icon {
+    margin-left: 12px;
+    cursor: pointer;
+}
+
+.active {
+    color: #0960bd;
+    background-color: #e3f4fc;
+}
+
+.setting {
+    display: flex;
+    align-items: center;
+    width: 200px;
+
+    .title {
+        margin-left: 12px;
+        cursor: pointer;
+    }
+}
+</style>

+ 94 - 0
src/views/pdd/updateCookies.vue

@@ -0,0 +1,94 @@
+<template>
+    <div class="container">
+        <Breadcrumb :items="['menu.pdd', 'menu.pdd.updateCookies']" />
+        <a-card class="general-card" :title="$t('menu.pdd.updateCookies')">
+            <a-row class="wrapper">
+                <a-col :span="24">
+                    <a-form ref="formRef" :model="formData" class="form" :label-col-props="{ span: 4 }"
+                        :wrapper-col-props="{ span: 19 }">
+                        <a-form-item field="cookie" :label="$t('taobao.cookies.label')" :rules="[{ required: true }]"
+                            row-class="keep-margin">
+                            <a-textarea v-model="formData.cookie" auto-size class="cookie"
+                                :placeholder="$t('taobao.cookies.placeholder')" />
+                        </a-form-item>
+                        <a-form-item>
+                            <a-space>
+                                <a-button type="primary" @click="validate">
+                                    {{ $t('form.save') }}
+                                </a-button>
+                                <a-button type="secondary" @click="reset">
+                                    {{ $t('form.reset') }}
+                                </a-button>
+                            </a-space>
+                        </a-form-item>
+                    </a-form>
+                </a-col>
+            </a-row>
+        </a-card>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { Message } from '@arco-design/web-vue';
+import { FormInstance } from '@arco-design/web-vue/es/form';
+import { UpdateCookieModel, updateCookies } from '@/api/pdd';
+
+
+const router = useRouter();
+
+const formRef = ref<FormInstance>();
+const formData = ref<UpdateCookieModel>({
+    cookie: '',
+});
+const validate = async () => {
+    const res = await formRef.value?.validate();
+    if (!res) {
+        try {
+            const { data } = await updateCookies(formData.value);
+            console.log(data, data.msg);
+            const msg = data.msg || '更新成功!';
+            if (data.success) {
+                Message.success(msg);
+                router.push('./list');
+            } else {
+                Message.error(data.msg);
+            }
+        } catch (err) {
+            console.error(err)
+        }
+    }
+};
+const reset = async () => {
+    await formRef.value?.resetFields();
+};
+</script>
+
+<style scoped lang="less">
+.container {
+    padding: 0 20px 20px 20px;
+}
+
+.wrapper {
+    padding: 20px 0 0 20px;
+    min-height: 580px;
+    background-color: var(--color-bg-2);
+    border-radius: 4px;
+}
+
+:deep(.section-title) {
+    margin-top: 0;
+    margin-bottom: 16px;
+    font-size: 14px;
+}
+
+.form {
+    margin: 0 auto;
+}
+
+.form .cookie {
+    height: 100%;
+    min-height: 500px;
+}
+</style>

+ 132 - 87
src/views/settings/config.vue

@@ -9,96 +9,134 @@
                         <a-form ref="formRef" :model="formData" class="form" :label-col-props="{ span: 4 }"
                             :wrapper-col-props="{ span: 19 }">
 
-                            <a-form-item field="ignorePercentage" label="放弃流量" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.ignorePercentage" :min="0" :max="100"
-                                    placeholder="主动放弃流量,0-100,举例:10 = 放弃10%" />
-                            </a-form-item>
-
-                            <a-form-item field="jdIgnorePercentage" label="JD放弃流量" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.jdIgnorePercentage" :min="0" :max="100"
-                                    placeholder="主动放弃流量,0-100,举例:10 = 放弃10%" />
-                            </a-form-item>
-
-                            <a-form-item field="pass_salt" label="pass_salt" :rules="[{ required: true }]">
-                                <a-input v-model="formData.pass_salt" />
-                            </a-form-item>
-
 
-                            <a-form-item field="ignorePercentageCity" label="流量控制-城市" :rules="[{ required: true }]">
-                                <a-input v-model="formData.ignorePercentageCity" />
-                            </a-form-item>
-
-                            <a-form-item field="jdIgnorePercentageCity" label="JD流量控制-城市" :rules="[{ required: true }]">
-                                <a-input v-model="formData.jdIgnorePercentageCity" />
-                            </a-form-item>
-
-                            <a-form-item field="fake_click_min" label="补点击次数" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.fake_click_min" :min="0" /> -
-                                <a-input-number v-model="formData.fake_click_max" :min="0" />
-                            </a-form-item>
+                            <a-tabs default-active-key="1">
+                                <a-tab-pane key="1" title="全局配置">
 
 
-
-                            <a-form-item field="fake_click_min" label="补点击次数" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.fake_click_min" :min="0" /> -
-                                <a-input-number v-model="formData.fake_click_max" :min="0" />
-                            </a-form-item>
-
-
-                            <a-form-item field="jd_limit_per_ip_24h" label="24小时转链次数(JD)" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.jd_limit_per_ip_24h" :min="0"
-                                    placeholder="同ip在24小时内可转链的次数。" />
-                            </a-form-item>
-                            <a-form-item field="tk_limit_per_ip_24h" label="24小时转链次数(TK)" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.tk_limit_per_ip_24h" :min="0"
-                                    placeholder="同ip在24小时内可转链的次数。" />
-                            </a-form-item>
-
-
-
-                            <a-form-item field="rt_max" label="转链超时" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.rt_max" :min="500" placeholder="转链API最长超时时间,单位毫秒" />
-                            </a-form-item>
-
-
-                            <a-form-item field="similar_timeout" label="搜同款超时" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.similar_timeout" :min="1000"
-                                    placeholder="搜同款API最长超时时间,单位毫秒" />
-                            </a-form-item>
-
-
-                            <a-form-item field="tk_whitelist_regular" label="淘口令正则">
-                                <a-textarea v-model="formData.tk_whitelist_regular" auto-size placeholder="淘口令正则" />
-                                <template #extra>
-                                    <a-button type="outline" @click="clickRegularTester">正则测试
-                                    </a-button>
-                                </template>
-                            </a-form-item>
-
-                            <a-form-item field="tk_blacklist_regular" label="淘口令排除正则">
-                                <a-textarea v-model="formData.tk_blacklist_regular" auto-size placeholder="淘口令排除正则" />
-                                <template #extra>
-                                    <a-button type="outline" @click="clickRegularTester">正则测试
-                                    </a-button>
-                                </template>
-                            </a-form-item>
-
-                            <a-form-item field="multi_token_regular" label="混合口令正则">
-                                <a-textarea v-model="formData.multi_token_regular" auto-size placeholder="混合口令正则" />
-                                <template #extra>
-                                    <a-button type="outline" @click="clickRegularTester">正则测试
-                                    </a-button>
-                                </template>
-                            </a-form-item>
-                            <a-divider />
-                            <a-form-item field="cpsIgnorePercentageCity" label="CPS流量控制-城市" :rules="[{ required: true }]">
-                                <a-input v-model="formData.cpsIgnorePercentageCity" />
-                            </a-form-item>
-
-                            <a-form-item field="cps_limit_per_ip_24h" label="24小时转链次数(TK)" :rules="[{ required: true }]">
-                                <a-input-number v-model="formData.cps_limit_per_ip_24h" :min="0"
-                                    placeholder="同ip在24小时内可转链的次数。" />
-                            </a-form-item>
+                                    <a-form-item field="pass_salt" label="pass_salt" :rules="[{ required: true }]">
+                                        <a-input v-model="formData.pass_salt" />
+                                    </a-form-item>
+
+
+                                    <a-form-item field="ignorePercentageCity" label="流量控制-城市">
+                                        <a-input v-model="formData.ignorePercentageCity" />
+                                    </a-form-item>
+
+                                    <a-form-item field="fake_click_min" label="补点击次数" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.fake_click_min" :min="0" /> -
+                                        <a-input-number v-model="formData.fake_click_max" :min="0" />
+                                    </a-form-item>
+
+
+
+                                    <a-form-item field="fake_click_min" label="补点击次数" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.fake_click_min" :min="0" /> -
+                                        <a-input-number v-model="formData.fake_click_max" :min="0" />
+                                    </a-form-item>
+
+                                    <a-form-item field="rt_max" label="转链超时" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.rt_max" :min="500"
+                                            placeholder="转链API最长超时时间,单位毫秒" />
+                                    </a-form-item>
+
+
+                                    <a-form-item field="similar_timeout" label="搜同款超时" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.similar_timeout" :min="1000"
+                                            placeholder="搜同款API最长超时时间,单位毫秒" />
+                                    </a-form-item>
+
+
+                                </a-tab-pane>
+                                <a-tab-pane key="cps" title="CPS">
+
+                                    <a-form-item field="cpsIgnorePercentageCity" label="CPS流量控制-城市">
+                                        <a-input v-model="formData.cpsIgnorePercentageCity" />
+                                    </a-form-item>
+
+                                </a-tab-pane>
+                                <a-tab-pane key="tb" title="淘宝">
+
+
+                                    <a-form-item field="tk_whitelist_regular" label="淘口令正则">
+                                        <a-textarea v-model="formData.tk_whitelist_regular" auto-size
+                                            placeholder="淘口令正则" />
+                                        <template #extra>
+                                            <a-button type="outline" @click="clickRegularTester">正则测试
+                                            </a-button>
+                                        </template>
+                                    </a-form-item>
+
+                                    <a-form-item field="tk_blacklist_regular" label="淘口令排除正则">
+                                        <a-textarea v-model="formData.tk_blacklist_regular" auto-size
+                                            placeholder="淘口令排除正则" />
+                                        <template #extra>
+                                            <a-button type="outline" @click="clickRegularTester">正则测试
+                                            </a-button>
+                                        </template>
+                                    </a-form-item>
+
+                                    <a-form-item field="multi_token_regular" label="混合口令正则">
+                                        <a-textarea v-model="formData.multi_token_regular" auto-size
+                                            placeholder="混合口令正则" />
+                                        <template #extra>
+                                            <a-button type="outline" @click="clickRegularTester">正则测试
+                                            </a-button>
+                                        </template>
+                                    </a-form-item>
+
+                                    <a-form-item field="ignorePercentage" label="放弃流量" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.ignorePercentage" :min="0" :max="100"
+                                            placeholder="主动放弃流量,0-100,举例:10 = 放弃10%" />
+                                    </a-form-item>
+
+
+                                    <a-form-item field="tk_limit_per_ip_24h" label="24小时转链次数(TK)"
+                                        :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.tk_limit_per_ip_24h" :min="0"
+                                            placeholder="同ip在24小时内可转链的次数。" />
+                                    </a-form-item>
+
+
+                                    <a-form-item field="cps_limit_per_ip_24h" label="24小时转链次数(TK)"
+                                        :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.cps_limit_per_ip_24h" :min="0"
+                                            placeholder="同ip在24小时内可转链的次数。" />
+                                    </a-form-item>
+
+                                </a-tab-pane>
+                                <a-tab-pane key="jd" title="京东">
+                                    <a-form-item field="jdIgnorePercentage" label="放弃流量" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.jdIgnorePercentage" :min="0" :max="100"
+                                            placeholder="主动放弃流量,0-100,举例:10 = 放弃10%" />
+                                    </a-form-item>
+                                    <a-form-item field="jdIgnorePercentageCity" label="流量控制-城市">
+                                        <a-input v-model="formData.jdIgnorePercentageCity" />
+                                    </a-form-item>
+                                    <a-form-item field="jd_limit_per_ip_24h" label="24小时转链次数"
+                                        :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.jd_limit_per_ip_24h" :min="0"
+                                            placeholder="同ip在24小时内可转链的次数。" />
+                                    </a-form-item>
+                                </a-tab-pane>
+                                <a-tab-pane key="pdd" title="拼多多">
+                                    <a-form-item field="pddIgnorePercentage" label="放弃流量" :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.pddIgnorePercentage" :min="0" :max="100"
+                                            placeholder="主动放弃流量,0-100,举例:10 = 放弃10%" />
+                                    </a-form-item>
+
+                                    <a-form-item field="pddIgnorePercentageCity" label="流量控制-城市">
+                                        <a-input v-model="formData.pddIgnorePercentageCity" />
+                                    </a-form-item>
+
+                                    <a-form-item field="pdd_limit_per_ip_24h" label="24小时转链次数"
+                                        :rules="[{ required: true }]">
+                                        <a-input-number v-model="formData.pdd_limit_per_ip_24h" :min="0"
+                                            placeholder="同ip在24小时内可转链的次数。" />
+                                    </a-form-item>
+
+                                </a-tab-pane>
+                            </a-tabs>
                             <a-form-item>
                                 <a-space>
                                     <a-button type="primary" @click="validate">
@@ -109,6 +147,8 @@
                                     </a-button>
                                 </a-space>
                             </a-form-item>
+
+
                         </a-form>
                     </a-spin>
                 </a-col>
@@ -165,6 +205,11 @@ const formData = ref<UpdateConfigModel>({
     tk_limit_per_ip_24h: 0,
     cpsIgnorePercentageCity: '',
     cps_limit_per_ip_24h: 0,
+
+    pdd_limit_per_ip_24h: 0,
+    pddIgnorePercentageCity: '',
+    pddIgnorePercentage: 0,
+
 });
 
 const showRegularTester = ref<boolean>(false);

+ 27 - 16
src/views/taobao/components/categories-percent.vue

@@ -1,22 +1,18 @@
 <template>
     <a-spin :loading="loading" style="width: 400px">
         <a-card class="general-card" :header-style="{ paddingBottom: '0' }">
-
             <div>
                 <template v-if="record.accountName !== ''">
                     {{ record.accountName }}
                 </template>
                 API调用记录 -
-                {{
-                    dayjs(record.report_date).format(
-                        record.isLeaf ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD'
-                    )
-                }}
+                {{ dayjs(record.report_date).format(record.isLeaf ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD') }}
             </div>
             <a-radio-group v-model:model-value="showTable" type="button" @change="showTableChange as any"
                 style="margin-bottom:5px">
                 <a-radio value="message"> 响应类型 </a-radio>
                 <a-radio value="reason"> 放弃明细 </a-radio>
+                <a-radio value="deeplink"> deeplink </a-radio>
             </a-radio-group>
             <a-table v-if="showTable === 'message'" size="mini" :data="renderList" :scrollbar="scrollbar"
                 :scroll="scroll" :pagination="false" :bordered="false">
@@ -39,15 +35,33 @@
                     </a-table-column>
                 </template>
             </a-table>
-
             <a-table v-if="showTable === 'reason'" size="mini" :data="renderList2" :scrollbar="scrollbar"
                 :scroll="scroll" :pagination="false" :bordered="false">
                 <template #columns>
                     <a-table-column title="错误原因" data-index="title">
                         <template #cell="{ record }">
-                            <a-typography-paragraph :ellipsis="{
-                                rows: 1,
-                            }">
+                            <a-typography-paragraph :ellipsis="{ rows: 1 }">
+                                {{ record.name }}
+                            </a-typography-paragraph>
+                        </template>
+                    </a-table-column>
+                    <a-table-column title="次数" data-index="value">
+                    </a-table-column>
+                    <a-table-column title="百分比" data-index="increases">
+                        <template #cell="{ record }">
+                            <div class="increases-cell">
+                                <span>{{ record.increases }}%</span>
+                            </div>
+                        </template>
+                    </a-table-column>
+                </template>
+            </a-table>
+            <a-table v-if="showTable === 'deeplink'" size="mini" :data="renderList3" :scrollbar="scrollbar"
+                :scroll="scroll" :pagination="false" :bordered="false">
+                <template #columns>
+                    <a-table-column title="分类" data-index="title">
+                        <template #cell="{ record }">
+                            <a-typography-paragraph :ellipsis="{ rows: 1 }">
                                 {{ record.name }}
                             </a-typography-paragraph>
                         </template>
@@ -71,12 +85,7 @@
 import dayjs from 'dayjs';
 import useLoading from '@/hooks/loading';
 import { defineProps, ref } from 'vue';
-import {
-    TkReportRecord,
-    TkReportParams,
-    queryTkReportChartData,
-    ChartDataResponse,
-} from '@/api/taobao';
+import { DailyLogRecord, ChartDataResponse, ReportParams, queryReportChartData } from '@/api/app';
 
 // 使用 defineProps 来定义并接收 props
 const props = defineProps<{
@@ -96,6 +105,7 @@ const showTable = ref('message');
 const { loading, setLoading } = useLoading(true);
 const renderList = ref<ChartDataResponse[]>();
 const renderList2 = ref<ChartDataResponse[]>();
+const renderList3 = ref<ChartDataResponse[]>();
 
 const fetchData = async (
     params: TkReportParams = {
@@ -109,6 +119,7 @@ const fetchData = async (
         const res = await queryTkReportChartData(params);
         renderList.value = res.data;
         renderList2.value = res.data2;
+        renderList3.value = res.data3;
     } catch (err) {
         console.log(err);
     } finally {