123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- <template>
- <div class="customize-container">
- <el-card body-style="padding: 20px 80px 0 80px;">
- <div class="custom-card-title">
- <span class="custom-card-icon">|</span>
- <span class="custom-card-Text">自定义定向</span>
- </div>
- <div class="main-container">
- <div class="left-container">
- <el-tabs v-model="topTabName" class="demo-tabs" @tab-click="handleClick">
- <div class="tab-container-fixed-top">
- <span class="tab-top-label">添加定向时的竞价设置: </span>
- <el-select v-model="bidType">
- <el-option v-for="item in bidTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- <el-input v-model="bid" :disabled="bidType == '1'" style="width: 200px">
- <template #prepend>$</template>
- </el-input>
- </div>
- <el-tab-pane label="亚马逊受众" name="audience">
- <div>
- <div style="display: flex">
- <el-select v-model="audienceType" @change="handleSearchChange" style="width: 140px; margin-right: 10px">
- <el-option v-for="item in audienceTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- <el-input v-model="keywordInput" @change="handleSearchChange" placeholder="请输入关键词进行过滤"></el-input>
- </div>
- <hr style="margin-top: 5px" />
- <el-table
- :data="searchData"
- :row-key="(item) => item.audienceId"
- :show-header="false"
- v-loading="searchLoading"
- height="550"
- style="width: 100%">
- <el-table-column prop="date" label="Date">
- <template #default="{ row }">
- <div style="font-weight: 500; color: #000">{{ row.category }}</div>
- <div style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden">{{ row.audienceName }}</div>
- <div style="color: rgba(0, 0, 0, 0.45)">预估人数: {{ row.lowerBoundInclusive }} - {{ row.upperBoundExclusive }}</div>
- </template>
- </el-table-column>
- <el-table-column prop="opotion" label="option" width="80">
- <template #default="{ row }">
- <el-button type="primary" size="small" link @click="handleAddButtonClick(row)">添加</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </el-tab-pane>
- <el-tab-pane label="浏览再营销" name="views">
- <div class="tab-title">触达浏览过您推广的商品或其他类似商品、商品品类、品牌以及其他商品功能的顾客</div>
- <el-tabs v-model="viewsTabName" type="border-card">
- <div class="el-row align-center-bottom">
- <span class="select-label">回溯期: </span>
- <el-select v-model="viewsLookBack">
- <el-option v-for="item in viewsLookBackOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </div>
- <el-tab-pane label="建议" name="advice">
- <div style="height: 450px">
- <div>动态细分</div>
- <hr style="margin: 5px 0" />
- <div>
- <div style="display: flex; justify-content: space-between">
- <div>推广商品</div>
- <el-button type="primary" size="small" link @click="addPromoteProduct">添加</el-button>
- </div>
- <div style="display: flex; justify-content: space-between">
- <div>与推广商品类似的商品</div>
- <el-button type="primary" size="small" link @click="addPromoteSimilar">添加</el-button>
- </div>
- </div>
- </div>
- </el-tab-pane>
- <el-tab-pane label="搜索" name="search">
- <BrowseSearch @add-to-table="browseOrientation" @form-submitted="browseRefine"></BrowseSearch>
- </el-tab-pane>
- </el-tabs>
- </el-tab-pane>
- <el-tab-pane label="购买再营销" name="purchases">
- <div class="tab-title">向购买过广告商品或其他相关商品、商品类别、品牌及其他商品功能的购买者传递信息</div>
- <el-tabs v-model="purchasesTabName" type="border-card">
- <div class="el-row align-center-bottom">
- <span class="select-label">回溯期: </span>
- <el-select v-model="purchasesLookBack">
- <el-option v-for="item in purchasesLookBackOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </div>
- <el-tab-pane label="建议" name="advice">
- <div style="height: 450px"></div>
- </el-tab-pane>
- <el-tab-pane label="搜索" name="search">
- <BuySearch @add-to-table="buyOrientation" @form-submitted="buyRefine"></BuySearch>
- </el-tab-pane>
- </el-tabs>
- </el-tab-pane>
- </el-tabs>
- </div>
- <!-- 右侧内容区 -->
- <div class="right-container">
- <div class="right-container-top">
- <div style="padding-left: 15px; font-size: 15px">
- <span style="color: #8e9095">已添加: </span> <span style="font-weight: 500">{{ addedTableData.length }}</span>
- </div>
- <el-button link type="danger" @click="handleDeleteAll" style="margin-right: 15px">删除所有</el-button>
- </div>
- <el-table :data="addedTableData" :header-cell-style="changeTableHeader" height="600" style="width: 100%">
- <el-table-column prop="date" label="商品">
- <template #default="{ row }">
- <div v-if="row.cna || row.dialogTitle">浏览再营销</div>
- <div v-if="row.cna || row.dialogTitle">
- 分类: <span style="color: black">{{ row.cna ? row.cna : row.dialogTitle }}</span>
- </div>
- <div v-if="row.low_prices || row.high_prices">
- 商品价格: <span style="color: black">{{ row.low_prices ? row.low_prices : '--' }}</span>
- <span style="color: black">{{ row.high_prices ? row.high_prices : '--' }}</span>
- </div>
- <div v-if="row.delivery">
- 配送:
- <span style="color: black">{{ row.delivery ? row.delivery: '--' }}</span>
- </div>
- <div v-if="row.lookback">
- 回溯期: <span style="color: black">{{ row.lookback ? row.lookback : '--' }}</span>
- </div>
- <div v-if="row.audienceName">
- <div style="font-weight: 500; color: #000">{{ row.category }}</div>
- <el-tooltip class="box-item" effect="dark" :content="row.audienceName" placement="top">
- <div style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden">{{ row.audienceName }}</div>
- </el-tooltip>
- <div style="color: rgba(0, 0, 0, 0.45)">预估人数: {{ row.lowerBoundInclusive }} - {{ row.upperBoundExclusive }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column prop="name" label="竞价" width="160">
- <template #default="{ row }">
- <el-input v-model.number="row.bid">
- <template #prepend>$</template>
- </el-input>
- </template>
- </el-table-column>
- <el-table-column prop="address" label="当前建议竞价" width="160">
- <template #default="{ row }">
- <div>$</div>
- <div>$</div>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="60">
- <template #default="{ row }">
- <el-button link type="danger" size="small" @click="handleButtonClick(row)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- <div style="display: flex; justify-content: space-around; padding-top: 15px">
- <el-button type="primary" plain :disabled="!addedTableData.length" @click="handleSave">保存</el-button>
- </div>
- </div>
- </div>
- </el-card>
- </div>
- </template>
- <script setup lang="ts">
- import { onMounted, ref, watch, reactive, CSSProperties } from 'vue'
- import { request } from '/@/utils/service'
- import BrowseSearch from './BrowseSearch.vue'
- import BuySearch from './BuySearch.vue'
- import { ElMessage, type FormInstance, type FormRules, type TabsPaneContext } from 'element-plus'
- import { getAudiencesList } from '../api/index'
- import { useShopInfo } from '/@/stores/shopInfo'
- import { storeToRefs } from 'pinia'
- const shopInfo = useShopInfo()
- const { profile } = storeToRefs(shopInfo)
- // tab栏
- const topTabName = ref('audience')
- function handleClick(tab: TabsPaneContext, event: Event) {
- // console.log(tab, event)
- }
- // tab栏顶部固定部分功能
- const bidType = ref('2')
- const bidTypeOptions = [
- {
- value: '1',
- label: '建议竞价',
- },
- {
- value: '2',
- label: '自定义竞价',
- },
- ]
- const bid = ref('0.75')
- watch(
- bidType,
- () => {
- if (bidType.value == '1') {
- bid.value = ''
- } else {
- bid.value = '0.75'
- }
- },
- { immediate: true }
- )
- // 亚马逊受众tab的 下拉框和输入框
- const audienceType = ref('')
- const audienceTypeOptions = [
- {
- value: '',
- label: '所有受众',
- },
- {
- value: 'Lifestyle',
- label: '生活方式',
- },
- {
- value: 'Interest',
- label: '兴趣',
- },
- {
- value: 'Life event',
- label: '生活事件',
- },
- {
- value: 'In-market',
- label: '场内客群',
- },
- ]
- const keywordInput = ref('') // 关键词过滤输入框
- // 浏览再营销下的tab栏
- const viewsTabName = ref('advice')
- const viewsLookBack = ref('7')
- const viewsLookBackOptions = [
- {
- value: '7',
- label: '7天',
- },
- {
- value: '14',
- label: '14天',
- },
- {
- value: '30',
- label: '30天',
- },
- {
- value: '60',
- label: '60天',
- },
- {
- value: '90',
- label: '90天',
- },
- ]
- // 购买再营销下的tab栏
- const purchasesTabName = ref('advice')
- const purchasesLookBack = ref('7')
- const purchasesLookBackOptions = [
- {
- value: '7',
- label: '7天',
- },
- {
- value: '14',
- label: '14天',
- },
- {
- value: '30',
- label: '30天',
- },
- {
- value: '60',
- label: '60天',
- },
- {
- value: '90',
- label: '90天',
- },
- ]
- // 已添加的表格数据
- const addedTableData = ref([])
- function browseOrientation(data) {
- const exists = addedTableData.value.some((item) => item.cid === data.cid)
- if (!exists) {
- const dataWithLookback = {
- type: 'c',
- tactictype: 'views',
- lookback: viewsLookBack.value,
- bid: bid.value,
- classificationId: data.cid
- }
- console.log('dataWithLookback', dataWithLookback)
- addedTableData.value.push(dataWithLookback)
- } else {
- ElMessage({
- message: '请勿重复添加',
- type: 'warning',
- })
- }
- }
- function buyOrientation(data) {
- const exists = addedTableData.value.some((item) => item.cid === data.cid)
- if (!exists) {
- const dataWithLookback = {
- ...data,
- lookback: viewsLookBack.value,
- }
- console.log('dataWithLookback', dataWithLookback)
- addedTableData.value.push(dataWithLookback)
- } else {
- ElMessage({
- message: '请勿重复添加',
- type: 'warning',
- })
- }
- }
- // 点击细化后弹窗确认触发
- const deliveryMap = {
- eligible: '具备Prime资格',
- diseligible: '不具备Prime资格',
- all: '所有',
- }
- function browseRefine(data) {
- const exists = addedTableData.value.some((item) => item.cid === data.cid)
- if (!exists) {
- console.log('data', data)
- const tableRow = {
- type: 'c',
- tactictype: 'views',
- lookback: viewsLookBack.value,
- bid: bid.value,
- brandId: data.selectedBrands,
- classificationId: data.cid,
- delivery: data.delivery,
- // categoryId: data.categoryId,
- dialogTitle: data.dialogTitle, // 分类名称
- low_prices: data.prices.lowest,
- high_prices: data.prices.highest,
- low_rating: data.starRating[0],
- high_rating: data.starRating[1],
- }
- addedTableData.value.push(tableRow) // 添加到表格数据
- console.log('tableRow', tableRow)
- } else {
- ElMessage({
- message: '请勿重复添加',
- type: 'warning',
- })
- }
- }
- function buyRefine(data) {
- const exists = addedTableData.value.some((item) => item.cid === data.cid)
- if (!exists) {
- // addedTableData.value.push(data)
- const deliveryText = deliveryMap[data.delivery]
- const tableRow = {
- type: 'c',
- tactictype: 'views',
- lookback: viewsLookBack.value,
- bid: bid.value,
- brandId: data.brandId,
- classificationId: data.cid,
- delivery: data.delivery,
- categoryId: data.categoryId,
- dialogTitle: data.dialogTitle, // 分类名称
- prices: `\$${data.prices.lowest} ~ \$${data.prices.highest}`, // 价格范围
- // 其他需要的字段...
- }
- addedTableData.value.push(tableRow) // 添加到表格数据
- } else {
- ElMessage({
- message: '请勿重复添加',
- type: 'warning',
- })
- }
- }
- // 获取搜索的数据
- const searchLoading = ref(false)
- const searchData = ref([])
- const categoryMap = {
- Lifestyle: '生活方式',
- 'In-market': '场内客群',
- Interest: '兴趣',
- 'Life event': '生活事件',
- }
- function handleSearchChange() {
- getCustomData()
- }
- async function getCustomData() {
- searchLoading.value = true
- const query = {
- profile_id: profile.value.profile_id,
- categoryvalues: audienceType.value,
- values: keywordInput.value,
- }
- try {
- const response = await getAudiencesList(query)
- searchData.value = response.data.audiences.map((audience) => ({
- ...audience,
- category: categoryMap[audience.category] || audience.category,
- }))
- } catch (error) {
- console.error('error: ', error)
- } finally {
- searchLoading.value = false
- }
- }
- function handleAddButtonClick(row) {
- // 检查该行数据是否已经存在于 addedTableData 中
- const exists = addedTableData.value.some((item) => item.audienceId === row.audienceId)
- if (!exists) {
- // 如果不存在,则添加它到 addedTableData
- addedTableData.value.push(row)
- } else {
- // 如果已存在,显示一个警告消息
- ElMessage({
- message: `选项 ${row.audienceName} 已经添加,不能重复添加`,
- type: 'warning',
- })
- }
- }
- // 删除所有Table数据
- function handleDeleteAll() {
- addedTableData.value = []
- }
- // 单独删除功能
- function handleButtonClick(row) {
- if ('cid' in row) {
- // 如果行数据包含 cid 属性,使用 cid 来过滤
- addedTableData.value = addedTableData.value.filter((item) => item.cid !== row.cid)
- } else if ('audienceId' in row) {
- addedTableData.value = addedTableData.value.filter((item) => item.audienceId !== row.audienceId)
- } else if ('categoryId' in row) {
- addedTableData.value = addedTableData.value.filter((item) => item.cid !== row.cid)
- }
- }
- function addPromoteProduct() {
- const newProduct = {
- type: 'p',
- tactictype: 'purchases',
- lookback: viewsLookBack.value,
- asin: '',
- bid: 0.2,
- productType: 'relatedProduct',
- }
- // 例如 type, tactictype, productType 等字段来判断
- const exists = addedTableData.value.some(
- (item) => item.type === newProduct.type && item.tactictype === newProduct.tactictype && item.productType === newProduct.productType
- )
- if (!exists) {
- // 如果不存在,则添加它到 addedTableData
- addedTableData.value.push(newProduct)
- } else {
- // 如果已存在,显示一个警告消息
- ElMessage({
- message: '已经添加了相关商品,不能重复添加',
- type: 'warning',
- })
- }
- }
- function addPromoteSimilar() {}
- // 点击保存触发
- function handleSave() {
- // createCustom()
- console.log('addedTableData:', addedTableData.value)
- }
- function changeTableHeader(row) {
- if (row) {
- return {
- background: '#f5f7fa',
- }
- }
- }
- </script>
- <style scoped>
- .customize-container {
- margin-top: 10px;
- }
- .custom-card-title {
- font-weight: 700;
- padding-bottom: 18px;
- }
- .custom-card-Text {
- font-size: 18px;
- padding-left: 5px;
- }
- .custom-card-icon {
- color: #306cd7;
- font-size: 26px;
- }
- .main-container {
- display: flex;
- border: 1px solid #e5e7eb;
- height: 700px;
- margin-bottom: 20px;
- }
- .left-container {
- width: 50%;
- height: 699px;
- border-right: 1px solid #e5e7eb;
- }
- .right-container {
- width: 50%;
- height: 699px;
- border-bottom: 0;
- }
- .right-container-top {
- height: 40px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .demo-tabs {
- padding: 0 10px;
- }
- .demo-tabs > .el-tabs__content {
- padding: 32px;
- color: #6b778c;
- font-size: 32px;
- font-weight: 600;
- }
- /* 选中时的字体颜色 */
- ::v-deep(.demo-tabs .el-tabs__item.is-top.is-active) {
- color: #3569d6;
- }
- /* 选中时的下划线颜色 */
- ::v-deep(.demo-tabs .el-tabs__active-bar.is-top) {
- background-color: #3569d6;
- }
- .tab-container-fixed-top {
- display: flex;
- align-items: center;
- margin-bottom: 4px;
- gap: 8px;
- font-size: 13px;
- margin: 10px 0;
- }
- .tab-top-label {
- color: #4e5969;
- font-weight: 700;
- margin-right: 10px;
- }
- .align-center-bottom {
- align-items: center;
- margin-bottom: 12px;
- }
- .tab-title {
- line-height: 20px;
- padding-bottom: 10px;
- color: #8e9095;
- }
- .select-label {
- padding-right: 5px;
- color: #606266;
- }
- /* 修改隐藏table底部border */
- ::v-deep(.el-table__inner-wrapper::before) {
- background-color: #ffffff;
- }
- </style>
|