123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- <script lang="ts" setup>
- /**
- * @Name: adActivityDialog.vue
- * @Description:广告关联活动弹窗
- * @Author: xinyan
- */
- import { computed, onMounted, ref, watch } from 'vue';
- import { getAdGroupList, getRelationCampaign } from '/@/views/efTools/automation/api';
- import { storeToRefs } from 'pinia';
- import { useShopInfo } from '/@/stores/shopInfo';
- import { ElMessage } from 'element-plus';
- const props = defineProps({
- templateId: {
- type: [String, Number],
- required: true,
- },
- activeModel: {
- type: String,
- },
- modelValue: {
- type: Boolean,
- required: true,
- },
- });
- const emits = defineEmits(['update:modelValue']);
- const shopInfo = useShopInfo();
- const { profile } = storeToRefs(shopInfo);
- const { templateId } = toRefs(props);
- const { activeModel } = toRefs(props);
- const dialogVisible = ref(props.modelValue);
- //筛选条件
- const searchAdCampaign = ref('');
- const selectedCampaignType = ref('sp');
- const selectedAdGroup = ref('');
- const selectedStatus = ref('');
- const adCampaignName = ref([]);
- const campaignType = [
- { value: 'sb', label: 'SB' },
- { value: 'sp', label: 'SP' },
- { value: 'sd', label: 'SD' },
- ];
- const adGroups = ref([]);
- const campaignStatus = [
- { value: 0, label: '未存档' },
- { value: 'ENABLED', label: '已启用' },
- { value: 'PAUSED', label: '已暂停' },
- ];
- //表格
- const currentPage = ref(1);
- const pageSize = ref(25);
- const total = ref(0);
- const loading = ref(false);
- const refTable = ref(null);
- let selectedAds = ref([]);
- let selections = []; // 添加选中的项
- function handleCurrentChange(newPage) {
- currentPage.value = newPage;
- loading.value = true;
- fetchAdCampaign();
- }
- // 处理分页器每页显示条目数变化
- function handleSizeChange(newSize) {
- pageSize.value = newSize;
- currentPage.value = 1;
- fetchAdCampaign();
- }
- let isRestoringSelection = false;
- async function fetchAdCampaign() {
- try {
- loading.value = true;
- const cachedSelectedAds = [...selectedAds.value];
- const resp = await getRelationCampaign({
- profileId: profile.value.profile_id,
- templateId: templateId.value,
- campaignName: searchAdCampaign.value,
- portfolioId: selectedAdGroup.value,
- campaignStatus: selectedStatus.value,
- campaignType: selectedCampaignType.value,
- page: currentPage.value,
- limit: pageSize.value,
- });
- adCampaignName.value = resp.data;
- total.value = resp.total;
- currentPage.value = resp.page;
- // 开始恢复勾选状态
- isRestoringSelection = true;
- nextTick(() => {
- adCampaignName.value.forEach(item => {
- if (cachedSelectedAds.some(ad => ad.campaignId === item.campaignId)) {
- refTable.value.toggleRowSelection(item, true);
- }
- });
- isRestoringSelection = false;
- });
- } catch (error) {
- ElMessage.error('请求广告活动数据失败');
- } finally {
- loading.value = false;
- }
- }
- function handleSelectionChange(selection) {
- if (isRestoringSelection) return; // 恢复勾选时跳过该方法
- selections = selection;
- const newSelections = selections.filter(
- (sel) => !selectedAds.value.some((added) => added.campaignId === sel.campaignId)
- );
- if (newSelections.length > 0) {
- selectedAds.value.push(...newSelections);
- }
- // 处理取消选中的项
- const removedSelections = selectedAds.value.filter(
- (added) => !selections.some((sel) => sel.campaignId === added.campaignId)
- );
- if (removedSelections.length > 0) {
- selectedAds.value = selectedAds.value.filter(
- (added) => !removedSelections.some((removed) => removed.campaignId === added.campaignId)
- );
- }
- }
- function removeSelectedAd(index) {
- const removedAd = selectedAds.value.splice(index, 1)[0];
- const targetIndex = adCampaignName.value.findIndex(ad => ad.campaignName === removedAd.campaignName);
- if (targetIndex !== -1) {
- const adTable = refTable.value;
- adTable.toggleRowSelection(adCampaignName.value[targetIndex], false);
- }
- }
- function removeAllSelectedAds() {
- const adTable = refTable.value;
- selectedAds.value.forEach(ad => {
- const targetIndex = adCampaignName.value.findIndex(item => item.campaignName === ad.campaignName);
- if (targetIndex !== -1) {
- adTable.toggleRowSelection(adCampaignName.value[targetIndex], false);
- }
- });
- selectedAds.value = [];
- }
- function cancel() {
- dialogVisible.value = false;
- }
- //TODO: 确认按钮
- async function confirm() {
- const campaignItems = selectedAds.value.map(ad => ({
- campaignId: ad.campaignId,
- campaignType: ad.campaignType
- }));
- const adGroupInfo = [];
- const campaignTargetInfo = [
- { targetId: '492707808377423', adGroup_id: '448117369011017', bid: 0.45 },
- ];
- const campaignKeywordInfo = [
- { keywordId: '416969576305724', adGroup_id: '393554556566271', bid: 0.04 },
- ];
- const requestData = {
- profileId: profile.value.profile_id,
- templateId: templateId.value,
- campaignItems,
- adGroupInfo,
- campaignTargetInfo,
- campaignKeywordInfo
- };
- //console.log('requestData', requestData);
- }
- // 获取广告组下拉框
- async function fetchAdGroupList() {
- try {
- const resp = await getAdGroupList({
- profileId: profile.value.profile_id,
- });
- adGroups.value = resp.data.map((item: any) => {
- return {
- label: item.name,
- value: item.portfolioId
- };
- });
- } catch (error) {
- ElMessage.error('请求失败');
- }
- }
- const headerCellStyle = (args) => {
- if (args.rowIndex === 0) {
- return {
- backgroundColor: 'rgba(245, 245, 245, 0.9)',
- fontWeight: '500',
- };
- }
- };
- const cellStyle = () => {
- return {
- fontSize: '13px',
- //fontWeight: '500',
- };
- };
- //监控筛选条件变化
- watch(selectedCampaignType, () => {
- fetchAdCampaign();
- });
- watch(selectedAdGroup, (newVal) => {
- if (newVal) {
- selectedAdGroup.value = newVal;
- fetchAdCampaign();
- }
- });
- watch(selectedStatus, () => {
- fetchAdCampaign();
- });
- watch(templateId, () => {
- fetchAdCampaign();
- fetchAdGroupList();
- });
- watch(() => props.modelValue, (newValue) => {
- dialogVisible.value = newValue;
- });
- watch(dialogVisible, (newValue) => {
- emits('update:modelValue', newValue);
- });
- const treeProps = computed(() => {
- if (activeModel.value === 'adGroup' || activeModel.value === 'specified') {
- return { children: 'campaignGroupInfo' };
- }
- return {};
- });
- onMounted(() => {
- //fetchAdGroupList();
- });
- </script>
- <template>
- <el-dialog
- v-model="dialogVisible"
- class="custom-dialog"
- style="border-radius: 10px;"
- title="关联广告活动"
- width="1158px"
- >
- <div class="container">
- <div class="container-left">
- <el-input v-model="searchAdCampaign" placeholder="请输入广告活动" style="width: 100%;"
- @change="fetchAdCampaign()"></el-input>
- <div class="custom-inline">
- <el-select v-model="selectedCampaignType" placeholder="选择广告类型">
- <el-option v-for="item in campaignType"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- ></el-option>
- </el-select>
- <el-select v-model="selectedAdGroup" clearable placeholder="广告组合" style="margin-bottom: 10px;">
- <el-option
- v-for="item in adGroups"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- ></el-option>
- </el-select>
- <el-select v-model="selectedStatus" placeholder="状态" style="margin-bottom: 10px;">
- <el-option
- v-for="item in campaignStatus"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- ></el-option>
- </el-select>
- </div>
- <el-table
- ref="refTable"
- v-loading="loading"
- :cell-style="cellStyle"
- :data="adCampaignName"
- :row-key="'campaignId'"
- :header-cell-style="headerCellStyle"
- height="400"
- style="width: 100%;"
- :tree-props="treeProps"
- v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
- @selection-change="handleSelectionChange"
- >
- <el-table-column label="广告活动名称">
- <template #default="scope">
- <el-tag
- v-if="scope.row.campaignType"
- :color="scope.row.campaignType === 'sb' ? '#0163d2' : (scope.row.campaignType === 'sp' ? '#ff7424' : '#365672')"
- class="campaign-type"
- disable-transitions
- round>
- {{ scope.row.campaignType }}
- </el-tag>
- {{ scope.row.campaignName }}
- {{ scope.row.adGroupName }}
- </template>
- </el-table-column>
- <el-table-column type="selection" width="55"></el-table-column>
- </el-table>
- <div class="pagination-container mt-4">
- <el-pagination
- v-model:current-page="currentPage"
- :page-size="pageSize"
- :page-sizes="[10, 25, 50,100,200]"
- :total="total"
- background
- layout="total,sizes,prev, next, jumper"
- small
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
- </div>
- <div class="container-right">
- <h3>已选择({{ selectedAds.length }})</h3>
- <el-table
- :cell-style="cellStyle"
- :data="selectedAds"
- :header-cell-style="headerCellStyle"
- height="484"
- :tree-props="treeProps"
- v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
- style="width: 100%; margin-top: 20px;"
- >
- <el-table-column label="广告活动" prop="campaignName">
- <template #default="scope">
- <el-tag
- v-if="scope.row.campaignType"
- :color="scope.row.campaignType === 'sb' ? '#0163d2' : (scope.row.campaignType === 'sp' ? '#ff7424' : '#365672')"
- class="campaign-type"
- disable-transitions
- round>
- {{ scope.row.campaignType }}
- </el-tag>
- {{ scope.row.campaignName }}
- {{ scope.row.adGroupName }}
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- label="操作"
- width="100"
- >
- <template #header>
- <el-button link size="default" style="color: #2077d7" @click="removeAllSelectedAds">删除全部</el-button>
- </template>
- <template #default="scope">
- <el-button type="text" @click="removeSelectedAd(scope.$index)">
- <CircleClose style="width:16px;color:#4b5765" />
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="cancel">取消</el-button>
- <el-button type="primary" @click="confirm">确定</el-button>
- </div>
- </template>
- </el-dialog>
- </template>
- <style scoped>
- .pagination-container {
- display: flex;
- flex-direction: row-reverse;
- }
- .custom-inline {
- display: flex;
- justify-content: space-around;
- margin: 12px 0;
- gap: 4px;
- }
- .campaign-type {
- width: 35px;
- text-align: center;
- height: 22px;
- font-size: 13px;
- font-weight: 400;
- color: #fff;
- border-color: #fff;
- line-height: 22px;
- border-radius: 12px;
- margin-right: 4px;
- }
- .container {
- width: 100%;
- height: 100%;
- border: 1px solid #d6dbe2;
- border-radius: 4px;
- display: flex;
- overflow: hidden;
- align-content: center;
- flex-wrap: nowrap;
- flex-direction: row;
- /* padding: 10px; */
- }
- .container-left {
- width: 50%;
- border-right: 1px solid #d6dbe2;
- padding: 15px
- }
- .container-right {
- flex: 1;
- padding: 15px
- }
- </style>
|