feat(account-manage): 新增账号管理页面布局和功能

This commit is contained in:
rd
2025-09-19 15:20:17 +08:00
parent 7af09d77e1
commit d8f2173eef
5 changed files with 138 additions and 87 deletions

View File

@ -28,3 +28,16 @@ export const PLATFORM_LIST = [
value: 1,
},
];
export const SHOW_TYPES = [
{
label: '卡片',
value: 'card',
svgName: 'svg-card',
},
{
label: '列表',
value: 'list',
svgName: 'svg-list',
},
];

View File

@ -4,7 +4,7 @@
-->
<template>
<div class="account-manage-wrap">
<div class="filter-wrap bg-#fff rounded-8px">
<div class="filter-wrap mb-16px bg-#fff rounded-8px">
<div class="top flex h-64px px-24px py-10px justify-between items-center">
<p class="text-18px font-400 lh-26px color-#211F24 title">账号管理</p>
<div class="flex items-center">
@ -31,65 +31,71 @@
<FilterBlock ref="filterBlockRef" v-model:query="query" @onSearch="handleSearch" @onReset="handleReset" />
</div>
<!--存在异常账号-->
<div
v-if="dataSource.length > 0"
class="tip-row flex justify-between items-center px-16px py-10px w-100% my-12px h-48px"
:class="selectedItems.length > 0 ? 'selected' : isAbNormalStatus ? 'abnormal' : 'normal'"
v-if="hasAbNormalStatus"
class="tip-row flex justify-between items-center px-16px w-100% h-42px mb-16px abnormal"
>
<div class="flex items-center">
<div class="flex items-center">
<template v-if="selectedItems.length > 0">
<Checkbox
:checked="checkedAll"
:indeterminate="indeterminate"
class="mr-8px"
@change="(e) => handleChangeAll(e.target.checked)"
/>
<span class="label mr-24px">
已选
<span class="color-#6D4CFE">{{ selectedItems.length }}</span>
个账号
</span>
<span class="operation-btn" :class="{ disabled: isDisabledBatchSyncData }" @click="handleBatchSyncData"
>批量更新数据</span
>
<span class="operation-btn" @click="handleBatchTag">批量标签</span>
<span class="operation-btn" @click="handleBatchGroup">批量分组</span>
<span class="operation-btn red" @click="handleBatchDelete"> 批量删除 </span>
</template>
<template v-else>
<img :src="isAbNormalStatus ? icon5 : icon4" width="16" height="16" class="mr-8px" />
<span class="label"> {{ tipLabel }} </span>
</template>
<img :src="icon5" class="mr-8px" height="16" width="16" />
<span class="label"> {{ tipLabel }} </span>
</div>
</div>
<template v-if="selectedItems.length > 0">
<img :src="icon6" width="16" height="16" class="cursor-pointer" @click="handleCloseTip" />
</template>
<div v-else>
<Space v-if="isAbNormalStatus" class="flex items-center">
<Button type="primary" danger size="small" @click="handleOpenAbnormalAccount">
<template #default>查看异常账号</template>
<Button class="!h-24px !px-12px" danger size="small" type="primary" @click="handleOpenAbnormalAccount">
<template #default>查看异常账号</template>
</Button>
</div>
<!--操作行-->
<div class="tip-row flex justify-between items-center px-16px py-10px w-100% h-44px mb-16px">
<div class="flex items-center">
<Checkbox
:checked="checkedAll"
:indeterminate="indeterminate"
class="mr-24px"
@change="(e) => handleChangeAll(e.target.checked)"
>
全选
</Checkbox>
<template v-if="selectedItems.length">
<Button :disabled="isDisabledBatchSyncData" class="!h-24px !px-12px" type="text" @click="handleBatchSyncData">
批量更新数据
</Button>
</Space>
<Button class="!h-24px !px-12px" type="text" @click="handleBatchTag"> 批量标签</Button>
<Button class="!h-24px !px-12px" type="text" @click="handleBatchGroup"> 批量分组</Button>
<Button class="!h-24px !px-12px" danger type="text" @click="handleBatchDelete"> 批量删除</Button>
</template>
</div>
<div class="flex items-center">
<RadioGroup v-model:value="showType">
<RadioButton v-for="(item, index) in SHOW_TYPES" :key="index" :value="item.value">
<div class="flex items-center">
<SvgIcon :name="item.svgName" class="mr-4px" size="16" />
<span>{{ item.label }}</span>
</div>
</RadioButton>
</RadioGroup>
</div>
</div>
<div class="card-wrap">
<AccountTable
v-if="dataSource.length > 0"
:syncMediaAccounts="syncMediaAccounts"
:isLoadingTaskStatus="isLoadingTaskStatus"
:dataSource="dataSource"
:selectedItems="selectedItems"
@selectionChange="handleSelectionChange"
@delete="handleDelete"
@openEdit="handleOpenEdit"
@update="getData"
@updateSyncStatus="handleUpdateSyncStatus"
/>
<NoData v-else />
<template v-if="showType === 'card'">
<AccountTable
v-if="dataSource.length > 0"
:dataSource="dataSource"
:isLoadingTaskStatus="isLoadingTaskStatus"
:selectedItems="selectedItems"
:syncMediaAccounts="syncMediaAccounts"
@delete="handleDelete"
@openEdit="handleOpenEdit"
@selectionChange="handleSelectionChange"
@update="getData"
@updateSyncStatus="handleUpdateSyncStatus"
/>
<NoData v-else />
</template>
<div v-if="pageInfo.total > 0" class="pagination-row">
<Pagination
@ -118,10 +124,10 @@
<script setup>
import { ref, provide } from 'vue';
import { Checkbox, Button, Space, Pagination, notification } from 'ant-design-vue';
import { Checkbox, Button, Pagination, notification, RadioButton, RadioGroup } from 'ant-design-vue';
import FilterBlock from './components/filter-block';
import AccountTable from './components/account-table';
import AccountTable from './components/account-table/card.vue';
import GroupManageModal from './components/group-manage-modal';
import TagsManageModal from './components/tags-manage-modal';
import AddAccountModal from './components/add-account-modal';
@ -129,7 +135,7 @@ import DeleteAccountModal from './components/account-table/delete-account';
import BatchTagModal from './components/batch-tag-modal';
import BatchGroupModal from './components/batch-group-modal';
import { INITIAL_QUERY, INITIAL_PAGE_INFO } from './constants';
import { INITIAL_QUERY, INITIAL_PAGE_INFO, SHOW_TYPES } from './constants';
import { showImportResultNotification } from '@/utils/arcoD';
import { getTaskStatus } from '@/api/all/common';
import { EnumStatus } from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
@ -143,9 +149,9 @@ import {
import icon2 from '@/assets/img/media-account/icon-group.png';
import icon3 from '@/assets/img/media-account/icon-tag.png';
import icon4 from '@/assets/img/media-account/icon-success.png';
// import icon4 from '@/assets/img/media-account/icon-success.png';
import icon5 from '@/assets/img/media-account/icon-warn.png';
import icon6 from '@/assets/img/media-account/icon-close.png';
// import icon6 from '@/assets/img/media-account/icon-close.png';
let syncDataTimer = null;
let queryTaskTimer = null;
@ -165,17 +171,20 @@ const selectedItems = ref([]);
const healthData = ref({});
const syncMediaAccounts = ref([]);
const isLoadingTaskStatus = ref(false); // 正在查询状态中
const showType = ref('card');
const isAbNormalStatus = computed(() => healthData.value?.abnormal_number > 0);
const hasAbNormalStatus = computed(() => healthData.value?.abnormal_number > 0);
const isDisabledBatchSyncData = computed(() => selectedItems.value.some((item) => item.status !== EnumStatus.NORMAL));
const checkedAll = computed(() => selectedItems.value.length === dataSource.value.length);
const checkedAll = computed(
() => dataSource.value.length > 0 && selectedItems.value.length === dataSource.value.length,
);
const indeterminate = computed(
() => selectedItems.value.length > 0 && selectedItems.value.length < dataSource.value.length,
);
const tipLabel = computed(() => {
if (!isAbNormalStatus.value) {
if (!hasAbNormalStatus.value) {
return '太棒啦!所有账号都在正常运行。';
}
@ -279,9 +288,7 @@ const handleDelete = (item) => {
const { id, name } = item;
deleteAccountRef.value?.open({ id, name: `"${name || '-'}"` });
};
const handleCloseTip = () => {
selectedItems.value = [];
};
// 先立即执行一次
const getAsyncStatus = async () => {
const { code, data } = await getMediaAccountSyncStatus();

View File

@ -17,46 +17,52 @@
}
.tip-row {
border-radius: 2px;
background: #f0edff;
background: #fff;
.label {
font-family: $font-family-medium;
font-family: $font-family-regular;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
}
&.normal {
background: #ebf7f2;
.label {
color: #211f24;
}
}
&.abnormal {
background: #ffe7e4;
background: #FFE9E7;
.label {
color: #211f24;
}
}
.operation-btn {
padding: 0;
cursor: pointer;
color: var(--Brand-Brand-6, #6d4cfe);
font-family: $font-family-regular;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px; /* 157.143% */
&:not(:last-child) {
margin-right: 16px;
}
&.red {
color: #f64b31;
}
&.disabled {
color: #c5b7ff;
cursor: not-allowed;
:deep(.ant-checkbox) {
+ span {
font-family: $font-family-medium;
}
}
:deep(.ant-radio-group) {
.ant-radio-button-wrapper {
color: #737478;
&:first-child {
border-radius: 4px 0 0 4px;
}
&:last-child {
border-radius: 0 4px 4px 0;
}
&:hover {
color: #6D4CFE;
border-color: #6D4CFE;
}
&-checked {
border-color: #6D4CFE;
background: #F0EDFF;
color: #6D4CFE;
}
}
}
}
.card-wrap {
display: flex;