Merge branch 'feature/v1.3_营销资产中台' of http://gogs.lvfunai.com:444/ai-team/lingji-work-fe into feature/v1.3_营销资产中台

This commit is contained in:
林志军
2025-06-27 16:26:19 +08:00
13 changed files with 408 additions and 43 deletions

View File

@ -95,3 +95,13 @@ export const deleteTag = (id: string) => {
export const batchDeleteMediaAccounts = (params = {}) => { export const batchDeleteMediaAccounts = (params = {}) => {
return Http.delete(`/v1/media-accounts/batch`, params); return Http.delete(`/v1/media-accounts/batch`, params);
}; };
// 媒体账号-批量标签
export const batchPutTag = (params = {}) => {
return Http.put(`/v1/media-accounts/batch-tag`, params);
};
// 媒体账号-批量分组
export const batchPutGroup = (params = {}) => {
return Http.put(`/v1/media-accounts/batch-group`, params);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

View File

@ -12,19 +12,30 @@
} }
} }
.arco-modal { .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-header { .arco-modal-header {
border-bottom: none; border-bottom: 1px solid var(--Border-1, #d7d7d9);
height: 56px; height: 56px;
padding: 22px 24px 16px 24px; padding: 0 20px;
.arco-modal-title { .arco-modal-title {
justify-content: flex-start; justify-content: flex-start;
} }
} }
.arco-modal-body { .arco-modal-body {
padding: 24px 24px 20px; padding: 24px 20px;
.arco-form-item { .arco-form-item {
margin-bottom: 16px; margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
.arco-form-item-label { .arco-form-item-label {
color: var(--Text-1, #211f24); color: var(--Text-1, #211f24);
font-family: 'Alibaba PuHuiTi'; font-family: 'Alibaba PuHuiTi';
@ -34,15 +45,14 @@
line-height: 22px; /* 157.143% */ line-height: 22px; /* 157.143% */
} }
} }
.cancel-btn {
border-radius: 4px;
border: 1px solid var(--BG-500, #b1b2b5);
background: var(--BG-white, #fff);
}
} }
.arco-modal-footer { .arco-modal-footer {
border-top: none; display: flex;
padding: 0; height: 64px;
padding: 0px 20px;
justify-content: flex-end;
align-items: center;
border-top: 1px solid var(--Border-1, #d7d7d9);
} }
} }

View File

@ -11,20 +11,19 @@
v-model:visible="visible" v-model:visible="visible"
:title="isBatch ? '批量删除账号' : '删除账号'" :title="isBatch ? '批量删除账号' : '删除账号'"
width="400px" width="400px"
:footer="false"
modal-class="account-manage-modal" modal-class="account-manage-modal"
@close="onClose" @close="onClose"
> >
<div class="flex items-center mb-24px"> <div class="flex items-center">
<img :src="icon1" width="20" height="20" class="mr-12px" /> <img :src="icon1" width="20" height="20" class="mr-12px" />
<span>确认删除 {{ accountName }} 这个账号吗</span> <span>确认删除 {{ accountName }} 这个账号吗</span>
</div> </div>
<div class="text-right"> <template #footer>
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button> <a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete" <a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
>确认删除</a-button >确认删除</a-button
> >
</div> </template>
</a-modal> </a-modal>
</template> </template>

View File

@ -7,7 +7,6 @@
v-model:visible="visible" v-model:visible="visible"
:title="isEdit ? '编辑账号' : '添加账号'" :title="isEdit ? '编辑账号' : '添加账号'"
modal-class="add-account-modal" modal-class="add-account-modal"
:footer="false"
width="500px" width="500px"
:mask-closable="false" :mask-closable="false"
> >
@ -82,14 +81,13 @@
<TagSelect v-model="form.tag_ids" :options="tagOptions" placeholder="请选择…" size="large" /> <TagSelect v-model="form.tag_ids" :options="tagOptions" placeholder="请选择…" size="large" />
</a-form-item> </a-form-item>
</template> </template>
<div class="mt-24px text-right">
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" size="large" @click="onSubmit">
{{ isBatchImport ? '确定导入' : '生成授权码' }}
</a-button>
</div>
</a-form> </a-form>
<template #footer>
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" size="large" @click="onSubmit">
{{ isBatchImport ? '确定导入' : '生成授权码' }}
</a-button>
</template>
<QrCodeModal ref="qrCodeModalRef" /> <QrCodeModal ref="qrCodeModalRef" />
<ImportPromptModal ref="importPromptModalRef" /> <ImportPromptModal ref="importPromptModalRef" />

View File

@ -0,0 +1,142 @@
<!--
* @Author: RenXiaoDong
* @Date: 2025-06-27 09:35:49
-->
<template>
<a-modal
v-model:visible="visible"
title="批量分组"
modal-class="batch-group-modal"
width="800px"
:mask-closable="false"
>
<div class="mb-16px t1">
{{ `已选${accountGroupList.length}个账号` }}
</div>
<a-form ref="formRef" :model="form" layout="horizontal" auto-label-width>
<a-form-item label="编辑方式" required>
<a-radio-group v-model="editType">
<a-radio value="all">
<div class="flex items-center">
<span>统一编辑</span>
<a-tooltip content="原分组将被清除,统一加入新分组。">
<img :src="icon1" alt="icon" class="ml-2px" width="14" height="14" />
</a-tooltip>
</div>
</a-radio>
<a-radio value="each">分别编辑</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="选择分组" required>
<template v-if="editType === 'all'">
<div class="flex items-center w-100%">
<a-select v-model="form.group_id" :options="groupOptions" placeholder="请选择..." class="flex-1" />
</div>
</template>
</a-form-item>
<!-- 分别编辑 -->
<template v-if="editType === 'each'">
<a-table :data="accountGroupList" :pagination="false" row-key="id" class="w-100%">
<template #columns>
<a-table-column title="账号名称" data-index="name" width="200" />
<a-table-column title="选择分组" data-index="group_id">
<template #cell="{ record }">
<div class="flex items-center w-100%">
<a-select v-model="record.group_id" :options="groupOptions" placeholder="请选择..." />
</div>
</template>
</a-table-column>
</template>
</a-table>
</template>
</a-form>
<template #footer>
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
</template>
</a-modal>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { fetchAccountGroups, batchPutGroup } from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/icon-question.png';
// [{id, name, group_id: null}]
const emits = defineEmits(['update']);
const visible = ref(false);
const groupOptions = ref([]);
const formRef = ref();
const editType = ref('all');
const form = reactive({
group_id: null,
});
const accounts = ref([]); // [{id, name}]
const accountGroupList = ref([]); // [{id, name, group_id: null}]
const open = (accountList = []) => {
editType.value = 'all';
groupOptions.value = [];
form.group_id = null;
accounts.value = accountList;
accountGroupList.value = accountList.map((acc) => ({
...acc,
group_id: null,
}));
visible.value = true;
getTags();
};
const getTags = async () => {
groupOptions.value = [
{
label: '测试',
value: '1',
},
{
label: 'ceshi2',
value: 2,
},
];
const { code, data } = await fetchAccountGroups();
if (code === 200) {
groupOptions.value = data.map((item) => ({
label: item.name,
value: item.id,
}));
}
};
const onClose = () => {
visible.value = false;
form.tag_ids = [];
};
const onSubmit = async () => {
// 这里处理批量标签的提交逻辑
const _params =
editType.value === 'all'
? { id: -1, group_id: form.group_id }
: accountGroupList.value.map((item) => ({
id: item.id,
group_id: item.group_id,
}));
const { code } = await batchPutGroup({ media_accounts: _params });
if (code === 200) {
AMessage.success('批量分组成功');
emits('update');
visible.value = false;
}
};
defineExpose({ open });
</script>
<style lang="scss">
@import './style.scss';
</style>

View File

@ -0,0 +1,16 @@
@import '@/views/property-marketing/component.scss';
.batch-group-modal {
border-radius: 8px;
.arco-modal-body {
// min-height: 200px;
.t1 {
color: var(--Text-3, #737478);
font-family: 'Alibaba PuHuiTi';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px; /* 157.143% */
}
}
}

View File

@ -0,0 +1,171 @@
<!--
* @Author: RenXiaoDong
* @Date: 2025-06-27 09:35:49
-->
<template>
<a-modal
v-model:visible="visible"
title="批量标签"
modal-class="batch-tag-modal"
width="800px"
:mask-closable="false"
>
<div class="mb-16px t1">
{{ `已选${accountTagList.length}个账号` }}
</div>
<a-form ref="formRef" :model="form" layout="horizontal" auto-label-width>
<a-form-item label="编辑方式" required>
<a-radio-group v-model="editType">
<a-radio value="all">
<div class="flex items-center">
<span>统一编辑</span>
<a-tooltip content="原标签将被清除,统一为新标签。">
<img :src="icon1" alt="icon" class="ml-2px" width="14" height="14" />
</a-tooltip>
</div>
</a-radio>
<a-radio value="each">分别编辑</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="选择标签" required>
<template v-if="editType === 'all'">
<div class="flex items-center w-100%">
<a-select
v-model="form.tag_ids"
:options="tagOptions"
multiple
allow-create
placeholder="请输入标签,回车键可直接添加..."
:limit="5"
class="flex-1"
@create="handleCreateTag"
/>
<span class="ml-12px">{{ `${form.tag_ids.length}/5` }}</span>
</div>
</template>
</a-form-item>
<!-- 分别编辑 -->
<template v-if="editType === 'each'">
<a-table :data="accountTagList" :pagination="false" row-key="id" class="w-100%">
<template #columns>
<a-table-column title="账号名称" data-index="name" width="200" />
<a-table-column title="选择标签" data-index="tags">
<template #cell="{ record, rowIndex }">
<div class="flex items-center w-100%">
<a-select
v-model="record.tags"
:options="tagOptions"
multiple
allow-create
placeholder="请输入标签,回车键可直接添加..."
:limit="5"
style="width: 90%"
@create="(val) => handleCreateTag(val, rowIndex)"
/>
<span class="tag-count ml-8px">{{ record.tags.length }}/5</span>
</div>
</template>
</a-table-column>
</template>
</a-table>
</template>
</a-form>
<template #footer>
<a-button size="large" class="mr-16px cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
</template>
</a-modal>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { fetchAccountTags, batchPutTag } from '@/api/all/propertyMarketing';
import icon1 from '@/assets/img/icon-question.png';
const emits = defineEmits(['update']);
const visible = ref(false);
const tagOptions = ref([]);
const formRef = ref();
const editType = ref('all');
const form = reactive({
tag_ids: [],
});
const accounts = ref([]); // [{id, name}]
const accountTagList = ref([]); // [{id, name, tags: []}]
// 打开弹窗时请求标签数据
const open = (accountList = []) => {
editType.value = 'all';
tagOptions.value = [];
form.tag_ids = [];
accounts.value = accountList;
accountTagList.value = accountList.map((acc) => ({
...acc,
tags: [],
}));
visible.value = true;
getTags();
};
const getTags = async () => {
tagOptions.value = [
{
label: '测试',
value: '1',
},
{
label: 'ceshi2',
value: 2,
},
];
const { code, data } = await fetchAccountTags();
if (code === 200) {
tagOptions.value = data.map((item) => ({
label: item.name,
value: item.id,
}));
}
};
// 允许回车创建新标签
const handleCreateTag = (inputValue, idx) => {
const newTag = { label: inputValue, value: inputValue };
tagOptions.value.push(newTag);
if (typeof idx === 'number') {
accountTagList.value[idx].tags.push(inputValue);
} else {
form.tag_ids.push(inputValue);
}
};
const onClose = () => {
visible.value = false;
form.tag_ids = [];
};
const onSubmit = async () => {
const _params =
editType.value === 'all'
? { tag_ids: form.tag_ids }
: accountTagList.value.map((item) => ({
id: item.id,
tag_ids: item.tags,
}));
const { code } = await batchPutTag({ media_accounts: _params });
if (code === 200) {
AMessage.success('批量标签成功');
emits('update');
visible.value = false;
}
};
defineExpose({ open });
</script>
<style lang="scss">
@import './style.scss';
</style>

View File

@ -0,0 +1,16 @@
@import '@/views/property-marketing/component.scss';
.batch-tag-modal {
border-radius: 8px;
.arco-modal-body {
// min-height: 200px;
.t1 {
color: var(--Text-3, #737478);
font-family: 'Alibaba PuHuiTi';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px; /* 157.143% */
}
}
}

View File

@ -8,18 +8,17 @@
:title="isEdit ? '编辑分组' : '添加新分组'" :title="isEdit ? '编辑分组' : '添加新分组'"
modal-class="account-manage-modal" modal-class="account-manage-modal"
width="400px" width="400px"
:footer="false"
@close="onClose" @close="onClose"
> >
<a-form ref="formRef" :model="form" :rules="rules" layout="horizontal" auto-label-width> <a-form ref="formRef" :model="form" :rules="rules" layout="horizontal" auto-label-width>
<a-form-item :label="isEdit ? '分组名称' : '新分组名称'" field="name" required> <a-form-item :label="isEdit ? '分组名称' : '新分组名称'" field="name" required>
<a-input v-model="form.name" placeholder="请输入…" /> <a-input v-model="form.name" placeholder="请输入…" />
</a-form-item> </a-form-item>
<div class="text-right">
<a-button class="cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
</div>
</a-form> </a-form>
<template #footer>
<a-button class="cancel-btn" @click="onClose">取消</a-button>
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
</template>
</a-modal> </a-modal>
</template> </template>

View File

@ -3,24 +3,17 @@
* @Date: 2025-06-26 11:45:05 * @Date: 2025-06-26 11:45:05
--> -->
<template> <template>
<a-modal <a-modal v-model:visible="visible" title="删除分组" width="400px" modal-class="account-manage-modal" @close="onClose">
v-model:visible="visible"
title="删除分组"
width="400px"
:footer="false"
modal-class="account-manage-modal"
@close="onClose"
>
<div class="flex items-center mb-24px"> <div class="flex items-center mb-24px">
<img :src="icon1" width="20" height="20" class="mr-12px" /> <img :src="icon1" width="20" height="20" class="mr-12px" />
<span>确认删除 "{{ groupName }}" 这个分组吗</span> <span>确认删除 "{{ groupName }}" 这个分组吗</span>
</div> </div>
<div class="text-right"> <template #footer>
<a-button class="cancel-btn" size="large" @click="onClose">取消</a-button> <a-button class="cancel-btn" size="large" @click="onClose">取消</a-button>
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete" <a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
>确认删除</a-button >确认删除</a-button
> >
</div> </template>
</a-modal> </a-modal>
</template> </template>

View File

@ -8,7 +8,6 @@
width="480px" width="480px"
title="导入提示" title="导入提示"
modal-class="import-prompt-modal" modal-class="import-prompt-modal"
:footer="false"
:mask-closable="false" :mask-closable="false"
@close="close" @close="close"
> >
@ -17,12 +16,11 @@
<img :src="icon1" width="20" height="20" class="mr-12px" /> <img :src="icon1" width="20" height="20" class="mr-12px" />
<span class="tip"> 账号已成功导入当前为未授权状态请前往卡片列表手动授权完成授权后账号可正常使用 </span> <span class="tip"> 账号已成功导入当前为未授权状态请前往卡片列表手动授权完成授权后账号可正常使用 </span>
</div> </div>
<div class="mt-24px text-right w-100%">
<a-button size="large" class="mr-16px cancel-btn" @click="close">取消</a-button>
<a-button type="primary" size="large" @click="handleOk"> 去授权 </a-button>
</div>
</div> </div>
<template #footer>
<a-button size="large" class="mr-16px cancel-btn" @click="close">取消</a-button>
<a-button type="primary" size="large" @click="handleOk"> 去授权 </a-button>
</template>
</a-modal> </a-modal>
</template> </template>

View File

@ -104,6 +104,8 @@
<TagsManageModal ref="tagsManageModalRef" /> <TagsManageModal ref="tagsManageModalRef" />
<AddAccountModal ref="addAccountModalRef" /> <AddAccountModal ref="addAccountModalRef" />
<DeleteAccountModal ref="deleteAccountRef" @update="getData" /> <DeleteAccountModal ref="deleteAccountRef" @update="getData" />
<BatchTagModal ref="batchTagModalRef" @update="getData" />
<BatchGroupModal ref="batchGroupModalRef" @update="getData" />
</div> </div>
</template> </template>
@ -116,6 +118,8 @@ import GroupManageModal from './components/group-manage-modal';
import TagsManageModal from './components/tags-manage-modal'; import TagsManageModal from './components/tags-manage-modal';
import AddAccountModal from './components/add-account-modal'; import AddAccountModal from './components/add-account-modal';
import DeleteAccountModal from './components/account-table/delete-account'; import DeleteAccountModal from './components/account-table/delete-account';
import BatchTagModal from './components/batch-tag-modal';
import BatchGroupModal from './components/batch-group-modal';
import { INITIAL_QUERY } from './constants'; import { INITIAL_QUERY } from './constants';
import { getMediaAccounts } from '@/api/all/propertyMarketing'; import { getMediaAccounts } from '@/api/all/propertyMarketing';
@ -131,6 +135,8 @@ const groupManageModalRef = ref(null);
const tagsManageModalRef = ref(null); const tagsManageModalRef = ref(null);
const addAccountModalRef = ref(null); const addAccountModalRef = ref(null);
const deleteAccountRef = ref(null); const deleteAccountRef = ref(null);
const batchTagModalRef = ref(null);
const batchGroupModalRef = ref(null);
const tipStatus = ref(2); const tipStatus = ref(2);
const pageInfo = reactive({ const pageInfo = reactive({
@ -266,6 +272,13 @@ const handleDelete = (item) => {
const handleCloseTip = () => { const handleCloseTip = () => {
selectedItems.value = []; selectedItems.value = [];
}; };
const handleBatchTag = () => {
batchTagModalRef.value?.open(selectedItems.value);
};
const handleBatchGroup = () => {
batchGroupModalRef.value?.open(selectedItems.value);
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">