|
@@ -5,14 +5,15 @@
|
|
|
* @Author: Cheney
|
|
|
*/
|
|
|
|
|
|
-import { ref, computed, onBeforeUnmount } from 'vue';
|
|
|
-import { Plus } from '@element-plus/icons-vue';
|
|
|
+import { computed, ref } from 'vue';
|
|
|
+import { Bottom, InfoFilled, Plus, Top } 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;
|
|
@@ -44,12 +45,16 @@ const candidateFields = [
|
|
|
{ label: '关键词名称', value: 'keywords', type: 'array' },
|
|
|
];
|
|
|
|
|
|
+const isVisible = ref(true);
|
|
|
+const setting = ref('edit');
|
|
|
+
|
|
|
const { getSymbolOptions } = useSymbolOptions(candidateFields);
|
|
|
const maxIsDisabled = ref([]);
|
|
|
const minIsDisabled = ref([]);
|
|
|
const ruleFormRef = ref();
|
|
|
const condiBuilderRef = ref();
|
|
|
-const actionModel = ref('bid-ratio');
|
|
|
+const actionModel = ref([]);
|
|
|
+let ruleInfo = {};
|
|
|
|
|
|
const maxRuleNumber = computed(() => {
|
|
|
const ret = {
|
|
@@ -64,10 +69,10 @@ const maxRuleNumber = computed(() => {
|
|
|
return ret;
|
|
|
});
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- maxIsDisabled.value.push(!props.rule.action.max);
|
|
|
- minIsDisabled.value.push(!props.rule.action.min);
|
|
|
-})
|
|
|
+
|
|
|
+watch(() => props.rule, (newRule) => {
|
|
|
+ ruleInfo = newRule.conditions[0].action;
|
|
|
+});
|
|
|
|
|
|
function checkFloat(rule: any, value: any, callback: any) {
|
|
|
if (XEUtils.toNumber(value) <= 0) {
|
|
@@ -115,15 +120,19 @@ function addRule(actionType: string, index: number = -1) {
|
|
|
};
|
|
|
|
|
|
if (index === -1) {
|
|
|
+ // 第一条规则
|
|
|
props.rule.conditions.push(rule);
|
|
|
- if (actionType === 'increase'){
|
|
|
- maxIsDisabled.value.push(false);
|
|
|
- }else if (actionType === 'decrease'){
|
|
|
- minIsDisabled.value.push(false);
|
|
|
+ if (actionType === 'increase') {
|
|
|
+ actionModel.value.push('bid-ratio');
|
|
|
+ maxIsDisabled.value.push(ruleInfo.max !== '' && ruleInfo.max !== undefined);
|
|
|
+ } else if (actionType === 'decrease') {
|
|
|
+ actionModel.value.push('bid-ratio');
|
|
|
+ minIsDisabled.value.push(ruleInfo.min);
|
|
|
}
|
|
|
} else {
|
|
|
props.rule.conditions.splice(index + 1, 0, rule);
|
|
|
maxIsDisabled.value.splice(index + 1, 0, false); // 添加一个初始值
|
|
|
+ actionModel.value.splice(index + 1, 0, 'bid-ratio'); // 添加一个初始值
|
|
|
minIsDisabled.value.splice(index + 1, 0, false); // 添加一个初始值
|
|
|
}
|
|
|
}
|
|
@@ -131,20 +140,21 @@ function addRule(actionType: string, index: number = -1) {
|
|
|
if (props.rule.conditions.length === 0) {
|
|
|
props.rule.campaignType = 'sp';
|
|
|
props.rule.activeModel = 'campaign';
|
|
|
- // addRule('increase', -1);
|
|
|
+ console.log('actionModel.value',actionModel.value);
|
|
|
+ addRule('increase', -1);
|
|
|
}
|
|
|
|
|
|
-function delRule(index: number) {
|
|
|
+function delRule(actionType: string, index: number) {
|
|
|
props.rule.conditions.splice(index, 1);
|
|
|
- if (actionType === 'increase'){
|
|
|
+ if (actionType === 'increase') {
|
|
|
maxIsDisabled.value.splice(index, 1);
|
|
|
- }else if (actionType === 'decrease'){
|
|
|
+ } else if (actionType === 'decrease') {
|
|
|
minIsDisabled.value.splice(index, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function changeAction(action: any) {
|
|
|
- const [a, b] = actionModel.value.split('-');
|
|
|
+function changeAction(actionModel: any, action: any) {
|
|
|
+ const [a, b] = actionModel.split('-');
|
|
|
action.baseType = a;
|
|
|
action.numType = b;
|
|
|
action.set = '';
|
|
@@ -174,25 +184,60 @@ async function validateRuleForm() {
|
|
|
}
|
|
|
|
|
|
async function validateForm() {
|
|
|
+ // 当没有勾选最大值、最小值时,清空action的max和min值
|
|
|
+ props.rule.conditions.forEach((condition, index) => {
|
|
|
+ if (!maxIsDisabled.value[index]) {
|
|
|
+ condition.action.max = '';
|
|
|
+ }
|
|
|
+ if (!minIsDisabled.value[index]) {
|
|
|
+ condition.action.min = '';
|
|
|
+ }
|
|
|
+ });
|
|
|
const valid1 = await validateRuleForm();
|
|
|
const valid2 = await validateConditionsForm();
|
|
|
return valid1 && valid2;
|
|
|
}
|
|
|
|
|
|
-function onMaxCheckboxChange(index: number) {
|
|
|
- if (!maxIsDisabled.value[index]) {
|
|
|
- // 如果复选框被取消勾选,禁用输入框并清空对应的值
|
|
|
- props.rule.conditions[index].action.max = '';
|
|
|
+function handleClose() {
|
|
|
+ isVisible.value = false;
|
|
|
+}
|
|
|
+
|
|
|
+function moveUp(index) {
|
|
|
+ if (index > 0) {
|
|
|
+ const temp = props.rule.conditions[index];
|
|
|
+ props.rule.conditions[index] = props.rule.conditions[index - 1];
|
|
|
+ props.rule.conditions[index - 1] = temp;
|
|
|
+ // 更新ordering
|
|
|
+ updateOrdering();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function onMinCheckboxChange(index: number) {
|
|
|
- if (!minIsDisabled.value[index]) {
|
|
|
- // 如果复选框被取消勾选,禁用输入框并清空对应的值
|
|
|
- props.rule.conditions[index].action.min = '';
|
|
|
+function moveDown(index) {
|
|
|
+ if (index < props.rule.conditions.length - 1) {
|
|
|
+ const temp = props.rule.conditions[index];
|
|
|
+ props.rule.conditions[index] = props.rule.conditions[index + 1];
|
|
|
+ props.rule.conditions[index + 1] = temp;
|
|
|
+ // 更新ordering
|
|
|
+ updateOrdering();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function updateOrdering() {
|
|
|
+ props.rule.conditions.forEach((condition, index) => {
|
|
|
+ condition.ordering = index + 1; // 重新计算ordering,从1开始
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function getActionModelLabel(value) {
|
|
|
+ const option = ActionList.find(option => option.value === value);
|
|
|
+ return option ? option.label : '';
|
|
|
+}
|
|
|
+
|
|
|
+// 获取对应 set 值的后缀
|
|
|
+function getSetSuffix(numType) {
|
|
|
+ return numType === 'num' ? '$' : numType === 'ratio' ? '%' : '';
|
|
|
+}
|
|
|
+
|
|
|
defineExpose({ validateForm });
|
|
|
</script>
|
|
|
|
|
@@ -202,22 +247,42 @@ defineExpose({ validateForm });
|
|
|
<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>
|
|
|
+ <el-tag v-if="isVisible" class="custom-tag" closable color="#e7edf4" @close="handleClose">
|
|
|
+ <template #default>
|
|
|
+ <div class="tag-content">
|
|
|
+ <el-icon style="color: #0b52a7">
|
|
|
+ <InfoFilled />
|
|
|
+ </el-icon>
|
|
|
+ 可设置多个规则,如果一个对象命中多个规则,系统只是执行优先级最高的规则
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="mt-5">
|
|
|
+ <el-radio-group v-model="setting" size="small">
|
|
|
+ <el-radio-button label="编辑" value="edit" />
|
|
|
+ <el-radio-button label="排序" value="order" />
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="setting === 'edit'" class="rule-setting-container">
|
|
|
+ <div v-for="(info, index) in rule.conditions" :key="info.actionType + info.ordering" class="rule-setting-item">
|
|
|
<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">
|
|
|
+ <el-tooltip v-if="!disabled" content="添加规则" effect="dark" placement="top">
|
|
|
+ <el-icon :disabled="disabled" @click="addRule(info.actionType, index)">
|
|
|
<Plus />
|
|
|
</el-icon>
|
|
|
</el-tooltip>
|
|
|
- <el-tooltip content="删除规则" placement="top" effect="dark" v-if="rule.conditions.length !== 1 && !disabled">
|
|
|
- <el-icon @click="delRule(index)">
|
|
|
+ <el-tooltip v-if="rule.conditions.length !== 1 && !disabled" content="删除规则" effect="dark"
|
|
|
+ placement="top">
|
|
|
+ <el-icon @click="delRule(info.actionType,index)">
|
|
|
<DeleteFilled />
|
|
|
</el-icon>
|
|
|
</el-tooltip>
|
|
|
- <el-tooltip content="收起/展开规则" placement="top" effect="dark">
|
|
|
+ <el-tooltip content="收起/展开规则" effect="dark" placement="top">
|
|
|
<el-icon @click="info.show = !info.show">
|
|
|
<ArrowDown />
|
|
|
</el-icon>
|
|
@@ -225,62 +290,92 @@ defineExpose({ validateForm });
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-show="info.show">
|
|
|
- <el-form :inline="true" :model="info.action" ref="ruleFormRef" :disabled="disabled">
|
|
|
+ <el-form ref="ruleFormRef" :disabled="disabled" :inline="true" :model="info.action">
|
|
|
<!-- 竞价规则下面的下拉框和两个输入框 -->
|
|
|
<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-select v-model="actionModel[index]" style="width: 250px"
|
|
|
+ @change="changeAction(actionModel[index], info.action)">
|
|
|
<el-option
|
|
|
- v-for="item in ActionList"
|
|
|
- :key="item.value"
|
|
|
- :value="item.value"
|
|
|
- :label="item.label.replace('_', info.actionType === 'increase' ? '升高' : '降低')">
|
|
|
+ v-for="item in ActionList"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label.replace('_', info.actionType === 'increase' ? '升高' : '降低')"
|
|
|
+ :value="item.value">
|
|
|
</el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
- <el-form-item prop="set" :rules="{ validator: checkFloat }">
|
|
|
+ <el-form-item :rules="{ validator: checkFloat }" prop="set">
|
|
|
<InputFloat
|
|
|
- v-model="info.action.set"
|
|
|
- :prefix="info.action.numType === 'num' ? '$' : ''"
|
|
|
- :suffix="info.action.numType === 'ratio' ? '%' : ''"
|
|
|
- style="width: 120px">
|
|
|
+ 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">
|
|
|
+ <el-form-item v-if="info.actionType === 'increase'" label="最大值" prop="max">
|
|
|
<template v-slot:label>
|
|
|
- <el-checkbox v-model="maxIsDisabled[index]" @change="onMaxCheckboxChange(index)">最大值</el-checkbox>
|
|
|
+ <el-checkbox v-model="maxIsDisabled[index]">最大值</el-checkbox>
|
|
|
</template>
|
|
|
- <InputFloat :disabled="!maxIsDisabled[index]" v-model="info.action.max" style="width: 120px" prefix="$"></InputFloat>
|
|
|
+ <InputFloat v-model="info.action.max" :disabled="!maxIsDisabled[index]" prefix="$"
|
|
|
+ style="width: 120px"></InputFloat>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="最小值" v-else prop="min" >
|
|
|
+ <el-form-item v-else label="最小值" prop="min">
|
|
|
<template v-slot:label>
|
|
|
- <el-checkbox v-model="minIsDisabled[index]" @change="onMinCheckboxChange(index)">最小值</el-checkbox>
|
|
|
+ <el-checkbox v-model="minIsDisabled[index]">最小值</el-checkbox>
|
|
|
</template>
|
|
|
- <InputFloat :disabled="!minIsDisabled[index]" v-model="info.action.min" style="width: 120px" prefix="$"></InputFloat>
|
|
|
+ <InputFloat v-model="info.action.min" :disabled="!minIsDisabled[index]" prefix="$"
|
|
|
+ style="width: 120px"></InputFloat>
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
<el-form-item v-if="info.actionType === 'set'" prop="set">
|
|
|
- <InputFloat v-model="info.action.set" style="width: 120px" prefix="$"></InputFloat>
|
|
|
+ <InputFloat v-model="info.action.set" prefix="$" style="width: 120px"></InputFloat>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<conditionBuilder
|
|
|
- :data="info.conditions"
|
|
|
- :candidate-fields="candidateFields"
|
|
|
- ref="condiBuilderRef"
|
|
|
- :disabled="disabled" />
|
|
|
+ ref="condiBuilderRef"
|
|
|
+ :candidate-fields="candidateFields"
|
|
|
+ :data="info.conditions"
|
|
|
+ :disabled="disabled" />
|
|
|
</div>
|
|
|
</div>
|
|
|
- <el-popover placement="bottom-start" trigger="hover" :disabled="disabled">
|
|
|
+ <el-popover :disabled="disabled" placement="bottom-start" trigger="hover">
|
|
|
<template #reference>
|
|
|
- <el-button :icon="Plus" type="warning" :disabled="disabled">添加规则</el-button>
|
|
|
+ <el-button :disabled="disabled" :icon="Plus" type="warning">添加规则</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>
|
|
|
+ <span v-for="[name, title] of Object.entries(RuleNameMap)" class="popver-content-item" @click="addRule(name)">{{
|
|
|
+ title
|
|
|
+ }}</span>
|
|
|
</div>
|
|
|
</el-popover>
|
|
|
</div>
|
|
|
+ <div v-if="setting === 'order'" class="mt-2">
|
|
|
+ <div v-for="(info, index) in rule.conditions" :key="info.actionType + info.ordering">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="20">
|
|
|
+ <el-card body-style="padding: 12px 10px;" class="rule-setting-item" draggable="true" shadow="hover">
|
|
|
+ {{ RuleNameMap[info.actionType] }} - 规则{{ info.ordering }}
|
|
|
+ <span v-if="info.actionType === 'increase' || info.actionType === 'decrease'">
|
|
|
+ {{
|
|
|
+ getActionModelLabel(actionModel[index]).replace('_', info.actionType === 'increase' ? '升高' : '降低')
|
|
|
+ }}
|
|
|
+ {{ info.action.set }}
|
|
|
+ <span v-if="info.action.set && info.action.numType">
|
|
|
+ {{ getSetSuffix(info.action.numType) }}
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4">
|
|
|
+ <div class="mt-3 pl-2">
|
|
|
+ <el-button :disabled="index === 0" :icon="Top" link type="primary" @click="moveUp(index)"></el-button>
|
|
|
+ <el-button :disabled="index === rule.conditions.length - 1" :icon="Bottom" link type="primary"
|
|
|
+ @click="moveDown(index)"></el-button>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -336,4 +431,19 @@ defineExpose({ validateForm });
|
|
|
position: absolute;
|
|
|
transform: translateY(25%);
|
|
|
}
|
|
|
+
|
|
|
+.tag-content {
|
|
|
+ display: block;
|
|
|
+ max-width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.rule-setting-item {
|
|
|
+ width: 100%;
|
|
|
+ margin: 5px 0;
|
|
|
+ padding: 0;
|
|
|
+ border-radius: 0 !important;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
</style>
|