Merge remote-tracking branch 'origin/main' into feature/0724_新媒体账号状态重构
# Conflicts: # src/views/property-marketing/media-account/account-manage/components/account-table/index.vue # src/views/property-marketing/put-account/account-data/components/filter-block/index.vue # src/views/property-marketing/put-account/account-manage/components/account-table/index.vue # src/views/property-marketing/put-account/account-manage/components/filter-block/index.vue
This commit is contained in:
@ -14,6 +14,10 @@ export const updateCustomColumns = (params = {}) => {
|
||||
return Http.put('/v1/custom-columns', params);
|
||||
};
|
||||
|
||||
export const getUserList = (params = {}) => {
|
||||
return Http.get('/v1/users/list', params);
|
||||
};
|
||||
|
||||
// 任务中心-分页
|
||||
export const getTask = (params = {}) => {
|
||||
return Http.get('/v1/tasks', params);
|
||||
|
||||
@ -24,6 +24,11 @@ export const getMediaAccounts = (params = {}) => {
|
||||
return Http.get('/v1/media-accounts', params);
|
||||
};
|
||||
|
||||
// 媒体账号-列表
|
||||
export const getMediaAccountList = (params = {}) => {
|
||||
return Http.get('/v1/media-accounts/list', params);
|
||||
};
|
||||
|
||||
// 媒体账号-健康情况
|
||||
export const getMediaAccountsHealth = (params = {}) => {
|
||||
return Http.get('/v1/media-accounts/health', params);
|
||||
@ -361,3 +366,39 @@ export const getMediaAccountSyncStatus = (params = {}) => {
|
||||
export const deleteSyncStatus = (id: string) => {
|
||||
return Http.delete(`/v1/media-accounts/${id}/sync-status`);
|
||||
};
|
||||
|
||||
// 内容稿件-列表
|
||||
export const getWorksList = (params = {}) => {
|
||||
return Http.get('/v1/works/list', params);
|
||||
};
|
||||
|
||||
// 项目管理-分页
|
||||
export const getProjects = (params = {}) => {
|
||||
return Http.get('/v1/projects', params);
|
||||
};
|
||||
|
||||
// 项目管理-列表
|
||||
export const getProjectList = () => {
|
||||
return Http.get('/v1/projects/list');
|
||||
};
|
||||
|
||||
// 项目管理-删除
|
||||
export const deleteProject = (id: string) => {
|
||||
return Http.delete(`/v1/projects/${id}`);
|
||||
};
|
||||
|
||||
// 项目管理-添加
|
||||
export const postAddProject = (params: {}) => {
|
||||
return Http.post('/v1/projects', params);
|
||||
};
|
||||
|
||||
// 项目管理-修改
|
||||
export const putProject = (params = {}) => {
|
||||
const { id, ...rest } = params as { id: string; [key: string]: any };
|
||||
return Http.put(`/v1/projects/${id}`, rest);
|
||||
};
|
||||
|
||||
// 项目管理-详情
|
||||
export const getProjectDetail = (id: string) => {
|
||||
return Http.get(`/v1/projects/${id}`);
|
||||
};
|
||||
|
||||
3
src/assets/svg/svg-projectManagement.svg
Normal file
3
src/assets/svg/svg-projectManagement.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M5.25065 1.3125C5.4638 1.31254 5.67398 1.36363 5.86328 1.46159L7.86328 2.49674C8.05258 2.5947 8.26278 2.64579 8.47591 2.64583L13.3822 2.64583C14.1185 2.64583 14.7155 3.24282 14.7155 3.97917L14.7155 13.3542C14.7155 14.0905 14.1185 14.6875 13.3822 14.6875L2.61784 14.6875C1.88146 14.6875 1.28451 14.0905 1.28451 13.3542L1.28451 2.64583C1.28455 1.90949 1.88149 1.3125 2.61784 1.3125L5.25065 1.3125ZM4.528 9.99023C4.14147 9.9903 3.82815 10.3036 3.82813 10.6901C3.82813 11.0767 4.14146 11.3899 4.528 11.39C4.91459 11.39 5.22787 11.0767 5.22787 10.6901C5.22784 10.3035 4.91458 9.99023 4.528 9.99023ZM7.153 10.0905C6.82179 10.0907 6.55342 10.3589 6.55339 10.6901C6.55339 11.0214 6.82177 11.2902 7.153 11.2904L11.5384 11.2904C11.8698 11.2904 12.1387 11.0215 12.1387 10.6901C12.1386 10.3588 11.8698 10.0905 11.5384 10.0905L7.153 10.0905ZM4.528 6.50846C4.14155 6.50853 3.82828 6.82191 3.82813 7.20833C3.82813 7.59489 4.14146 7.90878 4.528 7.90885C4.91459 7.90885 5.22787 7.59493 5.22787 7.20833C5.22771 6.82187 4.9145 6.50846 4.528 6.50846ZM7.153 6.60872C6.82187 6.60889 6.55355 6.87721 6.55339 7.20833C6.55339 7.5396 6.82177 7.80843 7.153 7.80859H11.5384C11.8698 7.80859 12.1387 7.5397 12.1387 7.20833C12.1385 6.8771 11.8697 6.60872 11.5384 6.60872H7.153Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<p class="m-0 p-0 mb-24px s2 ml-32px">退出登录后,你将无法收到该账号的通知</p>
|
||||
<div class="flex items-center justify-end">
|
||||
<a-button class="cancel-btn" size="medium" @click="onClose">返回</a-button>
|
||||
<a-button class="!rounded-4px" size="medium" @click="onClose">返回</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="medium" @click="onLogout"
|
||||
>退出登录</a-button
|
||||
>
|
||||
@ -83,15 +83,12 @@ defineExpose({ open });
|
||||
}
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
.danger-btn {
|
||||
border-radius: 4px;
|
||||
background: var(--Functional-Danger-6, #f64b31) !important;
|
||||
border: none !important;
|
||||
&:hover {
|
||||
background: var(--Functional-Danger-6, #f64b31) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<a-menu-item v-for="item in menuList" :key="String(item.id)">
|
||||
<template v-if="item.children">
|
||||
<a-dropdown :popup-max-height="false" class="layout-menu-item-dropdown">
|
||||
<a-button>
|
||||
<a-button type="text">
|
||||
<span class="menu-item-text mr-2px"> {{ item.name }}</span>
|
||||
<icon-caret-down size="16" class="arco-icon-down !mr-0" />
|
||||
</a-button>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<span>确认删除 {{ accountName }} 这条记录吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px !bg-#f64b31 !border-none" status="danger" size="large" @click="onDelete"
|
||||
>确定</a-button
|
||||
>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<span>确认删除 {{ accountName }} 这条记录吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px !bg-#f64b31 !border-none" status="danger" size="large" @click="onDelete"
|
||||
>确定</a-button
|
||||
>
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
-->
|
||||
<template>
|
||||
<a-select
|
||||
v-model="selectedTags"
|
||||
v-model="selectedValues"
|
||||
:multiple="multiple"
|
||||
size="medium"
|
||||
:placeholder="placeholder"
|
||||
allow-clear
|
||||
:max-tag-count="3"
|
||||
:max-tag-count="maxTagCount"
|
||||
@change="handleChange"
|
||||
>
|
||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
||||
@ -38,28 +38,30 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
maxTagCount: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const selectedTags = ref(props.multiple ? [] : '');
|
||||
const selectedValues = ref(props.multiple ? [] : '');
|
||||
|
||||
// 监听外部传入的值变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
selectedTags.value = newVal;
|
||||
selectedValues.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 监听内部值变化,向外部发送更新
|
||||
watch(selectedTags, (newVal) => {
|
||||
watch(selectedValues, (newVal) => {
|
||||
emits('update:modelValue', newVal);
|
||||
});
|
||||
|
||||
const handleChange = (value) => {
|
||||
selectedTags.value = value;
|
||||
selectedValues.value = value;
|
||||
emits('change', value);
|
||||
};
|
||||
</script>
|
||||
@ -65,7 +65,7 @@
|
||||
|
||||
<template #footer>
|
||||
<div style="text-align: right">
|
||||
<a-button class="mr-8px cancel-btn" size="medium" @click="close">取消</a-button>
|
||||
<a-button class="mr-8px" size="medium" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="medium" @click="onSubmit">确定</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -87,13 +87,6 @@
|
||||
}
|
||||
}
|
||||
.arco-modal-footer {
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import { ref, onMounted } from 'vue';
|
||||
import { getQueryParam } from '@/utils/helper';
|
||||
|
||||
import { getEnterpriseByInviteCode, joinEnterpriseByInviteCode } from '@/api/all';
|
||||
|
||||
const enterprise = ref();
|
||||
const inviteCode = ref();
|
||||
|
||||
@ -27,8 +28,11 @@ async function handleJoin() {
|
||||
await joinEnterpriseByInviteCode(inviteCode.value);
|
||||
AMessage.success('加入成功');
|
||||
}
|
||||
onMounted(() => {
|
||||
getEnterprise();
|
||||
// onMounted(() => {
|
||||
// getEnterprise();
|
||||
// });
|
||||
defineExpose({
|
||||
getEnterprise,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
@ -1,20 +1,15 @@
|
||||
<template>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="svg-icon"
|
||||
:width="props.size"
|
||||
:height="props.size"
|
||||
>
|
||||
<svg aria-hidden="true" class="svg-icon" :width="props.size" :height="props.size">
|
||||
<use :xlink:href="symbolId" :fill="props.color" />
|
||||
</svg>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
const props = defineProps({
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
const props = defineProps({
|
||||
prefix: {
|
||||
type: String,
|
||||
default: "icon",
|
||||
default: 'icon',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
@ -22,14 +17,13 @@
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "#333",
|
||||
default: '#333',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: "12",
|
||||
default: '12',
|
||||
},
|
||||
});
|
||||
|
||||
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
|
||||
</script>
|
||||
});
|
||||
|
||||
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
|
||||
</script>
|
||||
|
||||
@ -9,6 +9,7 @@ interface UseTableSelectionWithPaginationOptions {
|
||||
};
|
||||
onPageChange?: (page: number) => void;
|
||||
onPageSizeChange?: (size: number) => void;
|
||||
onSelectChange?: () => void;
|
||||
}
|
||||
|
||||
const DEFAULT_PAGE_INFO = {
|
||||
@ -39,6 +40,7 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa
|
||||
} else {
|
||||
selectedRows.value = selectedRows.value.filter((v) => v[rowKey] !== record[rowKey]);
|
||||
}
|
||||
options.onSelectChange?.();
|
||||
};
|
||||
|
||||
// 全选/取消全选
|
||||
@ -56,6 +58,7 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((key) => !currentPageKeys.includes(key));
|
||||
selectedRows.value = selectedRows.value.filter((row) => !currentPageKeys.includes(row[rowKey]));
|
||||
}
|
||||
options.onSelectChange?.();
|
||||
};
|
||||
|
||||
const onPageChange = (page: number) => {
|
||||
@ -67,6 +70,9 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa
|
||||
pageInfo.value.page = 1;
|
||||
options.onPageSizeChange?.(size);
|
||||
};
|
||||
const resetPageInfo = () => {
|
||||
pageInfo.value = cloneDeep(DEFAULT_PAGE_INFO)
|
||||
}
|
||||
|
||||
const rowSelection = computed(() => ({
|
||||
type: 'checkbox',
|
||||
@ -84,6 +90,7 @@ export function useTableSelectionWithPagination(options: UseTableSelectionWithPa
|
||||
rowSelection,
|
||||
handleSelect,
|
||||
handleSelectAll,
|
||||
resetPageInfo,
|
||||
DEFAULT_PAGE_INFO,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
<script setup>
|
||||
import { useAppStore } from '@/stores';
|
||||
import { useResponsive } from '@/hooks';
|
||||
import JoinModal from '@/components/join-modal.vue';
|
||||
import { getQueryParam } from '@/utils/helper';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const joinEnterpriseVisible = ref(false);
|
||||
const joinModalRef = ref(null);
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
@ -36,14 +40,15 @@ const paddingStyle = computed(() => {
|
||||
onMounted(() => {
|
||||
checkHasInviteCode();
|
||||
});
|
||||
const setCollapsed = (val: boolean) => {
|
||||
const setCollapsed = (val) => {
|
||||
appStore.updateSettings({ menuCollapse: val });
|
||||
};
|
||||
|
||||
const checkHasInviteCode = () => {
|
||||
const inviteCode = getQueryParam('invite_code');
|
||||
if (inviteCode) {
|
||||
if (userStore.isLogin && inviteCode) {
|
||||
joinEnterpriseVisible.value = true;
|
||||
joinModalRef.value?.getEnterprise?.();
|
||||
}
|
||||
};
|
||||
const drawerVisible = ref(false);
|
||||
@ -57,7 +62,7 @@ provide('toggleDrawerMenu', () => {
|
||||
|
||||
<template>
|
||||
<a-layout :class="['layout', { mobile: appStore.hideMenu }]">
|
||||
<JoinModal v-model:visible="joinEnterpriseVisible" />
|
||||
<JoinModal v-model:visible="joinEnterpriseVisible" ref="joinModalRef" />
|
||||
<div v-if="navbar" class="layout-navbar">
|
||||
<base-navbar />
|
||||
</div>
|
||||
|
||||
@ -18,9 +18,10 @@ export default function setupUserLoginInfoGuard(router: Router) {
|
||||
const routeName = to?.name as string;
|
||||
const requiresAuth = to?.meta?.requiresAuth || false;
|
||||
const requireLogin = to?.meta?.requireLogin || false;
|
||||
const query = to?.query ?? {};
|
||||
|
||||
if (requireLogin && !userStore.isLogin) {
|
||||
goUserLogin();
|
||||
goUserLogin(query);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import IconRepository from '@/assets/svg/svg-repository.svg';
|
||||
import IconMediaAccount from '@/assets/svg/svg-mediaAccount.svg';
|
||||
import IconPutAccount from '@/assets/svg/svg-putAccount.svg';
|
||||
import IconIntelligentSolution from '@/assets/svg/svg-intelligentSolution.svg';
|
||||
import IconProjectManagement from '@/assets/svg/svg-projectManagement.svg';
|
||||
|
||||
const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
{
|
||||
@ -195,6 +196,32 @@ const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: '/project-manage',
|
||||
name: 'ProjectManagement',
|
||||
redirect: 'project-manage/project-list',
|
||||
meta: {
|
||||
locale: '项目管理',
|
||||
icon: IconProjectManagement,
|
||||
requiresAuth: true,
|
||||
requireLogin: true,
|
||||
roles: ['*'],
|
||||
id: MENU_GROUP_IDS.PROPERTY_ID,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'project-list',
|
||||
name: 'ProjectList',
|
||||
meta: {
|
||||
locale: '项目列表',
|
||||
requiresAuth: true,
|
||||
requireLogin: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
component: () => import('@/views/property-marketing/project-manage/project-list'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default COMPONENTS;
|
||||
|
||||
@ -85,6 +85,13 @@ export const MENU_LIST = [
|
||||
// 'IntelligentSolutionCompetitiveProductAnalysisReport',
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
name: '项目管理',
|
||||
routeName: 'ProjectList',
|
||||
includeRouteNames: [
|
||||
'ProjectList',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
183
src/styles/components/button.scss
Normal file
183
src/styles/components/button.scss
Normal file
@ -0,0 +1,183 @@
|
||||
.arco-btn {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #d7d7d9 !important;
|
||||
color: #3c4043 !important;
|
||||
font-family: $font-family-regular;
|
||||
font-size: 14px !important;
|
||||
font-style: normal;
|
||||
font-weight: 400 !important;
|
||||
line-height: 22px !important;
|
||||
&.arco-btn-disabled {
|
||||
border-color: #f2f3f5 !important;
|
||||
color: #b1b2b5 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
border-color: #e6e6e8 !important;
|
||||
color: #737478 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arco-btn-primary {
|
||||
background-color: $color-primary !important;
|
||||
border: none !important;
|
||||
color: #fff !important;
|
||||
&.arco-btn-disabled {
|
||||
color: #fff !important;
|
||||
background-color: $color-primary-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
color: #fff !important;
|
||||
background-color: $color-primary-5 !important;
|
||||
}
|
||||
}
|
||||
|
||||
//success
|
||||
&.arco-btn-status-success {
|
||||
background-color: $color-success !important;
|
||||
&.arco-btn-disabled {
|
||||
background-color: $color-success-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
background-color: $color-success-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// danger
|
||||
&.arco-btn-status-danger {
|
||||
background-color: $color-error !important;
|
||||
&.arco-btn-disabled {
|
||||
background-color: $color-error-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
background-color: $color-error-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// warning
|
||||
&.arco-btn-status-warning {
|
||||
background-color: $color-warning !important;
|
||||
&.arco-btn-disabled {
|
||||
background-color: $color-warning-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
background-color: $color-warning-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arco-btn-outline {
|
||||
border: 1px solid $color-primary !important;
|
||||
color: $color-primary !important;
|
||||
&.arco-btn-disabled {
|
||||
border-color: $color-primary-3 !important;
|
||||
color: $color-primary-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
border-color: $color-primary-5 !important;
|
||||
color: $color-primary-5 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.arco-btn-status-success {
|
||||
border: 1px solid $color-success !important;
|
||||
color: $color-success !important;
|
||||
&.arco-btn-disabled {
|
||||
border-color: $color-success-3 !important;
|
||||
color: $color-success-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
border-color: $color-success-5 !important;
|
||||
color: $color-success-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.arco-btn-status-danger {
|
||||
border: 1px solid $color-error !important;
|
||||
color: $color-error !important;
|
||||
&.arco-btn-disabled {
|
||||
border-color: $color-error-3 !important;
|
||||
color: $color-error-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
border-color: $color-error-5 !important;
|
||||
color: $color-error-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.arco-btn-status-warning {
|
||||
border: 1px solid $color-warning !important;
|
||||
color: $color-warning !important;
|
||||
&.arco-btn-disabled {
|
||||
border-color: $color-warning-3 !important;
|
||||
color: $color-warning-3 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
border-color: $color-warning-5 !important;
|
||||
color: $color-warning-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arco-btn-text {
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
color: $color-primary !important;
|
||||
&.arco-btn-disabled {
|
||||
color: $color-primary-2 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
color: $color-primary-5 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.arco-btn-status-success {
|
||||
color: $color-success !important;
|
||||
&.arco-btn-disabled {
|
||||
color: $color-success-2 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
color: $color-success-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.arco-btn-status-danger {
|
||||
color: $color-error !important;
|
||||
&.arco-btn-disabled {
|
||||
color: $color-error-2 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
color: $color-error-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.arco-btn-status-warning {
|
||||
color: $color-warning !important;
|
||||
&.arco-btn-disabled {
|
||||
color: $color-warning-2 !important;
|
||||
}
|
||||
&:not(.arco-btn-disabled) {
|
||||
&:hover {
|
||||
color: $color-warning-5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/styles/components/form.scss
Normal file
22
src/styles/components/form.scss
Normal file
@ -0,0 +1,22 @@
|
||||
.arco-form {
|
||||
.arco-form-item {
|
||||
margin-bottom: 16px !important;
|
||||
.arco-form-item-label-col {
|
||||
padding-right: 12px !important;
|
||||
.arco-form-item-label {
|
||||
color: #211f24;
|
||||
font-family: $font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
.arco-form-item-label-required-symbol {
|
||||
color: #f64b31;
|
||||
margin-right: 4px;
|
||||
font-size: 14px;
|
||||
font-family: $font-family-regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,4 +6,7 @@
|
||||
@import './modal.scss';
|
||||
@import "./textarea.scss";
|
||||
@import "./select.scss";
|
||||
@import "./date-picker.scss"
|
||||
@import "./date-picker.scss";
|
||||
@import "./button.scss";
|
||||
@import "./steps.scss";
|
||||
@import "./form.scss";
|
||||
47
src/styles/components/steps.scss
Normal file
47
src/styles/components/steps.scss
Normal file
@ -0,0 +1,47 @@
|
||||
.arco-steps {
|
||||
.arco-steps-item {
|
||||
.arco-steps-item-node {
|
||||
.arco-steps-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 32px;
|
||||
color: #3c4043;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
font-family: $font-family-manrope-medium;
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
}
|
||||
.arco-steps-item-content {
|
||||
.arco-steps-item-title {
|
||||
color: #3c4043;
|
||||
font-family: $font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
&::after {
|
||||
background-color: #e6e6e8 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-active,
|
||||
&-finish {
|
||||
.arco-steps-item-node {
|
||||
.arco-steps-icon {
|
||||
color: #fff;
|
||||
background-color: #6d4cfe;
|
||||
}
|
||||
}
|
||||
.arco-steps-item-content {
|
||||
.arco-steps-item-title {
|
||||
font-family: $font-family-medium;
|
||||
&::after {
|
||||
background-color: #6d4cfe !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,9 @@
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-30 16:03:42
|
||||
*/
|
||||
@import './font.scss';
|
||||
@import './lib/variable.scss';
|
||||
@import './lib/reset.scss';
|
||||
|
||||
@import './vars.scss';
|
||||
@import './components/index.scss';
|
||||
// @import './font.scss';
|
||||
|
||||
@ -11,7 +11,7 @@ html,
|
||||
body {
|
||||
background: $color-background;
|
||||
font-family: $font-family-regular;
|
||||
font-size: $font-size-14;
|
||||
font-size: 14px;
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ $font-family-regular: 'PingFangSC-Regular', 'Microsoft Yahei', Arial, sans-serif
|
||||
$font-family-medium: 'PingFangSC-Medium', 'Microsoft Yahei', Arial, sans-serif;
|
||||
$font-family-light: 'PingFangSC-Light', 'Microsoft Yahei', Arial, sans-serif;
|
||||
$font-family-bold: 'PingFangSC-Semibold', 'PingFangSC-Regular', 'Microsoft Yahei', Arial, sans-serif;
|
||||
|
||||
// 数字字体包
|
||||
$font-family-manrope-regular: 'Manrope-Regular';
|
||||
$font-family-manrope-medium: 'Manrope-Medium';
|
||||
@ -12,4 +13,44 @@ $font-family-manrope-semiBold: 'Manrope-SemiBold';
|
||||
|
||||
$color-background: #f9f9f9;
|
||||
|
||||
$font-size-14: 14px;
|
||||
$color-primary: #6d4cfe; // 常规
|
||||
$color-primary-5: #8A70FE; // hover
|
||||
$color-primary-7: #573DCB; // click
|
||||
$color-primary-3: #A794FE; // disabled
|
||||
$color-primary-2: #C5B7FF; // text disabled
|
||||
$color-primary-1: #F0EDFF; // 浅色
|
||||
|
||||
$color-success: #25C883;
|
||||
$color-success-5: #57CF9C;
|
||||
$color-success-7: #1BAE71;
|
||||
$color-success-3: #81DBB5;
|
||||
$color-success-2: #ABE7CE;
|
||||
$color-success-1: #EBF7F2;
|
||||
|
||||
$color-warning: #FFAE00;
|
||||
$color-warning-5: #FFBE33;
|
||||
$color-warning-7: #CC8B00;
|
||||
$color-warning-3: #FFCF66;
|
||||
$color-warning-2: #FFDF99;
|
||||
$color-warning-1: #FFF7E5;
|
||||
|
||||
$color-error: #F64B31;
|
||||
$color-error-5: #F86F5A;
|
||||
$color-error-7: #C53C27;
|
||||
$color-error-3: #FA9383;
|
||||
$color-error-2: #FBB7AD;
|
||||
$color-error-1: #FFE9E7;
|
||||
|
||||
$color-blue: #2A59F3;
|
||||
$color-blue-5: #557AF6;
|
||||
$color-blue-7: #2247C2;
|
||||
$color-blue-3: #7F9CF8;
|
||||
$color-blue-2: #AABDFA;
|
||||
$color-blue-1: #E5ECFF;
|
||||
|
||||
$color-teal: #39C6E9;
|
||||
$color-teal-5: #60D2ED;
|
||||
$color-teal-7: #2E9EBA;
|
||||
$color-teal-3: #88DDF2;
|
||||
$color-teal-2: #B0E8F6;
|
||||
$color-teal-1: #E1F9FF;
|
||||
14
src/styles/mixins/ellipsis.scss
Normal file
14
src/styles/mixins/ellipsis.scss
Normal file
@ -0,0 +1,14 @@
|
||||
@mixin multi-ellipsis($lines) {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: $lines;
|
||||
/* autoprefixer: ignore next */
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
@mixin ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
1
src/styles/mixins/index.scss
Normal file
1
src/styles/mixins/index.scss
Normal file
@ -0,0 +1 @@
|
||||
@import "./ellipsis.scss"
|
||||
55
src/utils/platform.ts
Normal file
55
src/utils/platform.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import icon1 from '@/assets/img/media-account/icon-jl.png';
|
||||
import icon2 from '@/assets/img/media-account/icon-jg.png';
|
||||
import icon3 from '@/assets/img/media-account/icon-bili.png';
|
||||
import icon4 from '@/assets/img/media-account/icon-dy.png';
|
||||
import icon5 from '@/assets/img/media-account/icon-xhs.png';
|
||||
|
||||
// 投放账户
|
||||
export enum ENUM_PUT_ACCOUNT_PLATFORM {
|
||||
jl = 0,
|
||||
jg = 1,
|
||||
bili = 2,
|
||||
};
|
||||
// 新媒体账号
|
||||
export enum ENUM_MEDIA_ACCOUNT_PLATFORM {
|
||||
dy = 0,
|
||||
xhs = 1,
|
||||
}
|
||||
|
||||
export const PLATFORM_LIST = [
|
||||
{
|
||||
label: '巨量',
|
||||
value: ENUM_PUT_ACCOUNT_PLATFORM.jl,
|
||||
icon: icon1,
|
||||
},
|
||||
{
|
||||
label: '聚光',
|
||||
value: ENUM_PUT_ACCOUNT_PLATFORM.jg,
|
||||
icon: icon2,
|
||||
},
|
||||
{
|
||||
label: 'B站',
|
||||
value: ENUM_PUT_ACCOUNT_PLATFORM.bili,
|
||||
icon: icon3,
|
||||
},
|
||||
];
|
||||
|
||||
export const MEDIA_ACCOUNT_PLATFORMS = [
|
||||
{
|
||||
label: '抖音',
|
||||
value: 0,
|
||||
icon: icon4,
|
||||
},
|
||||
{
|
||||
label: '小红书',
|
||||
value: 1,
|
||||
icon: icon5,
|
||||
},
|
||||
];
|
||||
|
||||
export const getPutAccountPlatformLogo = (value: ENUM_PUT_ACCOUNT_PLATFORM) => {
|
||||
return PLATFORM_LIST.find((v) => v.value === value)?.icon ?? null;
|
||||
};
|
||||
export const getMediaAccountPlatformLogo = (value: ENUM_MEDIA_ACCOUNT_PLATFORM) => {
|
||||
return MEDIA_ACCOUNT_PLATFORMS.find((v) => v.value === value)?.icon ?? null;
|
||||
};
|
||||
@ -85,7 +85,7 @@ export function formatTableField(fieldItem: any, rowValue: any, showExactValue =
|
||||
return `${fieldItem.prefix || ''}${value}${fieldItem.suffix || ''}`;
|
||||
}
|
||||
|
||||
export function exactFormatTime(val: number, curYearFmt = 'MM-DD HH:mm', otherYearFmt = 'YYYY-MM-DD HH:mm') {
|
||||
export function exactFormatTime(val: number, curYearFmt = 'MM-DD HH:mm:ss', otherYearFmt = 'YYYY-MM-DD HH:mm:ss') {
|
||||
if (!val) return '-';
|
||||
const year = dayjs(val * 1000).year();
|
||||
const currYear = dayjs().year();
|
||||
|
||||
@ -133,7 +133,7 @@
|
||||
</a-space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="handleCancel">取消</a-button>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
@ -397,14 +397,6 @@ const handleOk = () => {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--Border-1, #d7d7d9);
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -260,7 +260,7 @@
|
||||
</a-space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="handleCancel">取消</a-button>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
@ -713,14 +713,6 @@ onMounted(() => {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--Border-1, #d7d7d9);
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -110,7 +110,7 @@
|
||||
</a-space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="handleCancel">取消</a-button>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
@ -318,14 +318,6 @@ const search = () => {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--Border-1, #d7d7d9);
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -54,16 +54,15 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item hide-label class="mt-68px mb-16px">
|
||||
<div
|
||||
<a-button
|
||||
type="primary"
|
||||
class="w-480 h-48 text-16px rounded-8px text-center text-white leading-48px"
|
||||
class="w-480 h-48 !text-16px !rounded-8px"
|
||||
:class="disabledSubmitBtn ? 'cursor-no-drop' : 'cursor-pointer'"
|
||||
:style="{ backgroundColor: disabledSubmitBtn ? '#C5B7FF' : '#6D4CFE' }"
|
||||
:disabled="disabledSubmitBtn"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
{{ isLogin ? '登录' : '注册并开通企业账号' }}
|
||||
</div>
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-space class="text-12px color-#737478 justify-start items-center">
|
||||
@ -126,13 +125,16 @@
|
||||
<script setup lang="ts">
|
||||
import PuzzleVerification from './components/PuzzleVerification.vue';
|
||||
import { fetchLoginCaptCha, fetchAuthorizationsCaptcha, fetchProfileInfo } from '@/api/all/login';
|
||||
import { joinEnterpriseByInviteCode } from '@/api/all';
|
||||
import { ref, reactive, onUnmounted, computed } from 'vue';
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useEnterpriseStore } from '@/stores/modules/enterprise';
|
||||
import { handleUserLogin } from '@/utils/user';
|
||||
import router from '@/router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const formRef = ref();
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
const enterpriseStore = useEnterpriseStore();
|
||||
const countdown = ref(0);
|
||||
@ -145,7 +147,6 @@ const submitting = ref(false);
|
||||
const hasCheck = ref(false);
|
||||
const mobileNumber = ref('');
|
||||
const selectedAccountIndex = ref(0);
|
||||
|
||||
const accounts = ref([]);
|
||||
|
||||
const loginForm = reactive({
|
||||
@ -300,6 +301,15 @@ const handleSubmit = async () => {
|
||||
// 处理登录成功逻辑
|
||||
AMessage.success(isLogin.value ? '登录成功' : '注册成功');
|
||||
userStore.setToken(data.access_token);
|
||||
|
||||
const { invite_code } = route.query;
|
||||
if (invite_code) {
|
||||
const { code } = await joinEnterpriseByInviteCode(invite_code as string);
|
||||
if (code === 200) {
|
||||
AMessage.success('加入企业成功');
|
||||
}
|
||||
}
|
||||
|
||||
getProfileInfo();
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@ -21,13 +21,13 @@
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row flex">
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
|
||||
@ -3,23 +3,11 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
|
||||
:deep(.edit-btn) {
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
width: 100%;
|
||||
|
||||
|
||||
@ -1,13 +1,4 @@
|
||||
.arco-modal {
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
|
||||
.arco-modal-body {
|
||||
.arco-form-item {
|
||||
margin-bottom: 16px;
|
||||
|
||||
@ -25,13 +25,13 @@
|
||||
</div>
|
||||
|
||||
<div class="filter-row flex">
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium">
|
||||
<a-button type="outline" class="mr-12px" size="medium">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium">
|
||||
<a-button size="medium">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
|
||||
@ -25,13 +25,13 @@
|
||||
</div>
|
||||
|
||||
<div class="filter-row flex">
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium">
|
||||
<a-button type="outline" class="mr-12px" size="medium">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium">
|
||||
<a-button size="medium">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
|
||||
@ -15,11 +15,11 @@
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-button class="w-110px search-btn mr-12px" size="medium" @click="handleExport">
|
||||
<a-button type="outline" class="w-110px mr-12px" size="medium" @click="handleExport">
|
||||
<template #icon> <icon-download /> </template>
|
||||
<template #default>导出数据</template>
|
||||
</a-button>
|
||||
<a-button class="w-110px search-btn" size="medium" @click="openCustomColumn">
|
||||
<a-button type="outline" class="w-110px" size="medium" @click="openCustomColumn">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="14" height="14" />
|
||||
</template>
|
||||
@ -115,7 +115,7 @@
|
||||
}}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<a-button type="outline" size="small" class="search-btn" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.isRateField" #cell="{ record }">
|
||||
@ -144,7 +144,7 @@
|
||||
</a-table-column>
|
||||
<a-table-column data-index="operation" fixed="right" width="100" title="操作">
|
||||
<template #cell="{ record }">
|
||||
<a-button type="outline" size="small" class="search-btn" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
|
||||
<template #footer>
|
||||
<div style="text-align: right">
|
||||
<a-button class="mr-8px cancel-btn" size="medium" @click="close">取消</a-button>
|
||||
<a-button class="mr-8px" size="medium" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="medium" @click="onSubmit">确定</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -87,13 +87,5 @@
|
||||
}
|
||||
}
|
||||
.arco-modal-footer {
|
||||
.cancel-btn {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
&:hover {
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">分组</span>
|
||||
<a-space class="w-200px">
|
||||
<GroupSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.group_ids" :options="groups" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
@ -31,7 +31,7 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
@ -47,13 +47,13 @@
|
||||
</a-select>
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
@ -66,9 +66,8 @@
|
||||
<script setup>
|
||||
import { reactive, defineEmits, defineProps } from 'vue';
|
||||
import { fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select';
|
||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
|
||||
@ -2,16 +2,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
.filter-wrap {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e6e6e8;
|
||||
|
||||
@ -36,13 +36,13 @@
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
|
||||
@ -19,16 +19,6 @@
|
||||
padding: 10px 0;
|
||||
align-items: center;
|
||||
}
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
width: 100%;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<span>确认删除 {{ accountName }} 这个账号吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
|
||||
@ -46,6 +46,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">
|
||||
<a-tooltip
|
||||
v-if="item.projects.length > 2"
|
||||
position="bottom"
|
||||
:content="
|
||||
item.projects
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
.join(',')
|
||||
"
|
||||
>
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||
</div>
|
||||
</a-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 class="field-row">
|
||||
<span class="label">分组</span>
|
||||
<span class="cts">{{ item.group?.name || '-' }}</span>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<span>确认暂停同步 “{{ accountName }}” 这个账号的数据吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" size="large" @click="onConfirm">确定</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
@mixin ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
|
||||
@ -19,12 +19,11 @@ import {
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
import TagSelect from '@/views/property-marketing/media-account/components/tag-select';
|
||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||
// import ImportPromptModal from '../import-prompt-modal';
|
||||
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
import SyncDataModal from '../sync-data-modal';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
// import { downloadByUrl } from '@/utils/tools';
|
||||
import { showExportNotification } from '@/utils/arcoD';
|
||||
@ -37,6 +36,7 @@ import {
|
||||
putMediaAccounts,
|
||||
getTemplateUrl,
|
||||
batchMediaAccounts,
|
||||
getProjectList,
|
||||
} from '@/api/all/propertyMarketing';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-download.png';
|
||||
@ -58,6 +58,7 @@ const INITIAL_FORM = {
|
||||
platform: 1,
|
||||
group_id: undefined,
|
||||
tag_ids: [],
|
||||
project_ids: [],
|
||||
end_work_link: undefined,
|
||||
cookie: undefined,
|
||||
};
|
||||
@ -66,6 +67,7 @@ export default {
|
||||
setup(props, { emit, expose }) {
|
||||
const groupOptions = ref([]);
|
||||
const tagOptions = ref([]);
|
||||
const projects = ref([]);
|
||||
const visible = ref(false);
|
||||
const uploadType = ref('manual');
|
||||
const uploadStatus = ref(UploadStatus.DEFAULT);
|
||||
@ -126,6 +128,12 @@ export default {
|
||||
tagOptions.value = data;
|
||||
}
|
||||
};
|
||||
const getProjects = async () => {
|
||||
const { code, data } = await getProjectList();
|
||||
if (code === 200) {
|
||||
projects.value = data;
|
||||
}
|
||||
};
|
||||
function handleUpload(option) {
|
||||
const { fileItem } = option;
|
||||
uploadStatus.value = UploadStatus.WAITING;
|
||||
@ -141,6 +149,9 @@ export default {
|
||||
const reset = () => {
|
||||
formRef.value?.resetFields();
|
||||
formRef.value?.clearValidate();
|
||||
groupOptions.value = [];
|
||||
tagOptions.value = [];
|
||||
projects.value = [];
|
||||
form.value = cloneDeep(INITIAL_FORM);
|
||||
fileName.value = '';
|
||||
file.value = null;
|
||||
@ -162,6 +173,7 @@ export default {
|
||||
}
|
||||
getGroups();
|
||||
getTags();
|
||||
getProjects();
|
||||
visible.value = true;
|
||||
};
|
||||
const getAccountDetail = async () => {
|
||||
@ -364,8 +376,16 @@ export default {
|
||||
<FormItem label="号码持有人" field="holder_name">
|
||||
<Input v-model={form.value.holder_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||
</FormItem>
|
||||
<FormItem label="所属项目">
|
||||
<CommonSelect
|
||||
v-model={form.value.project_ids}
|
||||
options={projects.value}
|
||||
placeholder="请选择…"
|
||||
size="large"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="选择分组">
|
||||
<GroupSelect
|
||||
<CommonSelect
|
||||
v-model={form.value.group_id}
|
||||
multiple={false}
|
||||
options={groupOptions.value}
|
||||
@ -373,8 +393,9 @@ export default {
|
||||
size="large"
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="选择标签">
|
||||
<TagSelect v-model={form.value.tag_ids} options={tagOptions.value} placeholder="请选择…" size="large" />
|
||||
<CommonSelect v-model={form.value.tag_ids} options={tagOptions.value} placeholder="请选择…" size="large" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="笔记链接"
|
||||
@ -406,7 +427,6 @@ export default {
|
||||
v-model={form.value.cookie}
|
||||
placeholder="请输入..."
|
||||
size="large"
|
||||
max-length={500}
|
||||
auto-size={{ minRows: 5, maxRows: 8 }}
|
||||
/>
|
||||
</FormItem>
|
||||
@ -415,7 +435,7 @@ export default {
|
||||
)}
|
||||
</Form>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px;">
|
||||
<Button size="large" class="cancel-btn" onClick={onClose}>
|
||||
<Button size="large" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="large" loading={importLoading.value} onClick={onSubmit}>
|
||||
|
||||
@ -76,15 +76,10 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" class="cancel-btn" @click="handleRefreshQrCode">
|
||||
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" @click="handleRefreshQrCode">
|
||||
重新生成
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="[MODAL_STATE.SUCCESS, MODAL_STATE.FAILED].includes(modalState)"
|
||||
size="large"
|
||||
class="cancel-btn"
|
||||
@click="close"
|
||||
>
|
||||
<a-button v-if="[MODAL_STATE.SUCCESS, MODAL_STATE.FAILED].includes(modalState)" size="large" @click="close">
|
||||
取消
|
||||
</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk">
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<a-form-item label="选择分组" required>
|
||||
<template v-if="editType === 'all'">
|
||||
<div class="flex items-center w-100%">
|
||||
<GroupSelect v-model="form.group_id" :options="groupOptions" :multiple="false" class="flex-1" />
|
||||
<CommonSelect v-model="form.group_id" :options="groupOptions" :multiple="false" class="flex-1" />
|
||||
</div>
|
||||
</template>
|
||||
</a-form-item>
|
||||
@ -47,7 +47,7 @@
|
||||
<a-table-column title="选择分组" data-index="group_id">
|
||||
<template #cell="{ record }">
|
||||
<div class="flex items-center w-100%">
|
||||
<GroupSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
|
||||
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
|
||||
</div>
|
||||
</template>
|
||||
</a-table-column>
|
||||
@ -56,7 +56,7 @@
|
||||
</template>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
@ -65,7 +65,7 @@
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { fetchAccountGroups, batchPutGroup } from '@/api/all/propertyMarketing';
|
||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import icon1 from '@/assets/img/icon-question.png';
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
</template>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -33,16 +33,20 @@
|
||||
<span class="label">平台</span>
|
||||
<a-space class="w-160px">
|
||||
<a-select v-model="query.platform" size="medium" placeholder="全部" allow-clear @change="handleSearch">
|
||||
<a-option v-for="(item, index) in PLATFORM_LIST" :key="index" :value="item.value" :label="item.label">{{
|
||||
item.label
|
||||
}}</a-option>
|
||||
<a-option
|
||||
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</a-option
|
||||
>
|
||||
</a-select>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
@ -50,22 +54,28 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">分组</span>
|
||||
<a-space class="w-200px">
|
||||
<GroupSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">所属项目</span>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">标签</span>
|
||||
<a-space class="w-320px">
|
||||
<TagSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
@ -77,13 +87,17 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, defineEmits, defineProps } from 'vue';
|
||||
import { fetchAccountTags, fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
||||
import TagSelect from '@/views/property-marketing/media-account/components/tag-select';
|
||||
import GroupSelect from '@/views/property-marketing/media-account/components/group-select';
|
||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select';
|
||||
import {
|
||||
fetchAccountTags,
|
||||
getProjectList,
|
||||
fetchAccountGroups,
|
||||
fetchAccountOperators,
|
||||
} from '@/api/all/propertyMarketing';
|
||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import { INITIAL_QUERY, PLATFORM_LIST } from '@/views/property-marketing/media-account/account-manage/constants';
|
||||
import { INITIAL_QUERY } from '@/views/property-marketing/media-account/account-manage/constants';
|
||||
import { MEDIA_ACCOUNT_PLATFORMS } from '@/utils/platform';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
@ -97,6 +111,7 @@ const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
const tags = ref([]);
|
||||
const groups = ref([]);
|
||||
const operators = ref([]);
|
||||
const projects = ref([]);
|
||||
|
||||
const handleSearch = () => {
|
||||
emits('update:query', props.query);
|
||||
@ -127,11 +142,18 @@ const getOperators = async () => {
|
||||
operators.value = data;
|
||||
}
|
||||
};
|
||||
const getProjects = async () => {
|
||||
const { code, data } = await getProjectList();
|
||||
if (code === 200) {
|
||||
projects.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTags();
|
||||
getGroups();
|
||||
getOperators();
|
||||
getProjects();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<span>确认删除 "{{ groupName }}" 这个分组吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="close">取消</a-button>
|
||||
<a-button size="large" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk"> 去授权 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -92,13 +92,12 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" class="cancel-btn" @click="handleRefreshQrCode">
|
||||
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" @click="handleRefreshQrCode">
|
||||
重新生成
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="modalState === MODAL_STATE.SUCCESS || modalState === MODAL_STATE.FAILED"
|
||||
size="large"
|
||||
class="cancel-btn"
|
||||
@click="close"
|
||||
>
|
||||
取消
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="close">稍后再说</a-button>
|
||||
<a-button size="large" @click="close">稍后再说</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk"> 更新数据 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
<!--
|
||||
* @Author: AI
|
||||
* @Date: 2025-06-27
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
@ -16,7 +12,7 @@
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<span>确认删除 "{{ tagName }}" 这个标签吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
|
||||
@ -9,6 +9,7 @@ export const INITIAL_QUERY = {
|
||||
operator_id: '',
|
||||
group_ids: [],
|
||||
tag_ids: [],
|
||||
project_ids: [],
|
||||
};
|
||||
|
||||
export const INITIAL_PAGE_INFO = {
|
||||
|
||||
@ -8,19 +8,19 @@
|
||||
<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">
|
||||
<a-button class="w-112px mr-12px search-btn" size="medium" @click="handleOpenTagsModal">
|
||||
<a-button class="w-112px mr-12px" type="outline" size="medium" @click="handleOpenTagsModal">
|
||||
<template #icon>
|
||||
<img :src="icon3" width="16" height="16" />
|
||||
</template>
|
||||
<template #default>标签管理</template>
|
||||
</a-button>
|
||||
<a-button class="w-112px mr-12px search-btn" size="medium" @click="handleOpenGroupModal">
|
||||
<a-button class="w-112px mr-12px" type="outline" size="medium" @click="handleOpenGroupModal">
|
||||
<template #icon>
|
||||
<img :src="icon2" width="16" height="16" />
|
||||
</template>
|
||||
<template #default>分组管理</template>
|
||||
</a-button>
|
||||
<a-button type="primary" class="w-112px search-btn" size="medium" @click="handleOpenAccountModal">
|
||||
<a-button type="primary" class="w-112px" size="medium" @click="handleOpenAccountModal">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="16" height="16" />
|
||||
</template>
|
||||
@ -70,7 +70,7 @@
|
||||
</template>
|
||||
<div v-else>
|
||||
<a-space v-if="isAbNormalStatus" class="flex items-center">
|
||||
<a-button class="w-96px err-btn" size="mini" @click="handleOpenAbnormalAccount">
|
||||
<a-button type="primary" status="danger" size="mini" @click="handleOpenAbnormalAccount">
|
||||
<template #default>查看异常账号</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
||||
@ -2,16 +2,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
.filter-wrap {
|
||||
.top {
|
||||
.title {
|
||||
@ -47,15 +37,6 @@
|
||||
color: #211f24;
|
||||
}
|
||||
}
|
||||
.err-btn {
|
||||
background-color: #f64b31 !important;
|
||||
color: var(--BG-white, #fff);
|
||||
font-family: 'PingFang SC';
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 166.667% */
|
||||
}
|
||||
.operation-btn {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
<!--
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-25 14:02:40
|
||||
-->
|
||||
<template>
|
||||
<a-select
|
||||
v-model="selectedGroups"
|
||||
:multiple="multiple"
|
||||
size="medium"
|
||||
:placeholder="placeholder"
|
||||
allow-clear
|
||||
:max-tag-count="3"
|
||||
@change="handleChange"
|
||||
>
|
||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default: () => [],
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '全部',
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const selectedGroups = ref(props.multiple ? [] : '');
|
||||
|
||||
// 监听外部传入的值变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
selectedGroups.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
// 监听内部值变化,向外部发送更新
|
||||
watch(selectedGroups, (newVal) => {
|
||||
emits('update:modelValue', newVal);
|
||||
});
|
||||
|
||||
const handleChange = (value) => {
|
||||
selectedGroups.value = value;
|
||||
emits('change', value);
|
||||
};
|
||||
</script>
|
||||
@ -1,64 +0,0 @@
|
||||
<!--
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-25 14:02:40
|
||||
-->
|
||||
<template>
|
||||
<a-select
|
||||
v-model="selectedOperators"
|
||||
:multiple="multiple"
|
||||
size="medium"
|
||||
:placeholder="placeholder"
|
||||
allow-clear
|
||||
@change="handleChange"
|
||||
>
|
||||
<a-option v-for="(item, index) in options" :key="index" :value="item.id" :label="item.name">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default: () => [],
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '全部',
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const selectedOperators = ref(props.multiple ? [] : '');
|
||||
|
||||
// 监听外部传入的值变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
selectedOperators.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 监听内部值变化,向外部发送更新
|
||||
watch(selectedOperators, (newVal) => {
|
||||
emits('update:modelValue', newVal);
|
||||
});
|
||||
|
||||
const handleChange = (value) => {
|
||||
selectedOperators.value = value;
|
||||
emits('change', value);
|
||||
};
|
||||
</script>
|
||||
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="添加项目"
|
||||
modal-class="add-project-modal"
|
||||
width="960px"
|
||||
:mask-closable="false"
|
||||
@close="onClose"
|
||||
>
|
||||
<div class="content">
|
||||
<a-steps changeable :current="currentStep" @change="setCurrent" class="mb-24px mx-79px">
|
||||
<a-step v-for="(step, index) in STEPS" :key="index">{{ step.label }}</a-step>
|
||||
</a-steps>
|
||||
|
||||
<component :is="activeComp" v-model:formQuery="formQuery" ref="compRef" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-between items-center w-100%">
|
||||
<div>
|
||||
<a-button type="outline" size="medium" @click="onPrev" v-if="!isFirstStep">上一步</a-button>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-button size="medium" class="mr-8px" @click="onCancel">取消</a-button>
|
||||
<a-button type="primary" size="medium" @click="onSubmit">{{ isLastStep ? '确认添加' : '下一步' }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { postAddProject, putProject, getProjectDetail } from '@/api/all/propertyMarketing';
|
||||
|
||||
import StepOne from './stepOne.vue';
|
||||
import StepTwo from './stepTwo.vue';
|
||||
import StepThree from './stepThree.vue';
|
||||
import StepFour from './stepFour.vue';
|
||||
|
||||
const STEPS = [
|
||||
{
|
||||
label: '项目信息',
|
||||
index: 1,
|
||||
comp: StepOne,
|
||||
},
|
||||
{
|
||||
label: '关联平台账号',
|
||||
index: 2,
|
||||
comp: StepTwo,
|
||||
},
|
||||
{
|
||||
label: '关联渠道账户',
|
||||
index: 3,
|
||||
comp: StepThree,
|
||||
},
|
||||
{
|
||||
label: '关联内容稿件',
|
||||
index: 4,
|
||||
comp: StepFour,
|
||||
},
|
||||
];
|
||||
const INITIAL_QUERY = {
|
||||
name: '',
|
||||
budget: '',
|
||||
target: '',
|
||||
background: '',
|
||||
media_account_ids: [],
|
||||
placement_account_ids: [],
|
||||
work_ids: [],
|
||||
};
|
||||
|
||||
const update = inject('update');
|
||||
|
||||
const visible = ref(false);
|
||||
const currentStep = ref(1);
|
||||
const formQuery = ref(cloneDeep(INITIAL_QUERY));
|
||||
const compRef = ref(null);
|
||||
const projectId = ref(null);
|
||||
|
||||
const isFirstStep = computed(() => currentStep.value === 1);
|
||||
const isEdit = computed(() => projectId.value);
|
||||
const isLastStep = computed(() => currentStep.value === STEPS.length);
|
||||
const activeComp = computed(() => STEPS.find((v) => v.index === currentStep.value)?.comp ?? null);
|
||||
|
||||
const open = (id = null) => {
|
||||
projectId.value = id;
|
||||
|
||||
if (id) {
|
||||
getDetail();
|
||||
}
|
||||
|
||||
visible.value = true;
|
||||
};
|
||||
const getDetail = (id) => {
|
||||
getProjectDetail(projectId.value).then((res) => {
|
||||
if (res.code === 200) {
|
||||
formQuery.value = res.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
const onClose = () => {
|
||||
currentStep.value = 1;
|
||||
formQuery.value = cloneDeep(INITIAL_QUERY);
|
||||
projectId.value = '';
|
||||
compRef.value?.reset?.();
|
||||
|
||||
visible.value = false;
|
||||
};
|
||||
const onCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (isFirstStep.value) {
|
||||
const valid = await compRef.value.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLastStep.value) {
|
||||
isEdit.value ? handleEdit() : handleAdd();
|
||||
} else {
|
||||
currentStep.value++;
|
||||
}
|
||||
};
|
||||
const handleAdd = () => {
|
||||
postAddProject(formQuery.value).then((res) => {
|
||||
if (res.code === 200) {
|
||||
onClose();
|
||||
update();
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleEdit = () => {
|
||||
putProject({ id: projectId.value, ...formQuery.value }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
onClose();
|
||||
update();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setCurrent = async (current) => {
|
||||
if (isFirstStep.value) {
|
||||
const valid = await compRef.value.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentStep.value = current;
|
||||
};
|
||||
const onPrev = () => {
|
||||
currentStep.value--;
|
||||
};
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<div class="table-wrap flex h-448px">
|
||||
<div class="left flex-1 pr-12px flex flex-col">
|
||||
<div class="flex items-center mb-16px">
|
||||
<a-input
|
||||
v-model="query.uid"
|
||||
class="w-160px mr-16px"
|
||||
placeholder="搜索序号"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-input
|
||||
v-model="query.title"
|
||||
class="w-220px mr-16px"
|
||||
placeholder="搜索内容稿件标题"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
|
||||
<a-select
|
||||
v-model="query.uploader_id"
|
||||
size="medium"
|
||||
placeholder="选择上传人员"
|
||||
class="w-160px"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-option v-for="(item, index) in uploaders" :key="index" :value="item.id" :label="item.name">
|
||||
{{ item.name || '-' }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
column-resizable
|
||||
row-key="id"
|
||||
:row-selection="rowSelection"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%', y: '100%' }"
|
||||
class="flex-1 overflow-hidden"
|
||||
:selected-keys="selectedRowKeys"
|
||||
bordered
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
>
|
||||
<template #empty>
|
||||
<NoData text="暂无账户" />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell="{ record }">
|
||||
<template v-if="column.dataIndex === 'created_at'">
|
||||
{{ exactFormatTime(record.created_at) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<div class="right w-320px px-12px flex flex-col">
|
||||
<div class="flex justify-between">
|
||||
<p class="mb-16px s1">{{ `已选择(${selectedRows?.length ?? 0})` }}</p>
|
||||
<a-button type="text" @click="onClearSelect" v-if="selectedRows.length">清空</a-button>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden">
|
||||
<template v-if="selectedRows?.length">
|
||||
<div class="tag-item mb-8px" v-for="item in selectedRows" :key="item.id">
|
||||
<a-tooltip :content="item.name">
|
||||
<p class="name mr-4px">{{ item.name || '-' }}</p>
|
||||
</a-tooltip>
|
||||
<icon-close size="12" class="color-#3C4043 cursor-pointer flex-shrink-0" @click="onDelete(item)" />
|
||||
</div>
|
||||
</template>
|
||||
<NoData v-else text="暂无账户" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
|
||||
import { getPlacementAccountOperators, getWorksList } from '@/api/all/propertyMarketing';
|
||||
import { getUserList } from '@/api/all/common';
|
||||
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
|
||||
const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'uid',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '内容稿件标题',
|
||||
dataIndex: 'title',
|
||||
},
|
||||
{
|
||||
title: '上传时间',
|
||||
dataIndex: 'created_at',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '上传人员',
|
||||
dataIndex: 'uploader.name',
|
||||
width: 120,
|
||||
},
|
||||
];
|
||||
const emit = defineEmits(['update:formQuery']);
|
||||
|
||||
const props = defineProps({
|
||||
formQuery: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { dataSource, selectedRowKeys, selectedRows, rowSelection, handleSelect, handleSelectAll } =
|
||||
useTableSelectionWithPagination({
|
||||
onSelectChange: () => {
|
||||
updateFormQuery();
|
||||
},
|
||||
});
|
||||
|
||||
const query = ref({
|
||||
uid: '',
|
||||
uploader_id: '',
|
||||
title: '',
|
||||
});
|
||||
const uploaders = ref([]);
|
||||
const allData = ref([]);
|
||||
|
||||
const updateFormQuery = () => {
|
||||
emit('update:formQuery', {
|
||||
...props.formQuery,
|
||||
work_ids: selectedRowKeys.value,
|
||||
});
|
||||
};
|
||||
const handleSearch = () => {
|
||||
const { uid, title, uploader_id } = query.value;
|
||||
dataSource.value = allData.value.filter((item) => {
|
||||
const uinMatch = uid === '' ? true : item.uid.includes(uid);
|
||||
const titleMatch = title === '' ? true : item.title === title;
|
||||
const operatorIdMatch = uploader_id === '' ? true : item.uploader?.id === uploader_id;
|
||||
return uinMatch && titleMatch && operatorIdMatch;
|
||||
});
|
||||
};
|
||||
|
||||
const getUsers = async () => {
|
||||
const { code, data } = await getUserList();
|
||||
if (code === 200) {
|
||||
uploaders.value = data.map( v => ({
|
||||
...v,
|
||||
name: v.name || v.mobile
|
||||
}));
|
||||
|
||||
console.log(uploaders.value);
|
||||
}
|
||||
};
|
||||
const getTableData = async () => {
|
||||
const { code, data } = await getWorksList();
|
||||
if (code === 200) {
|
||||
allData.value = data ?? [];
|
||||
dataSource.value = data ?? [];
|
||||
initSelect();
|
||||
}
|
||||
};
|
||||
const initSelect = () => {
|
||||
if (props.formQuery.work_ids?.length) {
|
||||
selectedRowKeys.value = props.formQuery.work_ids;
|
||||
selectedRows.value = dataSource.value.filter((v) => selectedRowKeys.value.includes(v.id));
|
||||
}
|
||||
};
|
||||
|
||||
const onClearSelect = () => {
|
||||
selectedRowKeys.value = [];
|
||||
selectedRows.value = [];
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
const onDelete = (item) => {
|
||||
const { id } = item;
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((v) => v !== id);
|
||||
selectedRows.value = selectedRows.value.filter((v) => v.id !== id);
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getUsers();
|
||||
getTableData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-wrap {
|
||||
.s1 {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
}
|
||||
.left {
|
||||
border-right: 1px solid var(--Border-2, #e6e6e8);
|
||||
:deep(.arco-table) {
|
||||
}
|
||||
}
|
||||
.right {
|
||||
.tag-item {
|
||||
max-width: 100%;
|
||||
width: fit-content;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
height: 24px;
|
||||
padding: 0px 8px;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
.name {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px; /* 157.143% */
|
||||
flex: 1;
|
||||
@include ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<a-form ref="formRef" :model="formQuery" :rules="rules" layout="horizontal" auto-label-width class="h-448px">
|
||||
<a-form-item label="项目名称" required field="name">
|
||||
<a-input v-model="formQuery.name" placeholder="请输入项目名称" size="large" class="!w-400px" />
|
||||
</a-form-item>
|
||||
<a-form-item label="项目预算" field="budget">
|
||||
<a-input v-model="formQuery.budget" placeholder="请输入项目预算" size="large" class="!w-400px" />
|
||||
</a-form-item>
|
||||
<a-form-item label="项目目标" field="target">
|
||||
<a-textarea
|
||||
v-model="formQuery.target"
|
||||
placeholder="请输入项目目标"
|
||||
:max-length="500"
|
||||
show-word-limit
|
||||
class="h-154px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="项目背景" field="background">
|
||||
<a-textarea
|
||||
v-model="formQuery.background"
|
||||
placeholder="请输入项目背景"
|
||||
:max-length="500"
|
||||
show-word-limit
|
||||
class="h-154px"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
formQuery: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const formRef = ref(null);
|
||||
|
||||
const rules = {
|
||||
name: [{ required: true, message: '请输入项目名称' }],
|
||||
};
|
||||
|
||||
const validate = async () => {
|
||||
const errors = await formRef.value.validate();
|
||||
return !errors
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
|
||||
defineExpose({ validate, reset });
|
||||
</script>
|
||||
@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<div class="table-wrap flex h-448px">
|
||||
<div class="left flex-1 pr-12px flex flex-col">
|
||||
<div class="flex items-center mb-16px">
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
class="w-220px mr-16px"
|
||||
placeholder="搜索账户"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-select
|
||||
v-model="query.platform"
|
||||
class="mr-16px w-160px"
|
||||
size="medium"
|
||||
placeholder="选择平台"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-option
|
||||
v-for="(item, index) in PLATFORM_LIST"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</a-option
|
||||
>
|
||||
</a-select>
|
||||
<a-select
|
||||
v-model="query.operator_id"
|
||||
size="medium"
|
||||
placeholder="选择运营人员"
|
||||
class="w-160px"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-option v-for="(item, index) in operators" :key="index" :value="item.id" :label="item.name">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
column-resizable
|
||||
row-key="id"
|
||||
:row-selection="rowSelection"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%', y: '100%' }"
|
||||
class="flex-1 overflow-hidden"
|
||||
:selected-keys="selectedRowKeys"
|
||||
bordered
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
>
|
||||
<template #empty>
|
||||
<NoData text="暂无账户"/>
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell="{ record }">
|
||||
<template v-if="column.dataIndex === 'platform'">
|
||||
<img :src="getPutAccountPlatformLogo(record.platform)" width="19" height="19" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<div class="right w-320px px-12px flex flex-col">
|
||||
<div class="flex justify-between">
|
||||
<p class="mb-16px s1">{{ `已选择(${selectedRows?.length ?? 0})` }}</p>
|
||||
<a-button type="text" @click="onClearSelect" v-if="selectedRows.length">清空</a-button>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden">
|
||||
<template v-if="selectedRows?.length">
|
||||
<div class="tag-item mb-8px" v-for="item in selectedRows" :key="item.id">
|
||||
<a-tooltip :content="item.name">
|
||||
<p class="name mr-4px">{{ item.name || '-' }}</p>
|
||||
</a-tooltip>
|
||||
<icon-close size="12" class="color-#3C4043 cursor-pointer flex-shrink-0" @click="onDelete(item)" />
|
||||
</div>
|
||||
</template>
|
||||
<NoData v-else text="暂无账户" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { PLATFORM_LIST, getPutAccountPlatformLogo } from '@/utils/platform';
|
||||
import { formatTableField } from '@/utils/tools';
|
||||
|
||||
import { getPlacementAccountOperators, getPlacementAccountsList } from '@/api/all/propertyMarketing';
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
|
||||
const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '账号名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '渠道',
|
||||
dataIndex: 'platform',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '运营人员',
|
||||
dataIndex: 'operator.name',
|
||||
width: 140,
|
||||
},
|
||||
];
|
||||
const emit = defineEmits(['update:formQuery']);
|
||||
|
||||
const props = defineProps({
|
||||
formQuery: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { dataSource, selectedRowKeys, selectedRows, rowSelection, handleSelect, handleSelectAll } =
|
||||
useTableSelectionWithPagination({
|
||||
onSelectChange: () => {
|
||||
updateFormQuery();
|
||||
},
|
||||
});
|
||||
|
||||
const query = ref({
|
||||
name: '',
|
||||
operator_id: '',
|
||||
platform: '',
|
||||
});
|
||||
const operators = ref([]);
|
||||
const allData = ref([]);
|
||||
|
||||
const updateFormQuery = () => {
|
||||
emit('update:formQuery', {
|
||||
...props.formQuery,
|
||||
placement_account_ids: selectedRowKeys.value,
|
||||
});
|
||||
};
|
||||
const handleSearch = () => {
|
||||
const { name, platform, operator_id } = query.value;
|
||||
dataSource.value = allData.value.filter((item) => {
|
||||
const nameMatch = name === '' ? true : item.name.includes(name);
|
||||
const platformMatch = platform === '' ? true : item.platform === platform;
|
||||
const operatorIdMatch = operator_id === '' ? true : item.operator_id === operator_id;
|
||||
return nameMatch && platformMatch && operatorIdMatch;
|
||||
});
|
||||
};
|
||||
|
||||
const getOperators = async () => {
|
||||
const { code, data } = await getPlacementAccountOperators();
|
||||
if (code === 200) {
|
||||
operators.value = data;
|
||||
}
|
||||
};
|
||||
const getTableData = async () => {
|
||||
const { code, data } = await getPlacementAccountsList();
|
||||
if (code === 200) {
|
||||
allData.value = data ?? [];
|
||||
dataSource.value = data ?? [];
|
||||
initSelect();
|
||||
}
|
||||
};
|
||||
const initSelect = () => {
|
||||
if (props.formQuery.placement_account_ids?.length) {
|
||||
selectedRowKeys.value = props.formQuery.placement_account_ids;
|
||||
selectedRows.value = dataSource.value.filter((v) => selectedRowKeys.value.includes(v.id));
|
||||
}
|
||||
};
|
||||
|
||||
const onClearSelect = () => {
|
||||
selectedRowKeys.value = [];
|
||||
selectedRows.value = [];
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
const onDelete = (item) => {
|
||||
const { id } = item;
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((v) => v !== id);
|
||||
selectedRows.value = selectedRows.value.filter((v) => v.id !== id);
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getOperators();
|
||||
getTableData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-wrap {
|
||||
.s1 {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
}
|
||||
.left {
|
||||
border-right: 1px solid var(--Border-2, #e6e6e8);
|
||||
:deep(.arco-table) {
|
||||
}
|
||||
}
|
||||
.right {
|
||||
.tag-item {
|
||||
max-width: 100%;
|
||||
width: fit-content;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
height: 24px;
|
||||
padding: 0px 8px;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
.name {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px; /* 157.143% */
|
||||
flex: 1;
|
||||
@include ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<div class="table-wrap flex h-448px">
|
||||
<div class="left flex-1 pr-12px flex flex-col">
|
||||
<div class="flex items-center mb-16px">
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
class="w-220px mr-16px"
|
||||
placeholder="搜索账号"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-select
|
||||
v-model="query.platform"
|
||||
class="mr-16px w-160px"
|
||||
size="medium"
|
||||
placeholder="选择平台"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-option
|
||||
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</a-option
|
||||
>
|
||||
</a-select>
|
||||
<a-select
|
||||
v-model="query.operator_id"
|
||||
size="medium"
|
||||
placeholder="选择运营人员"
|
||||
class="w-160px"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-option v-for="(item, index) in operators" :key="index" :value="item.id" :label="item.name">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<a-table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
column-resizable
|
||||
row-key="id"
|
||||
:row-selection="rowSelection"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%', y: '100%' }"
|
||||
class="flex-1 overflow-hidden"
|
||||
:selected-keys="selectedRowKeys"
|
||||
bordered
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
>
|
||||
<template #empty>
|
||||
<NoData text="暂无账号"/>
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell="{ record }">
|
||||
<template v-if="column.dataIndex === 'platform'">
|
||||
<img :src="getMediaAccountPlatformLogo(record.platform)" width="19" height="19" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<div class="right w-320px px-12px flex flex-col">
|
||||
<div class="flex justify-between">
|
||||
<p class="mb-16px s1">{{ `已选择(${selectedRows?.length ?? 0})` }}</p>
|
||||
<a-button type="text" @click="onClearSelect" v-if="selectedRows.length">清空</a-button>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<div class="flex flex-wrap" v-if="selectedRows?.length">
|
||||
<div class="tag-item mr-8px mb-8px" v-for="item in selectedRows" :key="item.id">
|
||||
<span class="name mr-4px">{{ item.name || '-' }}</span>
|
||||
<icon-close size="12" class="color-#3C4043 cursor-pointer" @click="onDelete(item)" />
|
||||
</div>
|
||||
</div>
|
||||
<NoData v-else text="暂无账号" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { MEDIA_ACCOUNT_PLATFORMS, getMediaAccountPlatformLogo } from '@/utils/platform';
|
||||
import { formatTableField } from '@/utils/tools';
|
||||
|
||||
import { fetchAccountOperators, getMediaAccountList } from '@/api/all/propertyMarketing';
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
|
||||
const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '账号名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '平台',
|
||||
dataIndex: 'platform',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '运营人员',
|
||||
dataIndex: 'operator.name',
|
||||
width: 140,
|
||||
},
|
||||
];
|
||||
const emit = defineEmits(['update:formQuery']);
|
||||
|
||||
const props = defineProps({
|
||||
formQuery: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { dataSource, selectedRowKeys, selectedRows, rowSelection, handleSelect, handleSelectAll } =
|
||||
useTableSelectionWithPagination({
|
||||
onSelectChange: () => {
|
||||
updateFormQuery();
|
||||
},
|
||||
});
|
||||
|
||||
const query = ref({
|
||||
name: '',
|
||||
operator_id: '',
|
||||
platform: '',
|
||||
});
|
||||
const operators = ref([]);
|
||||
const allData = ref([]);
|
||||
|
||||
const updateFormQuery = () => {
|
||||
emit('update:formQuery', {
|
||||
...props.formQuery,
|
||||
media_account_ids: selectedRowKeys.value,
|
||||
});
|
||||
};
|
||||
const handleSearch = () => {
|
||||
const { name, platform, operator_id } = query.value;
|
||||
dataSource.value = allData.value.filter((item) => {
|
||||
const nameMatch = name === '' ? true : item.name.includes(name);
|
||||
const platformMatch = platform === '' ? true : item.platform === platform;
|
||||
const operatorIdMatch = operator_id === '' ? true : item.operator_id === operator_id;
|
||||
return nameMatch && platformMatch && operatorIdMatch;
|
||||
});
|
||||
};
|
||||
|
||||
const getOperators = async () => {
|
||||
const { code, data } = await fetchAccountOperators();
|
||||
if (code === 200) {
|
||||
operators.value = data;
|
||||
}
|
||||
};
|
||||
const getTableData = async () => {
|
||||
const { code, data } = await getMediaAccountList();
|
||||
if (code === 200) {
|
||||
allData.value = data ?? [];
|
||||
dataSource.value = data ?? [];
|
||||
initSelect();
|
||||
}
|
||||
};
|
||||
const initSelect = () => {
|
||||
if (props.formQuery.media_account_ids?.length) {
|
||||
selectedRowKeys.value = props.formQuery.media_account_ids;
|
||||
selectedRows.value = dataSource.value.filter((v) => selectedRowKeys.value.includes(v.id));
|
||||
}
|
||||
};
|
||||
|
||||
const onClearSelect = () => {
|
||||
selectedRowKeys.value = [];
|
||||
selectedRows.value = [];
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
const onDelete = (item) => {
|
||||
const { id } = item;
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((v) => v !== id);
|
||||
selectedRows.value = selectedRows.value.filter((v) => v.id !== id);
|
||||
updateFormQuery();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getOperators();
|
||||
getTableData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-wrap {
|
||||
.s1 {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
}
|
||||
.left {
|
||||
border-right: 1px solid var(--Border-2, #e6e6e8);
|
||||
:deep(.arco-table) {
|
||||
}
|
||||
}
|
||||
.right {
|
||||
.tag-item {
|
||||
width: fit-content;
|
||||
display: flex;
|
||||
height: 24px;
|
||||
padding: 0px 8px;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
.name {
|
||||
color: var(--Text-2, #3c4043);
|
||||
font-family: font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px; /* 157.143% */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,3 @@
|
||||
.add-project-modal {
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<!--
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-25 14:02:40
|
||||
-->
|
||||
<template>
|
||||
<div class="filter-wrap px-24px pt-12px pb-24px">
|
||||
<div class="filter-row flex">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">项目名称</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
class="w-240px"
|
||||
placeholder="请搜索..."
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
|
||||
const handleSearch = () => {
|
||||
emits('update:query', props.query);
|
||||
nextTick(() => {
|
||||
emits('onSearch');
|
||||
});
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emits('onReset');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -0,0 +1,23 @@
|
||||
.filter-wrap {
|
||||
.filter-row {
|
||||
.filter-row-item {
|
||||
&:not(:last-child) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
.label {
|
||||
margin-right: 8px;
|
||||
color: #211f24;
|
||||
font-family: $font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
flex-shrink: 0;
|
||||
line-height: 22px; /* 157.143% */
|
||||
}
|
||||
:deep(.arco-space-item) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-28 10:33:06
|
||||
*/
|
||||
export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'name',
|
||||
width: 240,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: '项目预算',
|
||||
dataIndex: 'budget',
|
||||
width: 180,
|
||||
prefix: "¥"
|
||||
},
|
||||
{
|
||||
title: '关联平台账号',
|
||||
dataIndex: 'media_account_count',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '关联渠道账户',
|
||||
dataIndex: 'placement_account_count',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '关联内容稿件',
|
||||
dataIndex: 'work_count',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_at',
|
||||
width: 180,
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
@ -0,0 +1,63 @@
|
||||
<!--
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-26 17:44:16
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="删除项目"
|
||||
width="480px"
|
||||
modal-class="project-manage-modal"
|
||||
@close="onClose"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 {{ projectName }} 这个项目吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { deleteProject } from '@/api/all/propertyMarketing';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
const update = inject('update');
|
||||
|
||||
const visible = ref(false);
|
||||
const projectId = ref(null);
|
||||
const projectName = ref('');
|
||||
|
||||
const isBatch = computed(() => Array.isArray(projectId.value));
|
||||
|
||||
function onClose() {
|
||||
visible.value = false;
|
||||
projectId.value = null;
|
||||
projectName.value = '';
|
||||
}
|
||||
|
||||
const open = (record) => {
|
||||
const { id = null, name = '' } = record;
|
||||
projectId.value = id;
|
||||
projectName.value = name;
|
||||
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
async function onDelete() {
|
||||
const { code } = await deleteProject(projectId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
update()
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<a-table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
column-resizable
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="flex-1 project-table w-100%"
|
||||
bordered
|
||||
@sorter-change="handleSorterChange"
|
||||
>
|
||||
<template #empty>
|
||||
<NoData text="暂无项目"/>
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'create_at'" #cell="{ record }">
|
||||
{{ exactFormatTime(record.create_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<a-button type="outline" size="mini" @click="onEdit(record)">编辑</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else #cell="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
import { TABLE_COLUMNS } from './constants';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||
|
||||
const emits = defineEmits(['edit', 'sorterChange', 'delete']);
|
||||
|
||||
const props = defineProps({
|
||||
dataSource: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const tableRef = ref(null);
|
||||
|
||||
// 处理排序变化
|
||||
const handleSorterChange = (column, order) => {
|
||||
emits('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
|
||||
};
|
||||
const onDelete = (item) => {
|
||||
emits('delete', item);
|
||||
};
|
||||
const onEdit = (item) => {
|
||||
emits('edit', item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -0,0 +1,10 @@
|
||||
.project-table {
|
||||
.cts {
|
||||
color: var(--Text-1, #211f24);
|
||||
font-family: $font-family-medium;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
export const INITIAL_QUERY = {
|
||||
name: '',
|
||||
sort_column: undefined,
|
||||
sort_order: undefined,
|
||||
};
|
||||
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="project-list-wrap">
|
||||
<div class="filter-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid mb-16px">
|
||||
<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">
|
||||
<a-button type="primary" class="w-112px search-btn" size="medium" @click="handleOpenAddProjectModal">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="16" height="16" />
|
||||
</template>
|
||||
<template #default>添加项目</template>
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<FilterBlock v-model:query="query" @onSearch="handleSearch" @onReset="handleReset" />
|
||||
</div>
|
||||
<div
|
||||
class="table-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid px-24px py-24px flex-1 flex flex-col"
|
||||
>
|
||||
<ProjectTable
|
||||
:dataSource="dataSource"
|
||||
@sorterChange="handleSorterChange"
|
||||
@delete="handleDelete"
|
||||
@edit="handleEdit"
|
||||
/>
|
||||
<div v-if="pageInfo.total > 0" class="pagination-box">
|
||||
<a-pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AddProjectModal ref="addProjectModalRef" />
|
||||
<DeleteProjectModal ref="deleteProjectModalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { INITIAL_QUERY } from './constants';
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
import { getProjects } from '@/api/all/propertyMarketing';
|
||||
|
||||
import FilterBlock from './components/filter-block';
|
||||
import ProjectTable from './components/project-table';
|
||||
import AddProjectModal from './components/add-project-modal';
|
||||
import DeleteProjectModal from './components/project-table/delete-project-modal.vue';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-add.png';
|
||||
|
||||
const { dataSource, pageInfo, onPageChange, onPageSizeChange, resetPageInfo } = useTableSelectionWithPagination({
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
onPageSizeChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
|
||||
const addProjectModalRef = ref(null);
|
||||
const deleteProjectModalRef = ref(null);
|
||||
|
||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||
|
||||
const getData = async () => {
|
||||
const { page, page_size } = pageInfo.value;
|
||||
const { code, data } = await getProjects({
|
||||
...query.value,
|
||||
page,
|
||||
page_size,
|
||||
});
|
||||
if (code === 200) {
|
||||
dataSource.value = data?.data ?? [];
|
||||
pageInfo.value.total = data.total;
|
||||
}
|
||||
};
|
||||
const handleSearch = () => {
|
||||
reload();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
resetPageInfo();
|
||||
query.value = cloneDeep(INITIAL_QUERY);
|
||||
reload();
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
pageInfo.value.page = 1;
|
||||
getData();
|
||||
};
|
||||
|
||||
const handleOpenAddProjectModal = () => {
|
||||
addProjectModalRef.value?.open();
|
||||
};
|
||||
const handleSorterChange = (column, order) => {
|
||||
query.value.sort_column = column;
|
||||
query.value.sort_order = order;
|
||||
reload();
|
||||
};
|
||||
|
||||
const handleDelete = (item) => {
|
||||
const { id, name } = item;
|
||||
deleteProjectModalRef.value?.open({ id, name: `“${name}”` });
|
||||
};
|
||||
const handleEdit = (item) => {
|
||||
addProjectModalRef.value?.open(item.id);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
|
||||
provide('update', getData);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -0,0 +1,29 @@
|
||||
.project-list-wrap {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.filter-wrap {
|
||||
.top {
|
||||
.title {
|
||||
font-family: $font-family-medium;
|
||||
font-style: normal;
|
||||
}
|
||||
:deep(.arco-btn) {
|
||||
.arco-btn-icon {
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.table-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.pagination-box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 16px 24px;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,7 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<OperatorSelect v-model="query.operator_id" :options="operators" />
|
||||
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" />
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
@ -43,13 +43,13 @@
|
||||
<a-range-picker v-model="query.data_time" size="medium" allow-clear format="YYYY-MM-DD" class="w-100%" />
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
@ -74,13 +74,13 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import EchartsItem from './components/echarts-item/index';
|
||||
import { PLATFORM_LIST } from '../common_constants';
|
||||
import { PLATFORM_LIST } from '@/utils/platform';
|
||||
import {
|
||||
getPlacementAccountsTrend,
|
||||
getPlacementAccountProjectsTrend,
|
||||
fetchAccountOperators,
|
||||
} from '@/api/all/propertyMarketing';
|
||||
import OperatorSelect from '@/views/property-marketing/media-account/components/operator-select/index.vue';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
import AccountSelect from '@/views/components/common/AccountSelect.vue';
|
||||
import PlanSelect from '@/views/components/common/PlanSelect.vue';
|
||||
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<a-button class="w-110px search-btn mr-12px" size="medium" @click="handleExport">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleExport">
|
||||
<template #icon> <icon-download /> </template>
|
||||
<template #default>导出数据</template>
|
||||
</a-button>
|
||||
<a-button class="w-110px search-btn" size="medium" @click="openCustomColumn">
|
||||
<a-button type="outline" size="medium" @click="openCustomColumn">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="14" height="14" />
|
||||
</template>
|
||||
@ -106,7 +106,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<a-button type="outline" size="small" class="search-btn" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.isRateField" #cell="{ record }">
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<div v-if="!isAccountTab" class="filter-row-item flex items-center">
|
||||
<span class="label">计划分组</span>
|
||||
<a-space class="w-200px">
|
||||
<group-select v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
@ -31,7 +31,7 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,13 +55,13 @@
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
@ -78,10 +78,9 @@ import {
|
||||
getPlacementAccountsList,
|
||||
getPlacementAccountOperators,
|
||||
} from '@/api/all/propertyMarketing';
|
||||
import GroupSelect from '../group-select';
|
||||
|
||||
import OperatorSelect from '@/views/property-marketing/put-account/components/operator-select';
|
||||
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||
import AccountSelect from '@/views/property-marketing/put-account/components/account-select';
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<span>确认删除 "{{ groupName }}" 这个分组吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<a-button class="w-110px search-btn mr-12px" size="medium" @click="handleExport">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleExport">
|
||||
<template #icon> <icon-download /> </template>
|
||||
<template #default>导出数据</template>
|
||||
</a-button>
|
||||
<a-button class="w-110px search-btn" size="medium" @click="openCustomColumn">
|
||||
<a-button type="outline" size="medium" @click="openCustomColumn">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="14" height="14" />
|
||||
</template>
|
||||
@ -106,7 +106,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<a-button type="outline" size="small" class="search-btn" @click="handleDetail(record)">详情</a-button>
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.isRateField" #cell="{ record }">
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<a-tab-pane key="1" title="账户"></a-tab-pane>
|
||||
<a-tab-pane key="2" title="计划"></a-tab-pane>
|
||||
<template v-if="!isAccountTab" #extra>
|
||||
<a-button class="w-112px mr-12px search-btn flex items-center" size="medium" @click="handleOpenGroupModal">
|
||||
<a-button type="outline" class="mr-12px flex items-center" size="medium" @click="handleOpenGroupModal">
|
||||
<template #icon>
|
||||
<img :src="icon2" width="16" height="16" />
|
||||
</template>
|
||||
|
||||
@ -2,16 +2,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
.filter-wrap {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e6e6e8;
|
||||
|
||||
@ -2,10 +2,6 @@
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-26 17:44:16
|
||||
-->
|
||||
<!--
|
||||
* @Author: RenXiaoDong
|
||||
* @Date: 2025-06-26 17:23:52
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
@ -19,7 +15,7 @@
|
||||
<span>确认删除 {{ accountName }} 这个账户吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
|
||||
@ -41,6 +41,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">
|
||||
<a-tooltip
|
||||
v-if="item.projects.length > 2"
|
||||
position="bottom"
|
||||
:content="
|
||||
item.projects
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
.join(',')
|
||||
"
|
||||
>
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||
</div>
|
||||
</a-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 class="field-row">
|
||||
<span class="label">账户总消耗</span>
|
||||
<span class="cts">{{ `¥${formatNumberShow({ value: item.total_use_amount, showExactValue: true })}` }}</span>
|
||||
@ -53,17 +77,18 @@
|
||||
<img :src="icon1" width="16" height="16" class="mr-8px cursor-pointer" @click="openDelete(item)" />
|
||||
<a-button
|
||||
v-if="showPauseButton(item.status)"
|
||||
class="w-64px search-btn mr-8px"
|
||||
type="outline"
|
||||
class="mr-8px"
|
||||
size="mini"
|
||||
@click="handlePause(item)"
|
||||
>
|
||||
<template #default>暂停同步</template>
|
||||
</a-button>
|
||||
<a-button class="w-64px search-btn mr-8px" size="mini" @click="handleReauthorize(item)">
|
||||
<a-button type="outline" class="mr-8px" size="mini" @click="handleReauthorize(item)">
|
||||
<template #default>获取凭证</template>
|
||||
</a-button>
|
||||
|
||||
<a-button class="w-40px search-btn" size="mini" @click="openEdit(item)">
|
||||
<a-button type="outline" size="mini" @click="openEdit(item)">
|
||||
<template #default>编辑</template>
|
||||
</a-button>
|
||||
</div>
|
||||
@ -76,8 +101,8 @@
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, computed } from 'vue';
|
||||
import { PLATFORM_LIST } from '@/views/property-marketing/put-account/common_constants';
|
||||
import { EnumPutAccountStatus } from '@/views/property-marketing/put-account/components/status-select/constants';
|
||||
import { PLATFORM_LIST } from '@/utils/platform';
|
||||
import { EnumStatus } from '@/views/property-marketing/put-account/components/status-select/constants';
|
||||
|
||||
import { formatNumberShow, exactFormatTime } from '@/utils/tools';
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<span>确认暂停同步 “{{ accountName }}” 这个账号的数据吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px !bg-#f64b31" size="large" @click="onConfirm">确定</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
@mixin ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
|
||||
@ -111,6 +111,9 @@
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="所属项目" field="project_ids">
|
||||
<CommonSelect v-model="form.project_ids" :options="projects" placeholder="请选择…" size="large" />
|
||||
</a-form-item>
|
||||
<template v-if="isEdit">
|
||||
<a-form-item label="账户总消耗" field="total_use_amount">
|
||||
<a-input v-model="form.total_use_amount" placeholder="请输入..." size="large" disabled />
|
||||
@ -131,7 +134,7 @@
|
||||
</template>
|
||||
</a-form>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="onSubmit" :loading="importLoading">
|
||||
{{ confirmBtnText }}
|
||||
</a-button>
|
||||
@ -148,7 +151,9 @@ import { ref, defineEmits } from 'vue';
|
||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||
// import ImportPromptModal from '../import-prompt-modal';
|
||||
import StatusBox from '../status-box';
|
||||
import { PLATFORM_LIST, ENUM_PLATFORM } from '@/views/property-marketing/put-account/common_constants';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import { PLATFORM_LIST, ENUM_PUT_ACCOUNT_PLATFORM } from '@/utils/platform';
|
||||
|
||||
import { showExportNotification } from '@/utils/arcoD';
|
||||
import { genRandomId } from '@/utils/tools';
|
||||
@ -158,6 +163,7 @@ import {
|
||||
putPlacementAccounts,
|
||||
getPlacementAccountsTemplateUrl,
|
||||
batchPlacementAccounts,
|
||||
getProjectList,
|
||||
} from '@/api/all/propertyMarketing';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-download.png';
|
||||
@ -177,6 +183,7 @@ const INITIAL_FORM = {
|
||||
holder_name: '',
|
||||
platform: 0,
|
||||
is_sync_project: 1,
|
||||
project_ids: [],
|
||||
};
|
||||
|
||||
const visible = ref(false);
|
||||
@ -191,6 +198,7 @@ const authorizedAccountModalRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
const file = ref(null);
|
||||
const form = ref(cloneDeep(INITIAL_FORM));
|
||||
const projects = ref([]);
|
||||
const importLoading = ref(false);
|
||||
|
||||
const rules = {
|
||||
@ -245,6 +253,7 @@ const reset = () => {
|
||||
fileName.value = '';
|
||||
file.value = null;
|
||||
isEdit.value = false;
|
||||
projects.value = [];
|
||||
importLoading.value = false;
|
||||
uploadStatus.value = UploadStatus.DEFAULT;
|
||||
uploadType.value = 'manual';
|
||||
@ -258,12 +267,19 @@ const open = (accountId = '') => {
|
||||
id.value = accountId;
|
||||
isEdit.value = !!accountId;
|
||||
|
||||
getProjects();
|
||||
if (accountId) {
|
||||
getAccountDetail();
|
||||
}
|
||||
|
||||
visible.value = true;
|
||||
};
|
||||
const getProjects = async () => {
|
||||
const { code, data } = await getProjectList();
|
||||
if (code === 200) {
|
||||
projects.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
const getAccountDetail = async () => {
|
||||
const { code, data } = await getPlacementAccountsDetail(id.value);
|
||||
@ -308,7 +324,7 @@ const handleBatchImport = async () => {
|
||||
|
||||
const handleAdd = async () => {
|
||||
// 聚光无子账号
|
||||
if (form.value.platform === ENUM_PLATFORM.jg) {
|
||||
if (form.value.platform === ENUM_PUT_ACCOUNT_PLATFORM.jg) {
|
||||
const { code, data } = await postPlacementAccounts(form.value);
|
||||
if (code === 200) {
|
||||
update();
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="cancel-btn" @click="close">取消</a-button>
|
||||
<a-button size="large" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk">{{ confirmBtnText }} </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
@ -67,7 +67,6 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { defineExpose, ref, computed, defineEmits } from 'vue';
|
||||
import { exactFormatTime } from '@/utils/tools';
|
||||
import { ENUM_PLATFORM } from '@/views/property-marketing/put-account/common_constants';
|
||||
import {
|
||||
putPlacementAccountsAuthorized,
|
||||
getPlacementAccountsAuthorizedStatus,
|
||||
|
||||
@ -42,18 +42,24 @@
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<OperatorSelect v-model="query.operator_id" :options="operators" @change="handleSearch" />
|
||||
<CommonSelect v-model="query.operator_id" :multiple="false" :options="operators" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-row flex">
|
||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">所属项目</span>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" />
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
<a-button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
@ -65,10 +71,10 @@
|
||||
|
||||
<script setup>
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
import { getPlacementAccountOperators } from '@/api/all/propertyMarketing';
|
||||
import { PLATFORM_LIST } from '@/views/property-marketing/put-account/common_constants';
|
||||
import { getPlacementAccountOperators, getProjectList } from '@/api/all/propertyMarketing';
|
||||
import { PLATFORM_LIST } from '@/utils/platform';
|
||||
import StatusSelect from '@/views/property-marketing/put-account/components/status-select';
|
||||
import OperatorSelect from '@/views/property-marketing/put-account/components/operator-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
@ -80,6 +86,7 @@ const props = defineProps({
|
||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
|
||||
const operators = ref([]);
|
||||
const projects = ref([]);
|
||||
|
||||
const handleSearch = () => {
|
||||
emits('update:query', props.query);
|
||||
@ -97,9 +104,16 @@ const getOperators = async () => {
|
||||
operators.value = data;
|
||||
}
|
||||
};
|
||||
const getProjects = async () => {
|
||||
const { code, data } = await getProjectList();
|
||||
if (code === 200) {
|
||||
projects.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getOperators();
|
||||
getProjects();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" class="mr-16px cancel-btn" @click="close">取消</a-button>
|
||||
<a-button size="large" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk"> 去授权 </a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
|
||||
@ -103,7 +103,7 @@
|
||||
>已选<span class="color-#6D4CFE num mx-3px">{{ selectedRows.length }}个</span>账户</span
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
class="ml-16px"
|
||||
|
||||
@ -8,4 +8,5 @@ export const INITIAL_QUERY = {
|
||||
status: '',
|
||||
platform: '',
|
||||
operator_id: '',
|
||||
project_ids: [],
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<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">
|
||||
<a-button type="primary" class="w-112px search-btn" size="medium" @click="handleOpenAccountModal">
|
||||
<a-button type="primary" class="w-112px" size="medium" @click="handleOpenAccountModal">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="16" height="16" />
|
||||
</template>
|
||||
@ -53,7 +53,7 @@
|
||||
</template>
|
||||
<div v-else>
|
||||
<a-space v-if="isAbNormalStatus" class="flex items-center">
|
||||
<a-button class="w-96px err-btn" size="mini" @click="handleOpenAbnormalAccount">
|
||||
<a-button type="primary" status="danger" size="mini" @click="handleOpenAbnormalAccount">
|
||||
<template #default>查看异常账号</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
@ -79,7 +79,7 @@
|
||||
show-page-size
|
||||
:page-size-options="[8, 16, 20, 32, 64]"
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.pageSize"
|
||||
:page-size="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
@ -117,7 +117,7 @@ let queryTaskTimer = null;
|
||||
|
||||
const pageInfo = ref({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
page_size: 20,
|
||||
total: 0,
|
||||
});
|
||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||
@ -173,10 +173,10 @@ const getHealthData = async () => {
|
||||
}
|
||||
};
|
||||
const getAccountData = async () => {
|
||||
const { page, pageSize } = pageInfo.value;
|
||||
const { page, page_size } = pageInfo.value;
|
||||
const { code, data, total } = await getPlacementAccounts({
|
||||
page,
|
||||
page_size: pageSize,
|
||||
page_size,
|
||||
...query.value,
|
||||
});
|
||||
if (code === 200) {
|
||||
@ -189,11 +189,11 @@ const reload = () => {
|
||||
getData();
|
||||
};
|
||||
const handleSearch = () => {
|
||||
getData();
|
||||
reload();
|
||||
};
|
||||
const handleReset = () => {
|
||||
pageInfo.value.page = 1;
|
||||
pageInfo.value.pageSize = 20;
|
||||
pageInfo.value.page_size = 20;
|
||||
pageInfo.value.total = 0;
|
||||
selectedItems.value = [];
|
||||
query.value = cloneDeep(INITIAL_QUERY);
|
||||
@ -205,7 +205,7 @@ const onPageChange = (current) => {
|
||||
getData();
|
||||
};
|
||||
const onPageSizeChange = (pageSize) => {
|
||||
pageInfo.value.pageSize = pageSize;
|
||||
pageInfo.value.page_size = pageSize;
|
||||
reload();
|
||||
};
|
||||
|
||||
|
||||
@ -2,16 +2,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
}
|
||||
:deep(.reset-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--BG-500, #b1b2b5);
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
.filter-wrap {
|
||||
.top {
|
||||
.title {
|
||||
@ -41,15 +31,6 @@
|
||||
color: #211f24;
|
||||
}
|
||||
}
|
||||
.err-btn {
|
||||
background-color: #f64b31 !important;
|
||||
color: var(--BG-white, #fff);
|
||||
font-family: 'PingFang SC';
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 166.667% */
|
||||
}
|
||||
.operation-btn {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user