feat(account-manage): 添加表格视图并优化现有组件样式和逻辑
This commit is contained in:
@ -3,7 +3,8 @@
|
||||
* @Date: 2025-06-25 15:31:15
|
||||
-->
|
||||
<template>
|
||||
<div class="card-container">
|
||||
<NoData v-if="!dataSource.length" />
|
||||
<div v-else class="card-container">
|
||||
<Spin
|
||||
v-for="(item, index) in dataSource"
|
||||
:key="index"
|
||||
@ -14,7 +15,12 @@
|
||||
<template #icon>
|
||||
<icon-sync size="24" />
|
||||
</template>
|
||||
<Checkbox :checked="isSelected(item)" :value="item.id" @change="toggleSelect(item)" class="relative top--2px"></Checkbox>
|
||||
<Checkbox
|
||||
:checked="isSelected(item)"
|
||||
:value="item.id"
|
||||
class="relative top--2px"
|
||||
@change="toggleSelect(item)"
|
||||
></Checkbox>
|
||||
<div class="ml-8px flex-1">
|
||||
<Tooltip title="点击查看账号详情">
|
||||
<p class="name cursor-pointer hover:!color-#6d4cfe" @click="goDetail(item)">{{ item.name || '-' }}</p>
|
||||
@ -47,30 +53,30 @@
|
||||
<span class="label">运营人员</span>
|
||||
<span class="cts">{{ item.operator?.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<span class="label">所属项目</span>
|
||||
<span v-if="!item.projects.length" class="cts">-</span>
|
||||
<div v-else class="flex items-center">
|
||||
<Tooltip
|
||||
v-if="item.projects.length > 2"
|
||||
placement="bottom"
|
||||
:title="
|
||||
item.projects
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
.join(',')
|
||||
"
|
||||
>
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<!-- <div class="field-row">-->
|
||||
<!-- <span class="label">所属项目</span>-->
|
||||
<!-- <span v-if="!item.projects.length" class="cts">-</span>-->
|
||||
<!-- <div v-else class="flex items-center">-->
|
||||
<!-- <Tooltip-->
|
||||
<!-- v-if="item.projects.length > 2"-->
|
||||
<!-- placement="bottom"-->
|
||||
<!-- :title="-->
|
||||
<!-- item.projects-->
|
||||
<!-- .slice(2)-->
|
||||
<!-- .map((v) => v.name)-->
|
||||
<!-- .join(',')-->
|
||||
<!-- "-->
|
||||
<!-- >-->
|
||||
<!-- <div class="tag-box">-->
|
||||
<!-- <span class="text">{{ `+${item.projects.length - 2}` }}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </Tooltip>-->
|
||||
|
||||
<div v-for="(project, index) in item.projects.slice(0, 2)" :key="index" class="tag-box">
|
||||
<span class="text">{{ project.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div v-for="(project, index) in item.projects.slice(0, 2)" :key="index" class="tag-box">-->
|
||||
<!-- <span class="text">{{ project.name }}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="field-row">
|
||||
<span class="label">分组</span>
|
||||
<span class="cts">{{ item.group?.name || '-' }}</span>
|
||||
@ -123,14 +129,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
<PauseAccountPatchModal ref="pauseAccountPatchModalRef" @success="emits('update')" />
|
||||
<ReauthorizeAccountModal ref="reauthorizeAccountModalRef" @update="emits('update')" />
|
||||
<AuthorizedAccountModal ref="authorizedAccountModalRef" @update="emits('update')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, computed, inject } from 'vue';
|
||||
import { defineProps, inject } from 'vue';
|
||||
import { Checkbox, Button, Tooltip, Spin } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { deleteSyncStatus } from '@/api/all/propertyMarketing';
|
||||
@ -141,10 +144,7 @@ import {
|
||||
EnumStatus,
|
||||
} from '@/views/property-marketing/media-account/components/status-select/status-box';
|
||||
|
||||
import PauseAccountPatchModal from './pause-account-patch';
|
||||
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
import ReauthorizeAccountModal from '../reauthorize-account-modal';
|
||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||
import FooterBtn from './footer-btn';
|
||||
|
||||
import icon1 from '@/assets/img/platform/icon-dy.png';
|
||||
@ -160,7 +160,7 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedItems: {
|
||||
selectedRows: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
@ -170,28 +170,26 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['openEdit', 'update', 'selectionChange', 'delete', 'updateSyncStatus']);
|
||||
const emits = defineEmits([
|
||||
'openEdit',
|
||||
'update',
|
||||
'delete',
|
||||
'updateSyncStatus',
|
||||
'pause',
|
||||
'reauthorize',
|
||||
'select',
|
||||
'selectAll',
|
||||
]);
|
||||
const syncData = inject('handleSyncData');
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const pauseAccountPatchModalRef = ref(null);
|
||||
const reauthorizeAccountModalRef = ref(null);
|
||||
const authorizedAccountModalRef = ref(null);
|
||||
|
||||
// 判断当前 item 是否被选中
|
||||
const isSelected = (item) => {
|
||||
return props.selectedItems.some((i) => i.id === item.id);
|
||||
return props.selectedRows.some((i) => i.id === item.id);
|
||||
};
|
||||
|
||||
const toggleSelect = (item) => {
|
||||
let newSelected;
|
||||
if (isSelected(item)) {
|
||||
newSelected = props.selectedItems.filter((i) => i.id !== item.id);
|
||||
} else {
|
||||
newSelected = [...props.selectedItems, item];
|
||||
}
|
||||
emits('selectionChange', newSelected);
|
||||
emits('select', item, !isSelected(item));
|
||||
};
|
||||
|
||||
const openEdit = (item) => {
|
||||
@ -203,21 +201,11 @@ const openDelete = (item) => {
|
||||
};
|
||||
|
||||
const handleReauthorize = (item) => {
|
||||
const { id, platform, error_status } = item;
|
||||
const isUnauthorized = isUnauthorizedStatus(error_status);
|
||||
if (isUnauthorized) {
|
||||
authorizedAccountModalRef.value?.open(id, platform);
|
||||
} else {
|
||||
reauthorizeAccountModalRef.value?.open(id, platform);
|
||||
}
|
||||
emits('reauthorize', item);
|
||||
};
|
||||
|
||||
const handlePause = (item) => {
|
||||
pauseAccountPatchModalRef.value?.open(item);
|
||||
};
|
||||
|
||||
const isUnauthorizedStatus = (error_status) => {
|
||||
return [EnumErrorStatus.UNAUTHORIZED].includes(error_status);
|
||||
emits('pause', item);
|
||||
};
|
||||
|
||||
const goDetail = (item) => {
|
||||
@ -269,6 +257,7 @@ const handleConfirm = (item) => {
|
||||
syncData(item);
|
||||
}
|
||||
if (error_status === EnumErrorStatus.LOGIN) {
|
||||
emits('');
|
||||
handleReauthorize(item);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,9 +3,8 @@ import {
|
||||
EnumErrorStatus,
|
||||
getStatusInfo,
|
||||
} from '@/views/property-marketing/media-account/components/status-select/status-box';
|
||||
import { Dropdown, Menu } from 'ant-design-vue';
|
||||
import { Dropdown, Menu, Tooltip, Button } from 'ant-design-vue';
|
||||
const { Item: MenuItem } = Menu;
|
||||
import { Tooltip, Button } from 'ant-design-vue';
|
||||
export default defineComponent({
|
||||
name: 'FooterBtn',
|
||||
props: {
|
||||
@ -44,7 +43,7 @@ export default defineComponent({
|
||||
};
|
||||
const renderUpdateBtn = () => {
|
||||
return (
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('syncData', props.item)}>
|
||||
<Button type="primary" class="!h-24px !px-12px" ghost size="small" onClick={() => emit('syncData', props.item)}>
|
||||
更新数据
|
||||
</Button>
|
||||
);
|
||||
@ -63,7 +62,7 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
<Button type="primary" ghost class="!h-24px !px-12px mr-8px" size="small">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
@ -88,7 +87,7 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
<Button type="primary" ghost class="mr-8px !h-24px !px-12px" size="small">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
@ -100,7 +99,13 @@ export default defineComponent({
|
||||
),
|
||||
}}
|
||||
></Dropdown>
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
size="small"
|
||||
class="!h-24px !px-12px"
|
||||
onClick={() => emit('handleReauthorize', props.item)}
|
||||
>
|
||||
开启同步
|
||||
</Button>
|
||||
</>
|
||||
@ -118,14 +123,20 @@ export default defineComponent({
|
||||
} else if ([EnumErrorStatus.REQUEST, EnumErrorStatus.FREEZE].includes(error_status)) {
|
||||
return (
|
||||
<Tooltip title={statusInfo.value.disabledBtnTooltip}>
|
||||
<Button type="primary" ghost size="small" disabled>
|
||||
<Button type="primary" ghost size="small" disabled class="!h-24px !px-12px">
|
||||
重新授权
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
class="!h-24px !px-12px"
|
||||
size="small"
|
||||
onClick={() => emit('handleReauthorize', props.item)}
|
||||
>
|
||||
{isUnauthorized ? '去授权' : '重新授权'}
|
||||
</Button>
|
||||
);
|
||||
@ -137,7 +148,7 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
<Button type="primary" ghost size="small" class="mr-8px !h-24px !px-12px">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:dataSource="dataSource"
|
||||
:pagination="false"
|
||||
:rowSelection="rowSelection"
|
||||
:scroll="{ x: '100%' }"
|
||||
:showSorterTooltip="false"
|
||||
bordered
|
||||
class="flex-1 manuscript-table w-100%"
|
||||
rowKey="id"
|
||||
>
|
||||
<template #emptyText>
|
||||
<NoData text="暂无文件" />
|
||||
</template>
|
||||
<Column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:align="column.align"
|
||||
:dataIndex="column.dataIndex"
|
||||
:ellipsis="true"
|
||||
:fixed="column.fixed"
|
||||
:minWidth="column.minWidth"
|
||||
:sorter="column.sortable"
|
||||
:width="column.width"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'name'" #customRender="{ record }">
|
||||
<TextOverTips
|
||||
:context="record.name || '-'"
|
||||
:line="1"
|
||||
class="name cursor-pointer hover:!color-#6d4cfe"
|
||||
@click="goDetail(record)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'tags'" #customRender="{ record }">
|
||||
<div v-if="record.tags.length > 0" class="flex flex-wrap gap-4px">
|
||||
<Tag v-for="tag in record.tags" :key="tag.id" class="mr-0 rounded-4px bg-#F2F3F5 px-8px">
|
||||
<Tooltip v-if="tag.name.length > 5" :title="tag.name">
|
||||
<span class="cts !color-#55585F !lh-24px !text-14px"> {{ `${tag.name.slice(0, 5)}...` }} </span>
|
||||
</Tooltip>
|
||||
<span v-else class="cts !color-#55585F !lh-24px !text-14px"> {{ tag.name }} </span>
|
||||
</Tag>
|
||||
</div>
|
||||
<template v-else> -</template>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'status'" #customRender="{ record }">
|
||||
<StatusBox :item="record" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'platform'" #customRender="{ record }">
|
||||
<img :src="record.platform === 0 ? icon2 : icon3" height="16" width="16" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'last_synced_at'" #customRender="{ record }">
|
||||
<span class="cts num">{{ getLastSyncedAt(record) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'last_authorized_at'" #customRender="{ record }">
|
||||
<span class="cts num">{{ formatTime(record.last_authorized_at) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<FooterBtn
|
||||
:item="record"
|
||||
@handlePause="handlePause"
|
||||
@handleReauthorize="handleReauthorize"
|
||||
@openDelete="openDelete"
|
||||
@openEdit="openEdit"
|
||||
@syncData="syncData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #customRender="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</Column>
|
||||
</Table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, inject } from 'vue';
|
||||
import { Tooltip, Table, Tag } from 'ant-design-vue';
|
||||
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
|
||||
const { Column } = Table;
|
||||
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import FooterBtn from './footer-btn';
|
||||
|
||||
// import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||
import icon2 from '@/assets/img/platform/icon-dy.png';
|
||||
import icon3 from '@/assets/img/platform/icon-xhs.png';
|
||||
|
||||
const emits = defineEmits([
|
||||
'openEdit',
|
||||
'update',
|
||||
'selectionChange',
|
||||
'delete',
|
||||
'updateSyncStatus',
|
||||
'pause',
|
||||
'reauthorize',
|
||||
'select',
|
||||
'selectAll',
|
||||
]);
|
||||
const syncData = inject('handleSyncData');
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const props = defineProps({
|
||||
dataSource: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tableColumns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedRowKeys: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
syncMediaAccounts: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isLoadingTaskStatus: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
});
|
||||
|
||||
const tableRef = ref(null);
|
||||
|
||||
const goDetail = (item) => {
|
||||
router.push(`/media-account/detail/${item.id}`);
|
||||
};
|
||||
|
||||
const handlePause = (item) => {
|
||||
emits('pause', item);
|
||||
};
|
||||
const handleReauthorize = (item) => {
|
||||
emits('reauthorize', item);
|
||||
};
|
||||
const openEdit = (item) => {
|
||||
emits('openEdit', item);
|
||||
};
|
||||
const openDelete = (item) => {
|
||||
emits('delete', item);
|
||||
};
|
||||
const formatTime = (time) => {
|
||||
return exactFormatTime(time, 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss');
|
||||
};
|
||||
|
||||
const getSyncMediaAccount = (item) => {
|
||||
return props.syncMediaAccounts.find((v) => v.id === item.id);
|
||||
};
|
||||
const getLastSyncedAt = (item) => {
|
||||
const target = getSyncMediaAccount(item);
|
||||
if (props.isLoadingTaskStatus && target) {
|
||||
if (target?.status !== 0) {
|
||||
return formatTime(target.last_synced_at);
|
||||
}
|
||||
}
|
||||
return formatTime(item.last_synced_at);
|
||||
};
|
||||
|
||||
const rowSelection = {
|
||||
selectedRowKeys: computed(() => props.selectedRowKeys),
|
||||
onSelect: (record, selected) => {
|
||||
emits('select', record, selected);
|
||||
},
|
||||
onSelectAll: (selected) => {
|
||||
emits('selectAll', selected);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -41,3 +41,63 @@ export const SHOW_TYPES = [
|
||||
svgName: 'svg-list',
|
||||
},
|
||||
];
|
||||
|
||||
export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '账号名称',
|
||||
dataIndex: 'name',
|
||||
width: 200,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '数据更新时间',
|
||||
dataIndex: 'last_synced_at',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '最后授权时间',
|
||||
dataIndex: 'last_authorized_at',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '平台',
|
||||
dataIndex: 'platform',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '账号ID',
|
||||
dataIndex: 'account_id',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '手机号码',
|
||||
dataIndex: 'mobile',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '运营人员',
|
||||
dataIndex: 'operator.name',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '分组',
|
||||
dataIndex: 'group.name',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '标签',
|
||||
dataIndex: 'tags',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
},
|
||||
];
|
||||
|
||||
@ -55,12 +55,12 @@
|
||||
:checked="checkedAll"
|
||||
:indeterminate="indeterminate"
|
||||
class="mr-24px"
|
||||
@change="(e) => handleChangeAll(e.target.checked)"
|
||||
@change="(e) => handleSelectAll(e.target.checked)"
|
||||
>
|
||||
全选
|
||||
</Checkbox>
|
||||
|
||||
<template v-if="selectedItems.length">
|
||||
<template v-if="selectedRows.length">
|
||||
<Button :disabled="isDisabledBatchSyncData" class="!h-24px !px-12px" type="text" @click="handleBatchSyncData">
|
||||
批量更新数据
|
||||
</Button>
|
||||
@ -81,21 +81,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-wrap">
|
||||
<template v-if="showType === 'card'">
|
||||
<AccountTable
|
||||
v-if="dataSource.length > 0"
|
||||
<component
|
||||
:is="showType === 'card' ? Card : Table"
|
||||
:dataSource="dataSource"
|
||||
:isLoadingTaskStatus="isLoadingTaskStatus"
|
||||
:selectedItems="selectedItems"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
:selectedRows="selectedRows"
|
||||
:syncMediaAccounts="syncMediaAccounts"
|
||||
:tableColumns="TABLE_COLUMNS"
|
||||
@delete="handleDelete"
|
||||
@openEdit="handleOpenEdit"
|
||||
@selectionChange="handleSelectionChange"
|
||||
@pause="handlePause"
|
||||
@reauthorize="handleReauthorize"
|
||||
@select="handleSelect"
|
||||
@selectAll="handleSelectAll"
|
||||
@update="getData"
|
||||
@updateSyncStatus="handleUpdateSyncStatus"
|
||||
/>
|
||||
<NoData v-else />
|
||||
</template>
|
||||
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row">
|
||||
<Pagination
|
||||
@ -105,7 +108,7 @@
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:pageSize="pageInfo.pageSize"
|
||||
:pageSize="pageInfo.page_size"
|
||||
:pageSizeOptions="['8', '16', '20', '32', '64']"
|
||||
@change="onPageChange"
|
||||
/>
|
||||
@ -119,6 +122,10 @@
|
||||
<DeleteAccountModal ref="deleteAccountRef" @update="getData" @batchUpdate="onBatchSuccess" />
|
||||
<BatchTagModal ref="batchTagModalRef" @update="onBatchSuccess" />
|
||||
<BatchGroupModal ref="batchGroupModalRef" @update="onBatchSuccess" />
|
||||
|
||||
<PauseAccountPatchModal ref="pauseAccountPatchModalRef" @success="getData" />
|
||||
<ReauthorizeAccountModal ref="reauthorizeAccountModalRef" @update="getData" />
|
||||
<AuthorizedAccountModal ref="authorizedAccountModalRef" @update="getData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -127,7 +134,12 @@ import { ref, provide } from 'vue';
|
||||
import { Checkbox, Button, Pagination, notification, RadioButton, RadioGroup } from 'ant-design-vue';
|
||||
|
||||
import FilterBlock from './components/filter-block';
|
||||
import AccountTable from './components/account-table/card.vue';
|
||||
import Card from './components/account-table/card.vue';
|
||||
import Table from './components/account-table/table.vue';
|
||||
import PauseAccountPatchModal from './components/account-table/pause-account-patch.vue';
|
||||
import AuthorizedAccountModal from './components/authorized-account-modal';
|
||||
import ReauthorizeAccountModal from './components/reauthorize-account-modal';
|
||||
|
||||
import GroupManageModal from './components/group-manage-modal';
|
||||
import TagsManageModal from './components/tags-manage-modal';
|
||||
import AddAccountModal from './components/add-account-modal';
|
||||
@ -135,10 +147,14 @@ 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, SHOW_TYPES } from './constants';
|
||||
import { INITIAL_QUERY, SHOW_TYPES, TABLE_COLUMNS } from './constants';
|
||||
import { showImportResultNotification } from '@/utils/notification';
|
||||
import { getTaskStatus } from '@/api/all/common';
|
||||
import { EnumStatus } from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
import {
|
||||
EnumErrorStatus,
|
||||
EnumStatus,
|
||||
} from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
import {
|
||||
getMediaAccounts,
|
||||
getMediaAccountsHealth,
|
||||
@ -156,6 +172,21 @@ import icon5 from '@/assets/img/media-account/icon-warn.png';
|
||||
let syncDataTimer = null;
|
||||
let queryTaskTimer = null;
|
||||
|
||||
const {
|
||||
selectedRowKeys,
|
||||
selectedRows,
|
||||
dataSource,
|
||||
pageInfo,
|
||||
DEFAULT_PAGE_INFO,
|
||||
onPageChange,
|
||||
handleSelect,
|
||||
handleSelectAll,
|
||||
} = useTableSelectionWithPagination({
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
|
||||
const groupManageModalRef = ref(null);
|
||||
const tagsManageModalRef = ref(null);
|
||||
const addAccountModalRef = ref(null);
|
||||
@ -163,10 +194,12 @@ const deleteAccountRef = ref(null);
|
||||
const batchTagModalRef = ref(null);
|
||||
const batchGroupModalRef = ref(null);
|
||||
const filterBlockRef = ref(null);
|
||||
const pauseAccountPatchModalRef = ref(null);
|
||||
const reauthorizeAccountModalRef = ref(null);
|
||||
const authorizedAccountModalRef = ref(null);
|
||||
|
||||
const pageInfo = ref(cloneDeep(INITIAL_PAGE_INFO));
|
||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||
const dataSource = ref([]);
|
||||
// const dataSource = ref([]);
|
||||
const selectedItems = ref([]);
|
||||
const healthData = ref({});
|
||||
const syncMediaAccounts = ref([]);
|
||||
@ -174,13 +207,11 @@ const isLoadingTaskStatus = ref(false); // 正在查询状态中
|
||||
const showType = ref('card');
|
||||
|
||||
const hasAbNormalStatus = computed(() => healthData.value?.abnormal_number > 0);
|
||||
const isDisabledBatchSyncData = computed(() => selectedItems.value.some((item) => item.status !== EnumStatus.NORMAL));
|
||||
const isDisabledBatchSyncData = computed(() => selectedRows.value.some((item) => item.status !== EnumStatus.NORMAL));
|
||||
|
||||
const checkedAll = computed(
|
||||
() => dataSource.value.length > 0 && selectedItems.value.length === dataSource.value.length,
|
||||
);
|
||||
const checkedAll = computed(() => dataSource.value.length > 0 && selectedRows.value.length === dataSource.value.length);
|
||||
const indeterminate = computed(
|
||||
() => selectedItems.value.length > 0 && selectedItems.value.length < dataSource.value.length,
|
||||
() => selectedRows.value.length > 0 && selectedRows.value.length < dataSource.value.length,
|
||||
);
|
||||
|
||||
const tipLabel = computed(() => {
|
||||
@ -223,10 +254,10 @@ const getHealthData = async () => {
|
||||
}
|
||||
};
|
||||
const getAccountData = async () => {
|
||||
const { page, pageSize } = pageInfo.value;
|
||||
const { page, page_size } = pageInfo.value;
|
||||
const { code, data } = await getMediaAccounts({
|
||||
page,
|
||||
page_size: pageSize,
|
||||
page_size,
|
||||
...query.value,
|
||||
});
|
||||
if (code === 200) {
|
||||
@ -242,23 +273,13 @@ const handleSearch = () => {
|
||||
reload();
|
||||
};
|
||||
const handleReset = () => {
|
||||
pageInfo.value = cloneDeep(INITIAL_PAGE_INFO);
|
||||
selectedItems.value = [];
|
||||
pageInfo.value = cloneDeep(DEFAULT_PAGE_INFO);
|
||||
selectedRows.value = [];
|
||||
selectedRowKeys.value = [];
|
||||
query.value = cloneDeep(INITIAL_QUERY);
|
||||
reload();
|
||||
};
|
||||
|
||||
const onPageChange = (current, pageSize) => {
|
||||
pageInfo.value.page = current;
|
||||
pageInfo.value.pageSize = pageSize;
|
||||
|
||||
getData();
|
||||
};
|
||||
const onPageSizeChange = (pageSize) => {
|
||||
pageInfo.value.pageSize = pageSize;
|
||||
reload();
|
||||
};
|
||||
|
||||
const handleOpenGroupModal = () => {
|
||||
groupManageModalRef.value?.open();
|
||||
};
|
||||
@ -273,15 +294,9 @@ const handleOpenEdit = (item) => {
|
||||
addAccountModalRef.value?.open(item.id);
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
selectedItems.value = val;
|
||||
};
|
||||
const handleChangeAll = (checked) => {
|
||||
selectedItems.value = checked ? cloneDeep(dataSource.value) : [];
|
||||
};
|
||||
const handleBatchDelete = () => {
|
||||
const ids = selectedItems.value.map((item) => item.id);
|
||||
const names = selectedItems.value.map((item) => `"${item.name || '-'}"`).join(',');
|
||||
const ids = selectedRows.value.map((item) => item.id);
|
||||
const names = selectedRows.value.map((item) => `"${item.name || '-'}"`).join(',');
|
||||
deleteAccountRef.value?.open({ id: ids, name: names });
|
||||
};
|
||||
const handleDelete = (item) => {
|
||||
@ -330,14 +345,14 @@ const handleSyncData = async (item) => {
|
||||
};
|
||||
|
||||
const handleBatchTag = () => {
|
||||
batchTagModalRef.value?.open(selectedItems.value);
|
||||
batchTagModalRef.value?.open(selectedRows.value);
|
||||
};
|
||||
const handleBatchSyncData = async () => {
|
||||
if (isDisabledBatchSyncData.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ids = selectedItems.value.map((item) => item.id);
|
||||
const ids = selectedRows.value.map((item) => item.id);
|
||||
const { code } = await postBatchSyncMediaAccountData({ ids });
|
||||
if (code === 200) {
|
||||
if (!isLoadingTaskStatus.value) {
|
||||
@ -346,10 +361,11 @@ const handleBatchSyncData = async () => {
|
||||
}
|
||||
};
|
||||
const handleBatchGroup = () => {
|
||||
batchGroupModalRef.value?.open(selectedItems.value);
|
||||
batchGroupModalRef.value?.open(selectedRows.value);
|
||||
};
|
||||
const onBatchSuccess = () => {
|
||||
selectedItems.value = [];
|
||||
selectedRowKeys.value = [];
|
||||
selectedRows.value = [];
|
||||
getData();
|
||||
};
|
||||
const handleOpenAbnormalAccount = () => {
|
||||
@ -357,6 +373,23 @@ const handleOpenAbnormalAccount = () => {
|
||||
reload();
|
||||
};
|
||||
|
||||
const isUnauthorizedStatus = (error_status) => {
|
||||
return [EnumErrorStatus.UNAUTHORIZED].includes(error_status);
|
||||
};
|
||||
|
||||
const handlePause = (item) => {
|
||||
pauseAccountPatchModalRef.value?.open(item);
|
||||
};
|
||||
const handleReauthorize = (item) => {
|
||||
const { id, platform, error_status } = item;
|
||||
const isUnauthorized = isUnauthorizedStatus(error_status);
|
||||
if (isUnauthorized) {
|
||||
authorizedAccountModalRef.value?.open(id, platform);
|
||||
} else {
|
||||
reauthorizeAccountModalRef.value?.open(id, platform);
|
||||
}
|
||||
};
|
||||
|
||||
// 查询导入账号任务状态
|
||||
const getSyncTaskStatus = async (id, notificationId) => {
|
||||
const { code, data } = await getTaskStatus(id);
|
||||
|
||||
Reference in New Issue
Block a user