|
@@ -1,87 +1,24 @@
|
|
|
-<template>
|
|
|
- <el-card>
|
|
|
- <div class="asj-h3">
|
|
|
- <span class="custom-title-icon"></span>
|
|
|
- 规则设置
|
|
|
- </div>
|
|
|
- <div class="rule-setting-container">
|
|
|
- <div v-for="(info, index) in rule.conditions" class="rule-setting-item" :key="info.actionType + info.ordering">
|
|
|
- <div class="rule-setting-title">
|
|
|
- <div class="asj-h3">{{ RuleNameMap[info.actionType] }} - 规则{{ info.ordering }}</div>
|
|
|
- <div class="rule-setting-opration">
|
|
|
- <el-tooltip content="添加规则" placement="top" effect="dark" v-if="!disabled">
|
|
|
- <el-icon @click="addRule(info.actionType, index)" :disabled="disabled"><Plus /></el-icon>
|
|
|
- </el-tooltip>
|
|
|
- <el-tooltip content="删除规则" placement="top" effect="dark" v-if="rule.conditions.length !== 1 && !disabled">
|
|
|
- <el-icon @click="delRule(index)"><DeleteFilled /></el-icon>
|
|
|
- </el-tooltip>
|
|
|
- <el-tooltip content="收起/展开规则" placement="top" effect="dark">
|
|
|
- <el-icon @click="info.show = !info.show"><ArrowDown /></el-icon>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div v-show="info.show">
|
|
|
- <el-form :inline="true" :model="info.action" ref="ruleFormRef" :disabled="disabled">
|
|
|
- <div v-if="info.actionType === 'increase' || info.actionType === 'decrease'">
|
|
|
- <el-form-item>
|
|
|
- <el-select v-model="actionModel" @change="changeAction(info.action)" style="width: 250px">
|
|
|
- <el-option
|
|
|
- v-for="item in ActionList"
|
|
|
- :key="item.value"
|
|
|
- :value="item.value"
|
|
|
- :label="item.label.replace('_', info.actionType === 'increase' ? '升高' : '降低')">
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="set" :rules="{ validator: checkFloat }">
|
|
|
- <InputFloat
|
|
|
- v-model="info.action.set"
|
|
|
- :prefix="info.action.numType === 'num' ? '$' : ''"
|
|
|
- :suffix="info.action.numType === 'ratio' ? '%' : ''"
|
|
|
- style="width: 120px">
|
|
|
- </InputFloat>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="最大值" v-if="info.actionType === 'increase'" prop="max" :rules="{ validator: checkMinMax }">
|
|
|
- <InputFloat v-model="info.action.max" style="width: 120px" prefix="$"></InputFloat>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="最小值" v-else prop="min" :rules="{ validator: checkMinMax }">
|
|
|
- <InputFloat v-model="info.action.min" style="width: 120px" prefix="$"></InputFloat>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <el-form-item v-if="info.actionType === 'set'" prop="set">
|
|
|
- <el-input v-model="info.action.set"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- <conditionBuilder :data="info.conditions" :candidate-fields="candidateFields" ref="condiBuilderRef" :disabled="disabled" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <el-popover placement="bottom-start" trigger="hover" :disabled="disabled">
|
|
|
- <template #reference>
|
|
|
- <el-button :icon="Plus" type="warning" :disabled="disabled">添加规则</el-button>
|
|
|
- </template>
|
|
|
- <div class="popver-content">
|
|
|
- <span class="popver-content-item" v-for="[name, title] of Object.entries(RuleNameMap)" @click="addRule(name)">{{ title }}</span>
|
|
|
- </div>
|
|
|
- </el-popover>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
-</template>
|
|
|
-
|
|
|
<script lang="ts" setup>
|
|
|
-import { ref, computed } from 'vue'
|
|
|
-import { Plus } from '@element-plus/icons-vue'
|
|
|
-import conditionBuilder from '/@/components/conditionBuilder/index.vue'
|
|
|
-import InputFloat from '/@/components/input-float/index.vue'
|
|
|
-import { useSymbolOptions } from '/@/components/conditionBuilder/utils'
|
|
|
-import { ActionList, RuleNameMap } from './enum'
|
|
|
+/**
|
|
|
+ * @Name: target-rule-setting
|
|
|
+ * @Description: 自动化-规则定向-规则设置
|
|
|
+ * @Author: Cheney
|
|
|
+ */
|
|
|
|
|
|
-import XEUtils from 'xe-utils'
|
|
|
+import { ref, computed } from 'vue';
|
|
|
+import { Plus } from '@element-plus/icons-vue';
|
|
|
+import conditionBuilder from '/@/components/conditionBuilder/index.vue';
|
|
|
+import InputFloat from '/@/components/input-float/index.vue';
|
|
|
+import { useSymbolOptions } from '/@/components/conditionBuilder/utils';
|
|
|
+import { ActionList, RuleNameMap } from './enum';
|
|
|
+import XEUtils from 'xe-utils';
|
|
|
|
|
|
interface Props {
|
|
|
- rule: AutoRule
|
|
|
- disabled?: boolean
|
|
|
+ rule: AutoRule;
|
|
|
+ disabled?: boolean;
|
|
|
}
|
|
|
-const props = defineProps<Props>()
|
|
|
+
|
|
|
+const props = defineProps<Props>();
|
|
|
const candidateFields = [
|
|
|
{ label: '曝光量', value: 'impressions' },
|
|
|
{ label: '点击量', value: 'clicks' },
|
|
@@ -104,40 +41,46 @@ const candidateFields = [
|
|
|
{ label: '商品-单个商品', value: 'asin' },
|
|
|
],
|
|
|
},
|
|
|
- { label: '关键词名称', value: 'keywords', type: 'array' }
|
|
|
-]
|
|
|
-const { getSymbolOptions } = useSymbolOptions(candidateFields)
|
|
|
-const ruleFormRef = ref()
|
|
|
-const condiBuilderRef = ref()
|
|
|
-const checkFloat = (rule: any, value: any, callback: any) => {
|
|
|
- if (XEUtils.toNumber(value) <= 0) {
|
|
|
- callback(new Error('请输入大于0的数值!'))
|
|
|
- } else {
|
|
|
- callback()
|
|
|
- }
|
|
|
-}
|
|
|
-const checkMinMax = (rule: any, value: any, callback: any) => {
|
|
|
- if (XEUtils.toNumber(value) <= 0) {
|
|
|
- callback(new Error('请输入大于0的数值!'))
|
|
|
- } else {
|
|
|
- callback()
|
|
|
- }
|
|
|
-}
|
|
|
+ { label: '关键词名称', value: 'keywords', type: 'array' },
|
|
|
+];
|
|
|
+
|
|
|
+const { getSymbolOptions } = useSymbolOptions(candidateFields);
|
|
|
+const ruleFormRef = ref();
|
|
|
+const condiBuilderRef = ref();
|
|
|
+const actionModel = ref('bid-ratio');
|
|
|
+
|
|
|
const maxRuleNumber = computed(() => {
|
|
|
const ret = {
|
|
|
increase: 0,
|
|
|
decrease: 0,
|
|
|
set: 0,
|
|
|
pause: 0,
|
|
|
- }
|
|
|
+ };
|
|
|
for (const info of props.rule.conditions) {
|
|
|
- ret[info.actionType] = Math.max(ret[info.actionType] || 0, info.ordering)
|
|
|
+ ret[info.actionType] = Math.max(ret[info.actionType] || 0, info.ordering);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+});
|
|
|
+
|
|
|
+function checkFloat(rule: any, value: any, callback: any) {
|
|
|
+ if (XEUtils.toNumber(value) <= 0) {
|
|
|
+ callback(new Error('请输入大于0的数值!'));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function checkMinMax(rule: any, value: any, callback: any) {
|
|
|
+ if (XEUtils.toNumber(value) <= 0) {
|
|
|
+ callback(new Error('请输入大于0的数值!'));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
}
|
|
|
- return ret
|
|
|
-})
|
|
|
-const addRule = (actionType: string, index: number = -1) => {
|
|
|
- const field = candidateFields[0].value
|
|
|
- const symbol = getSymbolOptions(field)[0].value
|
|
|
+}
|
|
|
+
|
|
|
+function addRule(actionType: string, index: number = -1) {
|
|
|
+ const field = candidateFields[0].value;
|
|
|
+ const symbol = getSymbolOptions(field)[0].value;
|
|
|
const rule = {
|
|
|
action: { set: '', baseType: '', max: '', min: '', numType: 'ratio' },
|
|
|
actionType: actionType,
|
|
@@ -162,62 +105,145 @@ const addRule = (actionType: string, index: number = -1) => {
|
|
|
exceptDay: '',
|
|
|
ordering: maxRuleNumber.value[actionType] + 1,
|
|
|
show: true,
|
|
|
- }
|
|
|
+ };
|
|
|
if (index === -1) {
|
|
|
- props.rule.conditions.push(rule)
|
|
|
+ props.rule.conditions.push(rule);
|
|
|
} else {
|
|
|
- props.rule.conditions.splice(index + 1, 0, rule)
|
|
|
+ props.rule.conditions.splice(index + 1, 0, rule);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
if (props.rule.conditions.length === 0) {
|
|
|
- props.rule.campaignType = 'sp'
|
|
|
- props.rule.activeModel = 'campaign'
|
|
|
- addRule('increase', -1)
|
|
|
+ props.rule.campaignType = 'sp';
|
|
|
+ props.rule.activeModel = 'campaign';
|
|
|
+ addRule('increase', -1);
|
|
|
}
|
|
|
|
|
|
-const delRule = (index: number) => {
|
|
|
- props.rule.conditions.splice(index, 1)
|
|
|
+function delRule(index: number) {
|
|
|
+ props.rule.conditions.splice(index, 1);
|
|
|
}
|
|
|
|
|
|
-const actionModel = ref('bid-ratio')
|
|
|
-const changeAction = (action: any) => {
|
|
|
- const [a, b] = actionModel.value.split('-')
|
|
|
- action.baseType = a
|
|
|
- action.numType = b
|
|
|
- action.set = ''
|
|
|
+function changeAction(action: any) {
|
|
|
+ const [a, b] = actionModel.value.split('-');
|
|
|
+ action.baseType = a;
|
|
|
+ action.numType = b;
|
|
|
+ action.set = '';
|
|
|
}
|
|
|
|
|
|
-const validateConditionsForm = async () => {
|
|
|
- const ret = []
|
|
|
+async function validateConditionsForm() {
|
|
|
+ const ret = [];
|
|
|
for (const f of condiBuilderRef.value) {
|
|
|
- ret.push(await f.validate())
|
|
|
+ ret.push(await f.validate());
|
|
|
}
|
|
|
for (const validList of ret) {
|
|
|
if (validList.includes(false)) {
|
|
|
- return false
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
- return true
|
|
|
+ return true;
|
|
|
}
|
|
|
-const validateRuleForm = async () => {
|
|
|
- const ret = []
|
|
|
+
|
|
|
+async function validateRuleForm() {
|
|
|
+ const ret = [];
|
|
|
for (const f of ruleFormRef.value) {
|
|
|
await f.validate((valid: boolean) => {
|
|
|
- ret.push(valid)
|
|
|
- })
|
|
|
+ ret.push(valid);
|
|
|
+ });
|
|
|
}
|
|
|
- return !ret.includes(false)
|
|
|
+ return !ret.includes(false);
|
|
|
}
|
|
|
|
|
|
-const validateForm = async () => {
|
|
|
- const valid1 = await validateRuleForm()
|
|
|
- const valid2 = await validateConditionsForm()
|
|
|
- return valid1 && valid2
|
|
|
+async function validateForm() {
|
|
|
+ const valid1 = await validateRuleForm();
|
|
|
+ const valid2 = await validateConditionsForm();
|
|
|
+ return valid1 && valid2;
|
|
|
}
|
|
|
|
|
|
-defineExpose({ validateForm })
|
|
|
+defineExpose({ validateForm });
|
|
|
</script>
|
|
|
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <div class="asj-h3">
|
|
|
+ <span class="custom-title-icon"></span>
|
|
|
+ 规则设置
|
|
|
+ </div>
|
|
|
+ <div class="rule-setting-container">
|
|
|
+ <div v-for="(info, index) in rule.conditions" class="rule-setting-item" :key="info.actionType + info.ordering">
|
|
|
+ <div class="rule-setting-title">
|
|
|
+ <div class="asj-h3">{{ RuleNameMap[info.actionType] }} - 规则{{ info.ordering }}</div>
|
|
|
+ <div class="rule-setting-opration">
|
|
|
+ <el-tooltip content="添加规则" placement="top" effect="dark" v-if="!disabled">
|
|
|
+ <el-icon @click="addRule(info.actionType, index)" :disabled="disabled">
|
|
|
+ <Plus />
|
|
|
+ </el-icon>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="删除规则" placement="top" effect="dark" v-if="rule.conditions.length !== 1 && !disabled">
|
|
|
+ <el-icon @click="delRule(index)">
|
|
|
+ <DeleteFilled />
|
|
|
+ </el-icon>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="收起/展开规则" placement="top" effect="dark">
|
|
|
+ <el-icon @click="info.show = !info.show">
|
|
|
+ <ArrowDown />
|
|
|
+ </el-icon>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-show="info.show">
|
|
|
+ <el-form :inline="true" :model="info.action" ref="ruleFormRef" :disabled="disabled">
|
|
|
+ <!-- 竞价规则下面的下拉框和两个输入框 -->
|
|
|
+ <div v-if="info.actionType === 'increase' || info.actionType === 'decrease'">
|
|
|
+ <el-form-item>
|
|
|
+ <el-select v-model="actionModel" @change="changeAction(info.action)" style="width: 250px">
|
|
|
+ <el-option
|
|
|
+ v-for="item in ActionList"
|
|
|
+ :key="item.value"
|
|
|
+ :value="item.value"
|
|
|
+ :label="item.label.replace('_', info.actionType === 'increase' ? '升高' : '降低')">
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="set" :rules="{ validator: checkFloat }">
|
|
|
+ <InputFloat
|
|
|
+ v-model="info.action.set"
|
|
|
+ :prefix="info.action.numType === 'num' ? '$' : ''"
|
|
|
+ :suffix="info.action.numType === 'ratio' ? '%' : ''"
|
|
|
+ style="width: 120px">
|
|
|
+ </InputFloat>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="最大值" v-if="info.actionType === 'increase'" prop="max" :rules="{ validator: checkMinMax }">
|
|
|
+ <InputFloat v-model="info.action.max" style="width: 120px" prefix="$"></InputFloat>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="最小值" v-else prop="min" :rules="{ validator: checkMinMax }">
|
|
|
+ <InputFloat v-model="info.action.min" style="width: 120px" prefix="$"></InputFloat>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <el-form-item v-if="info.actionType === 'set'" prop="set">
|
|
|
+ <el-input v-model="info.action.set"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <conditionBuilder
|
|
|
+ :data="info.conditions"
|
|
|
+ :candidate-fields="candidateFields"
|
|
|
+ ref="condiBuilderRef"
|
|
|
+ :disabled="disabled" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-popover placement="bottom-start" trigger="hover" :disabled="disabled">
|
|
|
+ <template #reference>
|
|
|
+ <el-button :icon="Plus" type="warning" :disabled="disabled">添加规则</el-button>
|
|
|
+ </template>
|
|
|
+ <div class="popver-content">
|
|
|
+ <span class="popver-content-item" v-for="[name, title] of Object.entries(RuleNameMap)" @click="addRule(name)">{{
|
|
|
+ title
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
<style lang="scss" scoped>
|
|
|
.popver-content {
|
|
|
display: flex;
|