Commit 0638bbb2 authored by jiyonggang's avatar jiyonggang

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/api/report.js
parents a3b18f26 7ce75464
......@@ -56,7 +56,7 @@ export function putinUpdateAdvertiseConversion(params) {
// 创建投放任务
export function putinCreatePutinTask(data) {
return request({
url: process.env.PUTIN_API + "/putin/create/putin-task",
url: process.env.PUTIN_API + "/putin/task/createPutinTask",
method: "post",
data
});
......@@ -423,3 +423,4 @@ export function getGoogleTokenList() {
// ----------------------------------------
......@@ -10,7 +10,7 @@
v-model="lang.selected"
@change="handleLanguageChange(lang.code)"
>
{{ lang.name }}
{{ lang.nameCn }}
</el-checkbox>
</div>
<el-divider content-position="center">已选择的语言</el-divider>
......@@ -22,7 +22,7 @@
@close="removeLanguage(lang.code)"
class="selected-language"
>
{{ lang.name }}
{{ lang.nameCn }}
</el-tag>
</transition-group>
</el-card>
......@@ -44,16 +44,312 @@ export default {
data() {
return {
languages: [
{ code: 'en', name: '英语', selected: true },
{ code: 'es', name: '西班牙语', selected: false },
{ code: 'fr', name: '法语', selected: false },
{ code: 'de', name: '德语', selected: false },
{ code: 'it', name: '意大利语', selected: false },
{ code: 'zh', name: '中文', selected: false },
{ code: 'ja', name: '日语', selected: false },
{ code: 'ko', name: '韩语', selected: false },
{ code: 'ru', name: '俄语', selected: false },
{ code: 'ar', name: '阿拉伯语', selected: false },
{
"code": "en",
"nameEn": "English",
"nameCn": "英语",
"criterionId": 1000
},
{
"code": "de",
"nameEn": "German",
"nameCn": "德语",
"criterionId": 1001
},
{
"code": "fr",
"nameEn": "French",
"nameCn": "法语",
"criterionId": 1002
},
{
"code": "es",
"nameEn": "Spanish",
"nameCn": "西班牙语",
"criterionId": 1003
},
{
"code": "it",
"nameEn": "Italian",
"nameCn": "意大利语",
"criterionId": 1004
},
{
"code": "ja",
"nameEn": "Japanese",
"nameCn": "日语",
"criterionId": 1005
},
{
"code": "da",
"nameEn": "Danish",
"nameCn": "丹麦语",
"criterionId": 1009
},
{
"code": "nl",
"nameEn": "Dutch",
"nameCn": "荷兰语",
"criterionId": 1010
},
{
"code": "fi",
"nameEn": "Finnish",
"nameCn": "芬兰语",
"criterionId": 1011
},
{
"code": "ko",
"nameEn": "Korean",
"nameCn": "韩语",
"criterionId": 1012
},
{
"code": "no",
"nameEn": "Norwegian",
"nameCn": "挪威语",
"criterionId": 1013
},
{
"code": "pt",
"nameEn": "Portuguese",
"nameCn": "葡萄牙语",
"criterionId": 1014
},
{
"code": "sv",
"nameEn": "Swedish",
"nameCn": "瑞典语",
"criterionId": 1015
},
{
"code": "zh_CN",
"nameEn": "Chinese (simplified)",
"nameCn": "简体中文",
"criterionId": 1017
},
{
"code": "zh_TW",
"nameEn": "Chinese (traditional)",
"nameCn": "繁体中文",
"criterionId": 1018
},
{
"code": "ar",
"nameEn": "Arabic",
"nameCn": "阿拉伯语",
"criterionId": 1019
},
{
"code": "bg",
"nameEn": "Bulgarian",
"nameCn": "保加利亚语",
"criterionId": 1020
},
{
"code": "cs",
"nameEn": "Czech",
"nameCn": "捷克语",
"criterionId": 1021
},
{
"code": "el",
"nameEn": "Greek",
"nameCn": "希腊语",
"criterionId": 1022
},
{
"code": "hi",
"nameEn": "Hindi",
"nameCn": "印地语",
"criterionId": 1023
},
{
"code": "hu",
"nameEn": "Hungarian",
"nameCn": "匈牙利语",
"criterionId": 1024
},
{
"code": "id",
"nameEn": "Indonesian",
"nameCn": "印尼语",
"criterionId": 1025
},
{
"code": "is",
"nameEn": "Icelandic",
"nameCn": "冰岛语",
"criterionId": 1026
},
{
"code": "iw",
"nameEn": "Hebrew",
"nameCn": "希伯来语",
"criterionId": 1027
},
{
"code": "lv",
"nameEn": "Latvian",
"nameCn": "拉脱维亚语",
"criterionId": 1028
},
{
"code": "lt",
"nameEn": "Lithuanian",
"nameCn": "立陶宛语",
"criterionId": 1029
},
{
"code": "pl",
"nameEn": "Polish",
"nameCn": "波兰语",
"criterionId": 1030
},
{
"code": "ru",
"nameEn": "Russian",
"nameCn": "俄语",
"criterionId": 1031
},
{
"code": "ro",
"nameEn": "Romanian",
"nameCn": "罗马尼亚语",
"criterionId": 1032
},
{
"code": "sk",
"nameEn": "Slovak",
"nameCn": "斯洛伐克语",
"criterionId": 1033
},
{
"code": "sl",
"nameEn": "Slovenian",
"nameCn": "斯洛文尼亚语",
"criterionId": 1034
},
{
"code": "sr",
"nameEn": "Serbian",
"nameCn": "塞尔维亚语",
"criterionId": 1035
},
{
"code": "uk",
"nameEn": "Ukrainian",
"nameCn": "乌克兰语",
"criterionId": 1036
},
{
"code": "tr",
"nameEn": "Turkish",
"nameCn": "土耳其语",
"criterionId": 1037
},
{
"code": "ca",
"nameEn": "Catalan",
"nameCn": "加泰罗尼亚语",
"criterionId": 1038
},
{
"code": "hr",
"nameEn": "Croatian",
"nameCn": "克罗地亚语",
"criterionId": 1039
},
{
"code": "vi",
"nameEn": "Vietnamese",
"nameCn": "越南语",
"criterionId": 1040
},
{
"code": "ur",
"nameEn": "Urdu",
"nameCn": "乌尔都语",
"criterionId": 1041
},
{
"code": "tl",
"nameEn": "Filipino",
"nameCn": "菲律宾语",
"criterionId": 1042
},
{
"code": "et",
"nameEn": "Estonian",
"nameCn": "爱沙尼亚语",
"criterionId": 1043
},
{
"code": "th",
"nameEn": "Thai",
"nameCn": "泰语",
"criterionId": 1044
},
{
"code": "bn",
"nameEn": "Bengali",
"nameCn": "孟加拉语",
"criterionId": 1056
},
{
"code": "fa",
"nameEn": "Persian",
"nameCn": "波斯语",
"criterionId": 1064
},
{
"code": "gu",
"nameEn": "Gujarati",
"nameCn": "古吉拉特语",
"criterionId": 1072
},
{
"code": "kn",
"nameEn": "Kannada",
"nameCn": "卡纳达语",
"criterionId": 1086
},
{
"code": "ml",
"nameEn": "Malayalam",
"nameCn": "马拉雅拉姆语",
"criterionId": 1098
},
{
"code": "mr",
"nameEn": "Marathi",
"nameCn": "马拉地语",
"criterionId": 1101
},
{
"code": "ms",
"nameEn": "Malay",
"nameCn": "马来语",
"criterionId": 1102
},
{
"code": "pa",
"nameEn": "Punjabi",
"nameCn": "旁遮普语",
"criterionId": 1110
},
{
"code": "ta",
"nameEn": "Tamil",
"nameCn": "泰米尔语",
"criterionId": 1130
},
{
"code": "te",
"nameEn": "Telugu",
"nameCn": "泰卢固语",
"criterionId": 1131
}
],
};
},
......
<template>
<div class="text-input-list">
<!-- 文本输入列表 -->
<div class="input-list">
<div
v-for="(text, index) in innerTexts"
:key="index"
class="input-item"
>
<el-input
v-model="innerTexts[index]"
:placeholder="`${placeholder} #${index + 1}`"
:maxlength="maxLength"
:class="{
'is-error': isOverLength(text),
'is-focused': focusedIndex === index
}"
show-word-limit="true"
@input="handleInput(index)"
@focus="focusedIndex = index"
@blur="focusedIndex = -1"
width="50%"
>
<template slot="append">
<el-button
v-if="canDelete(index)"
icon="el-icon-delete"
@click="handleRemove(index)"
class="delete-button"
></el-button>
</template>
</el-input>
<div class="input-status">
<transition name="fade">
<span v-if="duplicateIndexes.includes(index)" class="duplicate-warning">
重复内容
</span>
</transition>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TextInputList',
props: {
value: {
type: Array,
default: () => ['']
},
maxLength: {
type: Number,
default: 100
},
placeholder: {
type: String,
default: '请输入文本'
},
warningThreshold: {
type: Number,
default: 0.9 // 默认在90%时显示警告
}
},
data() {
return {
innerTexts: [''],
focusedIndex: -1,
duplicateIndexes: []
}
},
watch: {
value: {
handler(newVal) {
const valueToSet = newVal.length ? newVal : ['']
if (JSON.stringify(this.getNonEmptyTexts()) !== JSON.stringify(valueToSet)) {
this.innerTexts = [...valueToSet]
if (!this.innerTexts[this.innerTexts.length - 1]) {
this.innerTexts.push('')
}
}
},
immediate: true,
deep: true
}
},
methods: {
getNonEmptyTexts() {
return this.innerTexts.filter(text => text.trim() !== '')
},
isOverLength(text) {
return text.length > this.maxLength
},
canDelete(index) {
return this.innerTexts.length > 1
},
handleInput(index) {
const text = this.innerTexts[index]
this.duplicateIndexes = [] // 清除之前的重复标记
// 检查重复
const duplicateIndex = this.innerTexts.findIndex((t, i) =>
i !== index && t.trim() === text.trim() && text.trim() !== ''
)
if (duplicateIndex !== -1) {
this.$message({
message: '该文本已存在,请输入其他内容',
type: 'warning',
duration: 2000
})
this.duplicateIndexes = [index]
this.$set(this.innerTexts, index, '')
return
}
// 如果是最后一行且有内容,添加新行
if (index === this.innerTexts.length - 1 && text.trim() !== '') {
this.innerTexts.push('')
}
// 更新父组件的值
this.$emit('input', this.getNonEmptyTexts())
},
handleRemove(index) {
this.innerTexts.splice(index, 1)
if (this.innerTexts.length === 0) {
this.innerTexts.push('')
}
this.$emit('input', this.getNonEmptyTexts())
}
}
}
</script>
<style>
.text-input-list {
width: 100%;
}
.input-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.input-item {
position: relative;
margin-bottom: 24px;
transition: all 0.3s ease;
}
.input-item:hover .delete-button {
opacity: 1;
}
.delete-button {
opacity: 0.5;
transition: opacity 0.3s ease;
}
.delete-button:hover {
opacity: 1;
}
/* 输入框样式 */
.el-input.is-focused .el-input__inner {
border-color: #409EFF;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
}
.el-input__inner {
transition: all 0.3s ease;
}
.el-input.is-error .el-input__inner {
border-color: #F56C6C;
box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.1);
}
/* 状态显示区域 */
.input-status {
position: absolute;
left: 0;
bottom: -20px;
display: flex;
gap: 8px;
align-items: center;
font-size: 12px;
}
.input-counter {
color: #909399;
transition: all 0.3s ease;
}
.input-counter.is-error {
color: #F56C6C;
}
.input-counter.is-warning {
color: #E6A23C;
}
.duplicate-warning {
color: #F56C6C;
display: flex;
align-items: center;
}
/* 动画效果 */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
/* 输入框组样式 */
.el-input-group__append {
padding: 0;
}
.el-input-group__append .el-button {
border: none;
margin: 0;
height: 100%;
color: #909399;
}
.el-input-group__append .el-button:hover {
color: #F56C6C;
background-color: #fef0f0;
}
</style>
......@@ -368,46 +368,59 @@
<div class="drawer-item-con">
<el-form ref="form">
<el-form-item label="投放组名称">
<el-input
class="drawer-input"
style="width: 500px"
v-model="putinBaseInfo.taskName"
></el-input>
</el-form-item>
<el-form-item label="选择应用">
<el-select
v-model="putinBaseInfo.pkg"
v-model="putinTask.appInfo"
filterable
clearable
placeholder="请选择"
style="width: 200px"
@change="putinFetchAccount()"
@change="handleChangeApp"
>
<el-option
v-for="item in pkgList"
:key="item.value"
:label="item.label"
:value="item.value"
:value="item"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="任务名称">
<el-input
class="drawer-input"
style="width: 500px"
v-model="putinTask.taskName"
></el-input>
</el-form-item>
<el-form-item label="选择投放账户">
<tree-transfer
:mode="mode"
:title="title"
:from_data="generateData"
:to_data="toData"
:defaultProps="{ label: 'label' }"
@addBtn="add"
@removeBtn="remove"
width="80%"
<el-transfer
style="text-align: left; display: inline-block"
v-model="putinTask.putinAccounts"
filterable
width="100%"
height="360px"
filter
>
</tree-transfer>
:left-default-checked="[]"
:right-default-checked="[]"
:titles="['源列表', '目标列表']"
:button-texts="['', '']"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}'
}"
:data="generateData"
:filter-method="filterAccount"
@change="handleChange"
>
<span slot-scope="{ option }">{{ option.label }} - {{ option.key }}</span>
</el-transfer>
</el-form-item>
</el-form>
</div>
......@@ -422,33 +435,41 @@
<div class="drawer-item-con">
<el-form ref="form">
<el-form-item label="选择广告系列子类型">
<el-radio-group v-model="putinBaseInfo.deliveryRange">
<template v-for="item of globalEnums.campaignType">
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.name }}</el-radio-button
>
</template>
</el-radio-group>
<el-select
v-model="putinTask.campaignType"
placeholder=""
default-first-option
style="width: 200px"
>
<el-option
v-for="item in [{'name': '应用安装', 'value': 1, 'disabled': false}, { 'name': '应用互动', 'value': 2 , 'disabled': true}, { 'name': '应用预注册', 'value': 3 , 'disabled': true}]"
:key="item.value"
:label="item.name"
:value="item.value"
:disabled="item.disabled"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="选择移动应用平台">
<el-radio-group
v-model="makeCreative.putinInventoryType"
@change="changePutinInventory"
<el-select
v-model="putinTask.appStore"
placeholder=""
default-first-option
style="width: 200px"
>
<template v-for="item of [{'label': 'Android', 'value': 1}, {'label': 'iOS', 'value': 2}]">
<el-radio-button
:key="item.value"
:label="item.label"
:value="item.value"
>
{{ item.label }}
</el-radio-button>
</template>
</el-radio-group>
<el-option
v-for="item in [{'label': 'Android', 'value': 3, 'disabled': false}, {'label': 'iOS', 'value': 2, 'disabled': true}]"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
......@@ -460,7 +481,7 @@
<div class="drawer-item-con">
<el-input
class="apk-input"
v-model="putinBaseInfo.landUrl"
v-model="putinTask.campaignName"
></el-input>
</div>
</div>
......@@ -469,12 +490,12 @@
<div class="drawer-item border-bottom" style="padding-bottom: 20px">
<div class="drawer-item-title">地理位置</div>
<div class="drawer-item-con">
<CountrySelector v-model="countries" />
<CountrySelector v-model="putinTask.locations" />
</div>
<div class="drawer-item-title">语言</div>
<div class="drawer-item-con">
<LanguageSelector v-model="languages" />
<LanguageSelector v-model="putinTask.languages" />
</div>
<div class="drawer-item-title">开始日期和结束日期</div>
......@@ -482,7 +503,7 @@
<el-form ref="form">
<el-form-item label="开始日期">
<el-date-picker
v-model="startDate"
v-model="putinTask.startDate"
align="right"
type="date"
value-format="yyyy-MM-dd"
......@@ -492,7 +513,7 @@
<el-form-item label="结束日期">
<el-date-picker
v-model="endDate"
v-model="putinTask.endDate"
align="right"
type="date"
value-format="yyyy-MM-dd"
......@@ -510,7 +531,7 @@
<el-form-item label="广告预算" prop="budget">
<el-input
v-model="dailyBudget"
v-model="putinTask.dailyBudget"
placeholder="请输入广告预算"
@blur="formatBudget"
style="width: 30%"
......@@ -528,7 +549,7 @@
<div class="drawer-item-con">
<el-form ref="form">
<el-select
v-model="zhuanhuamubiao"
v-model="putinTask.zhuanhuamubiao"
placeholder=""
default-first-option
style="width: 200px"
......@@ -546,24 +567,25 @@
</div>
</div>
<div class="drawer-item border-bottom">
<div class="drawer-item-title" style="font-weight: 700">
广告组
</div>
<div class="drawer-item-title">广告组名称</div>
<div class="drawer-item-con">
<el-input
class="apk-input"
v-model="putinTask.adGroupName"
/>
</div>
</div>
<!-- 制作创意 -->
<div class="drawer-item">
<div class="drawer-item border-bottom">
<div class="drawer-item-title">制作创意</div>
<div class="drawer-item-con">
<el-form ref="form">
<el-form-item label="创意方式">
<el-radio-group v-model="makeCreative.creativeMaterialMode">
<template
v-for="(item, index) of [
{ label: '程序化创意', value: 'STATIC_ASSEMBLE' },
]"
>
<el-radio :label="item.value" :key="index">
{{ item.label }}
</el-radio>
</template>
</el-radio-group>
</el-form-item>
<el-form-item label="选择素材组">
<el-select
v-model="makeCreative.materialGroupId"
......@@ -579,411 +601,26 @@
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<el-form-item label="素材计划分发策略:">
<el-radio-group v-model="putinBaseInfo.putinStrag">
<template
v-for="item of [
{ label: '默认模式', value: 'default' },
{ label: '均分模式', value: 'avg' },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
<el-form-item label="创意组合">
<el-radio-group v-model="makeCreative.creativeComposeMethod">
<template v-for="(item, index) of portfolioList">
<el-radio :label="item.value" :key="index">
{{ item.label }}
</el-radio>
</template>
</el-radio-group>
</el-form-item>
<div v-if="makeCreative.creativeComposeMethod === 2">
<el-form-item label="竖版视频">
<el-input
v-model="makeCreative.verticalVideo"
placeholder="填写数量"
style="width: 200px"
></el-input>
</el-form-item>
<el-form-item label="横版视频">
<el-input
v-model="makeCreative.horizontalVideo"
placeholder="填写数量"
style="width: 200px"
></el-input>
</el-form-item>
<el-form-item label="大图横图">
<el-input
v-model="makeCreative.bigImage"
placeholder="填写数量"
style="width: 200px"
></el-input>
</el-form-item>
<el-form-item label="大图竖图">
<el-input
v-model="makeCreative.verticalBigImage"
placeholder="填写数量"
style="width: 200px"
></el-input>
</el-form-item>
<el-form-item label="小图">
<el-input
v-model="makeCreative.smallImage"
placeholder="填写数量"
style="width: 200px"
></el-input>
</el-form-item>
</div>
<el-form-item label="添加文案">
<el-input
style="width: 450px"
ref="inputText"
v-model="inputValue2"
@keyup.enter.native="handleInputConfirm2"
@blur="handleInputConfirm2"
>
<template slot="append">回车</template>
</el-input>
<!-- 选取文案子组件 -->
<span class="outer-father">
<!-- 子组件 选取文案列表 -->
<select-text
class="select-text"
@selectData="receiveData"
:appId="appId"
/>
</span>
<!-- 批量填写 -->
<span>
<text-textarea :text = arrays.textGroup.join() @confirm="handleTextareaData" />
</span>
<div class="checkedText">
<div class="checkedText-title">
<span style="margin-left: 10px"
>已选 {{ arrays.textGroup.length }}</span
>
<span style="float: right; margin-right: 10px">
<a href="javascript:;" @click="removeAll">清空</a>
</span>
</div>
<div style="padding: 10px">
<el-tag
class="tag-line"
:key="tag"
v-for="tag in arrays.textGroup"
closable
:disable-transitions="false"
@close="handleClose2(tag)"
@click="tagEdit(tag)"
>
{{ tag }}
</el-tag>
</div>
</div>
</el-form-item>
<el-form-item label="创意文案数">
<el-input-number
v-model="makeCreative.textNum"
:precision="0"
:step="1"
:min="1"
:max="10"
></el-input-number>
</el-form-item>
<!-- ********************************************************************** -->
<el-form-item v-if="is_card" label="推广卡片">
<span style="color: red"
>建议尺寸为108*108,大小小于1M。支持JPG、PNG等图片格式
</span>
<el-form-item label="推广卡片">
<div class="row-center-start">
<img
class="promotion-card"
:src="makeCreative.promotionCardImg"
alt=""
/>
<el-upload
ref="imgUpload"
:show-file-list="false"
:data="uploadData"
:on-success="imgSuccess"
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"
:action="uploadAction"
>
<el-button type="primary">上传图片</el-button>
</el-upload>
</div>
</el-form-item>
<el-form-item label="卡片标题">
<span style="color: red">卡片标题需在7个字符以内</span
><br />
<el-input
minlength="1"
maxlength="7"
show-word-limit
v-model="makeCreative.productDescription"
style="width: 300px"
@change="checkCardTitle"
></el-input>
</el-form-item>
<el-form-item label="推广卖点">
<span style="color: red"
>最多不超过10个卖点,每条需要在6-9个字符内</span
><br />
<el-tag
:key="tag"
v-for="tag in arrays.productSellingPoints"
closable
:disable-transitions="false"
@close="handleClose3(tag)"
>
{{ tag }}
</el-tag>
<el-input
minlength="6"
maxlength="9"
show-word-limit
class="input-new-tag"
v-if="inputVisible3"
v-model="inputValue3"
ref="saveTagInput3"
@keyup.enter.native="handleInputConfirm3"
@blur="handleInputConfirm3"
style="width: 300px"
>
</el-input>
<el-button
v-else
class="button-new-tag"
size="small"
@click="showInput3"
>
+ 添加
</el-button>
</el-form-item>
<el-form-item label="行动号召">
<el-radio-group v-model="makeCreative.enablePersonalAction">
<template
v-for="item of [
{ label: '开启智能优选', value: 1 },
{ label: '关闭智能优选', value: 0 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
<el-form-item label="">
<el-select
v-model="makeCreative.actionText"
placeholder="请选择"
style="width: 200px"
@focus="getCallActionList()"
>
<el-option
v-for="(item, idx) in callActionList"
:key="idx"
:label="item"
:value="item"
>
</el-option>
</el-select>
</el-form-item>
</el-form-item>
<!-- ********************************************************************** -->
<el-form-item
v-if="putinBaseInfo.landingType === 'LINK'"
label="广告来源"
>
<el-input
v-model="makeCreative.adSource"
placeholder="落地页推广必填(一般与公司名保持一致)"
/>
</el-form-item>
<el-form-item label="品牌主页">
<el-radio-group v-model="makeCreative.brandMainPage">
<template
v-for="(item, index) of [
{ label: '不开启', value: 1 },
{ label: '开启抖音主页', value: 2 },
]"
>
<el-radio :label="item.value" :key="index">
{{ item.label }}
</el-radio>
</template>
</el-radio-group>
</el-form-item>
<el-form-item v-if="!is_card" label="行动号召">
<el-select
v-model="makeCreative.actionText"
placeholder="请选择"
style="width: 200px"
@focus="getCallActionList()"
>
<el-option
v-for="(item, idx) in callActionList"
:key="idx"
:label="item"
:value="item"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="副标题">
<el-input
v-model="makeCreative.subTitle"
style="width: 600px"
></el-input>
</el-form-item>
<!-- unionVideoType -->
<el-form-item
v-if="
putinBaseInfo.unionVideoType === 'REWARDED_VIDEO' ||
(putinBaseInfo.deliveryRange == 'DEFAULT' &&
makeCreative.putinInventoryType === 'inventoryType')
"
label="试玩搭配"
>
<el-radio-group v-model="tryItOut" @change="onpenMetr">
<template
v-for="item of [
{ label: '不启用', value: 0 },
{ label: '启用', value: 1 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>
{{ item.label }}
</el-radio-button>
</template>
</el-radio-group>
</el-form-item>
<el-form-item v-show="tryItOut == 1" label="选择试玩">
<template v-for="(itm, idx) in tryMaterialList">
<div :key="idx">
{{ "广告主:" + idx + "—已选择 " + itm + "条" }}
</div>
</template>
</el-form-item>
<el-form-item label="*自动生成视频素材">
<el-radio-group v-model="makeCreative.isPresentedVideo">
<template
v-for="item of [
{ label: '不启用', value: 0 },
{ label: '启用', value: 1 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
<el-form-item label="最优创意衍生计划">
<el-radio-group v-model="makeCreative.bestCreativeDerivePlan">
<template
v-for="item of [
{ label: '不启用', value: 0 },
{ label: '启用', value: 1 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
<div class="drawer-item border-bottom">
<div class="drawer-item-title">标题</div>
<div class="drawer-item-con">
<TextInputList v-model="putinTask.headlines" :maxLength="30"/>
<el-form-item label="广告评论">
<el-radio-group v-model="makeCreative.adComment">
<template
v-for="item of [
{ label: '关闭', value: 0 },
{ label: '开启', value: 1 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
</div>
</div>
<el-form-item label="创意展现">
<el-radio-group v-model="makeCreative.creativeShowMode">
<template
v-for="item of [
{ label: '优选模式', value: 1 },
{ label: '轮播模式', value: 2 },
]"
>
<el-radio-button
:key="item.value"
:label="item.value"
:value="item.value"
>{{ item.label }}</el-radio-button
>
>
</template>
</el-radio-group>
</el-form-item>
</el-form>
<div class="drawer-item border-bottom">
<div class="drawer-item-title">广告内容描述</div>
<div class="drawer-item-con">
<TextInputList v-model="putinTask.descriptions" :maxLength="90"/>
</div>
</div>
<!-- 提交 -->
<div class="row-center-end" style="padding-right: 100px">
<el-button
......@@ -1038,9 +675,6 @@ import {
putinUpdateAdvertiseConversion,
putinCreatePutinTask,
putinFetchIndustryList,
getCallActionList,
getCrowdList,
getCreatedDirectPkg,
getAdvList,
getAdvertiseCount,
} from "@/api/report";
......@@ -1056,6 +690,7 @@ import AddAdvGroup from "./childComponents/AddAdvGroup";
import TextTextarea from "./childComponents/TextTextarea";
import CountrySelector from "./childComponents/CountrySelector";
import LanguageSelector from "./childComponents/LanguageSelector";
import TextInputList from "./childComponents/TextInputList";
import { stepList } from "./childComponents/util";
......@@ -1070,6 +705,7 @@ export default {
AddAdvGroup,
TextTextarea,
CountrySelector,
TextInputList,
}, // 注册
data() {
......@@ -1179,6 +815,28 @@ export default {
ladderStep: 0, // 阶梯价步长
putinStrag: 'default', //
},
// 任务保存数据
putinTask: {
taskName: '',
putinAccounts: [],
campaignName: '',
campaignType: 1,
zhuanhuamubiao: 1,
dailyBudget: 0.0,
targetCpa: 0.0,
appInfo: "",
appStore: 3,
startDate: '',
endDate: '',
locations: [],
languages: [],
adGroupName: '',
headlines: [],
descriptions: [],
imageAssets: [],
videoAssets: []
},
// 用户定向
orientation: {
......@@ -1300,6 +958,8 @@ export default {
inputVisible2: false,
inputValue2: "",
inputValue5: "",
inputVisibleTag: false,
inputValueTag: "",
......@@ -1321,14 +981,10 @@ export default {
},
},
created() {
this.startDate = moment().subtract(0, "days").format("YYYY-MM-DD");
// [new Date(2000, 10, 10, 10, 10), new Date(2000, 10, 11, 10, 10)],
this.putinTask.startDate = moment().subtract(0, "days").format("YYYY-MM-DD");
this._menuSelectApps(); // 获取App名称配置列表
this.APIGetEnums(); // 获取公共下拉框参数
this.putinFetchAccount(); // 获取投放账号列表
this.materialGroupList(); // 获取创建的素材组列表
this.putinFetchIndustryList(); // 抓取创意三级分类信息列表
this.putinFetchPutinTasks(); // 获取投放任务列表
......@@ -1342,62 +998,6 @@ export default {
},
methods: {
/* 获取人群包列表 */
APIGetCrowdList(advertiserId) {
let params = {
advertiserId: advertiserId,
};
getCrowdList(params).then((res) => {
// console.log("res111111", res);
this.custom_audienc = res.result.data; // 人群定向包
this.exclude_audience = res.result.data; // 用来处理排除人群 单独处理
});
},
/* 获取已创建的定向包 */
APIGetCreatedDirectPkg(pkg) {
let params = {
pkg,
};
getCreatedDirectPkg(params).then((res) => {
this.directPkg = res.result.data;
});
},
//获取行动号召列表
getCallActionList() {
if (
!this.targetList[0] ||
!this.targetList[0].pid ||
!this.targetList[0].id ||
!this.putinBaseInfo.landingType ||
this.targetList[0].pid == undefined ||
this.targetList[0].id == undefined ||
this.putinBaseInfo.landingType == undefined
) {
this.$message.error("请先填写上面的参数!");
this.callActionList = [];
return;
}
let params = {
accountId: this.targetList[0].pid,
advertiserId: this.targetList[0].id,
landType: this.putinBaseInfo.landingType,
industry: this.makeCreative.creativeCategory, //选填
};
getCallActionList(params).then((res) => {
if (res.status == 200) {
if (res.result.data.length == 0) {
this.$message.info("没有相关选项");
}
this.callActionList = res.result.data;
} else {
this.$message.error("行动请求列数据-请求错误");
}
});
},
//创建投放重置数据
clearAllData() {
this.drawer = true; // 打开抽屉
......@@ -1440,119 +1040,7 @@ export default {
ladderStep: 0, // 阶梯价步长
putinStrag: 'default'
};
this.orientation = {
id: "",
allowCity: "", // 城市
allowGender: "NONE", // 性别(默认: 不限)
allowAge: "", // 年龄
interestActionMode: "RECOMMEND", // 行为兴趣(默认: 系统推荐)
allowNetwork: "", // 网络
allowCarrier: "", // 运营商
retargetingTagsExclude: "",
retargetingTagsInclude: "",
selectHisPack: "",
};
this.makeCreative = {
id: "",
adSource: "",
materialGroupId: "",
creativeComposeMethod: 2,
verticalVideo: "",
horizontalVideo: "",
bigImage: "",
smallImage: "",
verticalBigImage: "",
textGroup: "", // 制作创意: 添加文案
textNum: 5, //文案数
promotionCardImg: "",
productImageId: "", // 商品卡片图片(主图)
productDescription: "", // 推广卡片 标题(描述)
productSellingPoints: "", // 推广卡片 商品卖点
enablePersonalAction: 1, // 是否使用智能优选,1为使用,0为不使用
actionText: "",
subTitle: "", // 制作创意: 副标题
adComment: 0,
advanceCreative: 0,
isPresentedVideo: 1,
bestCreativeDerivePlan: 1,
brandMainPage: 1,
creativeCategory: "", // 创意分类
creativeFullCategory: "", // 创意分类所有id, 便于回显
creativeTags: "", // 创意标签
creativeMaterialMode: "STATIC_ASSEMBLE", // 默认程序化创意
creativeShowMode: 1, // 创意展现方式, 默认优选模式
gdtMonitorUrl: "",
putinInventoryType: "smartInventory", // 投放位置的类型
putinInventory: "", // 投放位置的值
kuaishouMonitorUrl: "",
smartInventory: 1,
openPlay: "no", //开启试玩素材选择yes否则是no
};
this.arrays = {
creativeTags: [], // 创意标签
allowAge: [""], // 用户定向: 年龄
allowNetwork: [""], // 用户定向: 网络
allowCarrier: [""], // 用户定向: 运营商
textGroup: [], // 制作创意: 添加文案,
productSellingPoints: [], // 推广卡片 商品卖点
};
this.targetList = [];
// this.generateData = []; // 未选中数据 清除
this.toData = []; //已选中的数据 清除
this.targetData = ""; //
this.allowDirect = "Both";
this.creativeCategoryDefault = [];
//以上是格式化表单
this.together_id2 = [];
this.together_id1 = [];
this.custom_audienc_id = [];
this.activePutin = "newPutin";
this.bid_type = "only";
},
handleAgeDire(value) {
// console.log("改变:", value);
let ages = [...this.arrays.allowAge];
let len = ages.length;
if (len > 1) {
if (ages[len - 1] !== "") {
this.arrays.allowAge = ages.filter((i) => i !== "");
} else {
this.arrays.allowAge = ages.filter((i) => i === "");
}
}
},
handleNetDire() {
let net = [...this.arrays.allowNetwork];
let len = net.length;
if (len > 1) {
if (net[len - 1] !== "") {
this.arrays.allowNetwork = net.filter((i) => i !== "");
} else {
this.arrays.allowNetwork = net.filter((i) => i === "");
}
}
},
handleCarrierDire() {
let carrier = [...this.arrays.allowCarrier];
let len = carrier.length;
if (len > 1) {
if (carrier[len - 1] !== "") {
this.arrays.allowCarrier = carrier.filter((i) => i !== "");
} else {
this.arrays.allowCarrier = carrier.filter((i) => i === "");
}
}
},
checkCardTitle() {
// console.log("检查卡片标题:", this.makeCreative.productDescription);
if (this.makeCreative.productDescription.length > 7) {
this.$message.warning("卡片标题需在7字以内");
}
},
executeTask() {
......@@ -1603,20 +1091,8 @@ export default {
});
},
changePutinInventory: function (item) {
// console.log(12345, item);
this.makeCreative.putinInventory = "";
// 广告优选
if (this.makeCreative.putinInventoryType === "smartInventory") {
this.is_card = true;
} else {
this.is_card = false;
}
},
handleClose2(tag) {
this.arrays.textGroup.splice(this.arrays.textGroup.indexOf(tag), 1);
this.putinTask.headlines.splice(this.putinTask.headlines.indexOf(tag), 1);
},
/* 点击添加时 显示表单输入 */
......@@ -1638,29 +1114,30 @@ export default {
handleInputConfirm2() {
let inputValue2 = this.inputValue2;
if (inputValue2 && this.tagId == "") {
this.arrays.textGroup.push(inputValue2);
this.putinTask.headlines.push(inputValue2);
/* 添加到文案库 */
this.APIGetBusinTextAdd(inputValue2);
} else if (inputValue2 && this.tagId != "") {
this.APIGetBusinTextEdit(this.tagId, inputValue2); // 修改文案
this.arrays.textGroup.push(inputValue2);
this.putinTask.headlines.push(inputValue2);
}
// this.inputVisible2 = false;
this.inputValue2 = ""; // 添加完之后恢复表单为空值
},
// 批量添加文案
handleTextareaData(value) {
this.arrays.textGroup = [];
this.putinTask.headlines = [];
console.log(value);
// 过滤空行
var values = value.filter((item) => item != '');
console.log(values);
values.forEach((item) => {
this.arrays.textGroup.push(item);
this.putinTask.headlines.push(item);
});
this.arrays.textGroup = [...new Set(this.arrays.textGroup)];
this.putinTask.headlines = [...new Set(this.putinTask.headlines)];
/* 添加到文案库 */
this.APIGetBusinTextAdd(values.toString());
......@@ -1719,7 +1196,7 @@ export default {
handleInputConfirmTag() {
let inputValueTag = this.inputValueTag;
if (inputValueTag) {
this.arrays.textGroup.push(inputValueTag);
this.putinTask.headlines.push(inputValueTag);
}
this.inputVisibleTag = false;
this.inputValueTag = "";
......@@ -1779,56 +1256,8 @@ export default {
// 创建投放任务
putinCreatePutinTask: function () {
this.makeCreative.creativeTags = this.arrays.creativeTags.join();
this.orientation.allowAge = this.arrays.allowAge.join();
this.orientation.allowNetwork = this.arrays.allowNetwork.join();
this.orientation.allowCarrier = this.arrays.allowCarrier.join();
this.makeCreative.textGroup = JSON.stringify(this.arrays.textGroup);
this.makeCreative.productSellingPoints = JSON.stringify(
this.arrays.productSellingPoints
);
if (this.makeCreative.putinInventory instanceof Array) {
this.makeCreative.putinInventory = this.makeCreative.putinInventory.join();
}
if (
this.makeCreative.actionText === "" ||
this.makeCreative.actionText == null ||
this.makeCreative.actionText == undefined
) {
this.$message.error("请选择行动号召参数!");
return;
}
//点击选择试玩素材列表,如果不启用或者不是穿山甲激励视频,就将其置为空,否侧就多选拼串
if (this.tryItOut !== 1) {
this.makeCreative.openPlay = "no";
} else {
this.makeCreative.openPlay = "yes";
}
console.log(
"任务提交参数:",
JSON.stringify(
{
putinBaseInfo: this.putinBaseInfo,
orientation: this.orientation,
makeCreative: this.makeCreative,
},
null,
4
)
);
//提交按钮禁用
this.submitBtnState = true;
/* 接口请求 */
putinCreatePutinTask({
putinBaseInfo: this.putinBaseInfo,
orientation: this.orientation,
makeCreative: this.makeCreative,
})
putinCreatePutinTask(this.putinTask)
.then((res) => {
if (res.status === 200) {
this.putinFetchPutinTasks(); // 获取投放任务列表
......@@ -1934,52 +1363,14 @@ export default {
// console.log("targetList回显:", JSON.stringify(this.targetList, null, 4));
},
// 监听穿梭框组件添加
add(generateData, toData, obj) {
// 树形穿梭框模式transfer时,返回参数为左侧树移动后数据、右侧树移动后数据、移动的{keys,nodes,halfKeys,halfNodes}对象
// 通讯录模式addressList时,返回参数为右侧收件人列表、右侧抄送人列表、右侧密送人列表
// console.log("generateData:", generateData);
// console.log("toData:", JSON.stringify(toData, null, 4));
// console.log("obj:", obj);
/* 取一个广告组的id 用来获取人群包数据 */
this.crowdAdvertiserId = toData[0].children[0].id + "";
this.APIGetCrowdList(this.crowdAdvertiserId);
this.putinBaseInfo.selectAdvertisers = [];
this.targetList = []; // 清空组装投放目标列表
this.gettoData(toData); // 组装投放列表
},
// 监听穿梭框组件移除
remove(generateData, toData, obj) {
// 树形穿梭框模式transfer时,返回参数为左侧树移动后数据、右侧树移动后数据、移动的{keys,nodes,halfKeys,halfNodes}对象
// 通讯录模式addressList时,返回参数为右侧收件人列表、右侧抄送人列表、右侧密送人列表
/* console.log("generateData:", generateData);
console.log("toData:", toData);
console.log("obj:", obj); */
this.putinBaseInfo.selectAdvertisers = [];
this.targetList = []; // 清空组装投放目标列表
this.gettoData(toData);
},
// 获取投放账号列表
putinFetchAccount: function () {
for (let i = 0; i < this.pkgList.length; i++) {
if (this.pkgList[i].value == this.putinBaseInfo.pkg) {
this.appId = this.pkgList[i].id + "";
break;
}
}
this.uploadData.pkg = this.putinBaseInfo.pkg;
putinFetchAccount({
pkg: this.putinBaseInfo.pkg,
type: this.platformId,
pkg: this.putinTask.appInfo.value,
}).then((res) => {
this.generateData = res.result.data;
this.generateData = this.generateData .map(obj => ({ key: obj, label: obj.advertiserName}));
this.materialGroupList();
});
},
......@@ -2010,7 +1401,7 @@ export default {
// 获取创建的素材组列表
materialGroupList: function () {
materialGroupList({
pkg: this.putinBaseInfo.pkg,
pkg: this.putinTask.appInfo.value,
}).then((res) => {
this.materialList = res.result.data.content;
});
......@@ -2115,33 +1506,7 @@ export default {
this.makeCreative.id = "";
},
/* 逻辑定向回显 */
saveLogic(item) {
/* 根据定向逻辑中的值 确定是那个定向逻辑 */
if (
this.orientation.retargetingTagsExclude != null &&
this.orientation.retargetingTagsInclude != null
) {
this.allowDirect = "Both";
this.together_id1 = this.orientation.retargetingTagsInclude.split(",");
this.together_id2 = this.orientation.retargetingTagsExclude.split(",");
} else if (this.orientation.retargetingTagsExclude != null) {
this.allowDirect = "retargetingTagsExclude";
this.custom_audienc_id = this.orientation.retargetingTagsExclude.split(
","
);
} else if (this.orientation.retargetingTagsInclude != null) {
this.allowDirect = "retargetingTagsInclude";
this.custom_audienc_id = this.orientation.retargetingTagsInclude.split(
","
);
} else if (this.orientation.selectHisPack != null) {
this.activeName = "second";
} else {
this.crowdValue = "不限";
this.logicShow = false;
}
},
resetStatus(action, id) {
resetPutinStatus({ action: action, id: id }).then((resp) => {
......@@ -2224,7 +1589,7 @@ export default {
// 推广文案回显
let texts = item.makeCreative.textGroup;
this.arrays.textGroup = JSON.parse(texts);
this.putinTask.headlines = JSON.parse(texts);
// 推广卖点回显
let psp = item.makeCreative.productSellingPoints;
......@@ -2242,8 +1607,6 @@ export default {
this.crowdValue = "自定义人群";
this.logicShow = true;
/* 定向逻辑回显 */
this.saveLogic(item);
/* 选择媒体时的回显 */
this.change_putinInventory();
......@@ -2294,8 +1657,8 @@ export default {
receiveData(textData) {
// console.log("文案数据", textData);
textData.forEach((item) => {
if (this.arrays.textGroup.indexOf(item) === -1) {
this.arrays.textGroup.push(item);
if (this.putinTask.headlines.indexOf(item) === -1) {
this.putinTask.headlines.push(item);
}
});
},
......@@ -2317,7 +1680,7 @@ export default {
/* 删除表单 */
removeText(i) {
this.arrays.textGroup.splice(i, 1);
this.putinTask.headlines.splice(i, 1);
},
/* tab栏切换时触发 参数为被选中的tab */
......@@ -2403,7 +1766,7 @@ export default {
/* 清空选中的文案 */
removeAll() {
this.arrays.textGroup = [];
this.putinTask.headlines = [];
},
/* 清空创意分类中的标签 */
......@@ -2580,6 +1943,26 @@ export default {
if (this.dailyBudget !== '' && !isNaN(Number(this.dailyBudget))) {
this.dailyBudget = Number(this.dailyBudget).toFixed(2);
}
},
handleChangeApp(item){
this.putinFetchAccount()
if(this.putinTask.taskName == ''){
this.putinTask.taskName = `${item.label}-${moment().format("YYYY-MM-DD HH:mm:ss")}`
}
if(this.putinTask.campaignName == ''){
this.putinTask.campaignName = `${item.label}-${moment().format("YYYY-MM-DD HH:mm:ss")}`
}
if(this.putinTask.adGroupName == ''){
this.putinTask.adGroupName = `adGroup -${moment().format("YYYY-MM-DD HH:mm:ss")}`
}
},
filterAccount(query, item){
query = query.toLowerCase()
return item.key.toString().toLowerCase().includes(query)||item.label.toString().toLowerCase().includes(query)
}
},
};
......
......@@ -241,8 +241,8 @@ export default {
methods: {
APIgetSelectApps() {
const params = {
platformId: 4,
menuCode: "putin.apps",
platformId: 5,
menuCode: "game.Overview,android",
};
getSelectApps(params).then((res) => {
console.log("创意素材组下的下拉列表", res);
......
......@@ -484,8 +484,8 @@ export default {
// 创意素材组获取列表
APIgetSelectApps() {
const params = {
platformId: 4,
menuCode: "putin.apps",
platformId: 5,
menuCode: "game.Overview,android",
isGroup: "group",
};
getSelectApps(params).then((res) => {
......
......@@ -740,8 +740,8 @@ export default {
methods: {
APIgetSelectApps() {
const params = {
platformId: 4,
menuCode: "putin.apps",
platformId: 5,
menuCode: "game.Overview,android",
};
getSelectApps(params).then((res) => {
// console.log("创意素材组下的下拉列表", res);
......
......@@ -4,18 +4,12 @@
<el-tab-pane label="素材组" name="first">
<materialGroup v-if="isFirst"> </materialGroup>
</el-tab-pane>
<el-tab-pane label="衍生组" name="derive">
<materialDerive v-if="isDerive"> </materialDerive>
</el-tab-pane>
<el-tab-pane label="视图素材" name="second">
<materiallibrary v-if="isSecond"></materiallibrary>
</el-tab-pane>
<el-tab-pane label="文案素材" name="copywriting">
<copywritinglibrary v-if="isCopywriting"></copywritinglibrary>
</el-tab-pane>
<el-tab-pane label="试玩素材" name="tryplaymaterial">
<try-play-material v-if="isTryPlayMaterial" />
</el-tab-pane>
<el-tab-pane label="素材推荐" name="materialRecommend">
<material-recommend v-if="isRecommend" />
</el-tab-pane>
......@@ -27,7 +21,6 @@
// import { getUrlKey } from "../uti";
import { getEnums, getSelectApps } from "@/api/cloud";
import materialGroup from "./common/materialGroup";
import materialDerive from "./common/materialDerive";
import copywritinglibrary from "./common/copywritinglibrary";
import materiallibrary from "./common/materiallibrary";
import TryPlayMaterial from "./common/TryPlayMaterial";
......@@ -37,8 +30,6 @@ export default {
materialGroup,
copywritinglibrary,
materiallibrary,
materialDerive,
TryPlayMaterial,
MaterialRecommend,
},
data() {
......@@ -47,10 +38,8 @@ export default {
checkAll: false,
activeName: "first",
isFirst: true,
isDerive: false,
isSecond: false,
isCopywriting: false,
isTryPlayMaterial: false,
isRecommend: false,
/* 提取任务*/
options2: [],
......@@ -92,43 +81,26 @@ export default {
this.isFirst = true;
this.isSecond = false;
this.isCopywriting = false;
this.isDerive = false;
this.isTryPlayMaterial = false;
this.isRecommend = false;
} else if (tab.name === "second") {
this.isFirst = false;
this.isSecond = true;
this.isCopywriting = false;
this.isDerive = false;
this.isTryPlayMaterial = false;
this.isRecommend = false;
} else if (tab.name === "copywriting") {
this.isFirst = false;
this.isSecond = false;
this.isCopywriting = true;
this.isDerive = false;
this.isTryPlayMaterial = false;
this.isRecommend = false;
} else if (tab.name === "derive") {
this.isFirst = false;
this.isSecond = false;
this.isCopywriting = false;
this.isDerive = true;
this.isTryPlayMaterial = false;
this.isRecommend = false;
} else if (tab.name === "tryplaymaterial") {
this.isFirst = false;
this.isSecond = false;
this.isCopywriting = false;
this.isDerive = false;
this.isTryPlayMaterial = true;
this.isRecommend = false;
} else if (tab.name == "materialRecommend") {
this.isFirst = false;
this.isSecond = false;
this.isCopywriting = false;
this.isDerive = false;
this.isTryPlayMaterial = false;
this.isRecommend = true;
}
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment