提交 22f299a5 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 群组规则配置

上级 fa868381
...@@ -113,6 +113,7 @@ ...@@ -113,6 +113,7 @@
"useArrayMap": true, "useArrayMap": true,
"useArrayReduce": true, "useArrayReduce": true,
"useArraySome": true, "useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true, "useAsyncQueue": true,
"useAsyncState": true, "useAsyncState": true,
"useAttrs": true, "useAttrs": true,
...@@ -196,6 +197,7 @@ ...@@ -196,6 +197,7 @@
"useParallax": true, "useParallax": true,
"usePermission": true, "usePermission": true,
"usePointer": true, "usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true, "usePointerSwipe": true,
"usePreferredColorScheme": true, "usePreferredColorScheme": true,
"usePreferredContrast": true, "usePreferredContrast": true,
......
...@@ -114,6 +114,7 @@ declare global { ...@@ -114,6 +114,7 @@ declare global {
const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
const useArraySome: typeof import('@vueuse/core')['useArraySome'] const useArraySome: typeof import('@vueuse/core')['useArraySome']
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs'] const useAttrs: typeof import('vue')['useAttrs']
...@@ -197,6 +198,7 @@ declare global { ...@@ -197,6 +198,7 @@ declare global {
const useParallax: typeof import('@vueuse/core')['useParallax'] const useParallax: typeof import('@vueuse/core')['useParallax']
const usePermission: typeof import('@vueuse/core')['usePermission'] const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer'] const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
......
...@@ -54,6 +54,6 @@ export function getMetaEventList() { ...@@ -54,6 +54,6 @@ export function getMetaEventList() {
} }
// 获取实验下的所有标签 // 获取实验下的所有标签
export function getTagList(params?: { check_role?: boolean }) { export function getTagList(params?: { check_role?: 0 | 1 }) {
return httpRequest.get('/api/lab/v1/experiment/tag/all', { params }) return httpRequest.get('/api/lab/v1/experiment/tag/all', { params })
} }
.rule { .rule {
display: flex; display: flex;
.el-form-item { .el-form-item {
display: inline-flex;
margin-right: 10px; margin-right: 10px;
margin-bottom: 0; margin-bottom: 0;
} }
.el-form-item__content {
margin-left: 0 !important;
}
.el-select, .el-select,
.el-input { .el-input {
width: 120px; width: 120px;
......
...@@ -38,35 +38,44 @@ function toggleOperate(rule: EventRule) { ...@@ -38,35 +38,44 @@ function toggleOperate(rule: EventRule) {
} }
// 添加条件 // 添加条件
function handleAdd() { function handleAdd(items: EventRuleItem[]) {
eventAttrRule.value.items.push({ items.push({
happen_info: { is_happened: true, event_id: '', event_name: '', attr_list: [] }, happen_info: { is_happened: true, event_id: '', event_name: '', attr_list: [] },
trigger_info: { operate: '', operate_name: '', value: '' } trigger_info: { operate: '', operate_name: '', value: '' }
}) })
} }
// 删除条件 // 删除条件
function handleRemove(index: number) { function handleRemove(items: EventRuleItem[], index: number) {
eventAttrRule.value.items.splice(index, 1) items.splice(index, 1)
}
// 事件改变
function handleEventChange(value: string, rule: EventRuleItem) {
const currentEvent = metaEventList.value.find(item => item.id === value)
rule.happen_info.event_name = currentEvent?.name || ''
} }
// 添加属性条件 // 添加属性条件
function handleAttrAdd(attrs: RuleAttr[]) { function handleAttrAdd(attrs: RuleAttr[]) {
attrs.push({ attr_id: '', attr: '', attr_name: '', attr_type: '', operate: '', operate_name: '', value: '' }) attrs.push({ attr_id: '', attr: '', attr_name: '', attr_type: '', operate: '', operate_name: '', value: '' })
} }
// 删除属性条件 // 删除属性条件
function handleAttrRemove(attrs: RuleAttr[], index: number) { function handleAttrRemove(attrs: RuleAttr[], index: number) {
attrs.splice(index, 1) attrs.splice(index, 1)
} }
// 发生条件改变
function handleHappenOperateChange(value: string, item: EventRuleItem) {
item.happen_info.attr_list = []
item.trigger_info.value = ''
}
// 事件改变
function handleEventChange(value: string, item: EventRuleItem) {
const currentEvent = metaEventList.value.find(item => item.id === value)
item.happen_info.event_name = currentEvent?.name || ''
item.happen_info.attr_list = []
}
// 属性改变 // 属性改变
function handleAttrChange(value: string, attr: RuleAttr, rule: EventRuleItem) { function handleAttrChange(value: string, attr: RuleAttr, item: EventRuleItem) {
const found = getEventAttrList(rule.happen_info.event_id).find(item => item.id === value) const found = getEventAttrList(item.happen_info.event_id).find(item => item.id === value)
attr.attr = found?.english_name || '' attr.attr = found?.english_name || ''
attr.attr_name = found?.name || '' attr.attr_name = found?.name || ''
attr.attr_type = found?.type || '' attr.attr_type = found?.type || ''
...@@ -75,6 +84,7 @@ function handleAttrChange(value: string, attr: RuleAttr, rule: EventRuleItem) { ...@@ -75,6 +84,7 @@ function handleAttrChange(value: string, attr: RuleAttr, rule: EventRuleItem) {
attr.operate_name = '' attr.operate_name = ''
attr.value = '' attr.value = ''
} }
// 条件改变 // 条件改变
function handleOperateChange(value: string, item: RuleAttr) { function handleOperateChange(value: string, item: RuleAttr) {
const found = getOperatorList(item.attr_type).find(item => item.value === value) const found = getOperatorList(item.attr_type).find(item => item.value === value)
...@@ -82,10 +92,11 @@ function handleOperateChange(value: string, item: RuleAttr) { ...@@ -82,10 +92,11 @@ function handleOperateChange(value: string, item: RuleAttr) {
item.value = '' item.value = ''
} }
// 条件改变 // 触发条件改变
function handleTriggerOperateChange(value: string, rule: EventRuleItem) { function handleTriggerOperateChange(value: string, item: EventRuleItem) {
const found = numberOperatorList.find(item => item.value === value) const found = numberOperatorList.find(item => item.value === value)
rule.trigger_info.operate_name = found?.label || '' item.trigger_info.operate_name = found?.label || ''
item.trigger_info.value = ''
} }
</script> </script>
...@@ -104,11 +115,13 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -104,11 +115,13 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
<el-row> <el-row>
<!-- 发生 --> <!-- 发生 -->
<el-form-item> <el-form-item>
<el-select v-model="rule.happen_info.is_happened"> <el-select
v-model="rule.happen_info.is_happened"
@change="value => handleHappenOperateChange(value, rule)">
<el-option v-for="option in happenInfoList" v-bind="option"></el-option> <el-option v-for="option in happenInfoList" v-bind="option"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item v-if="rule.happen_info.is_happened">
<el-select v-model="rule.happen_info.event_id" @change="value => handleEventChange(value, rule)"> <el-select v-model="rule.happen_info.event_id" @change="value => handleEventChange(value, rule)">
<el-option <el-option
v-for="option in metaEventList" v-for="option in metaEventList"
...@@ -117,9 +130,16 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -117,9 +130,16 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
:value="option.id"></el-option> :value="option.id"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-button text :icon="Plus" @click="handleAttrAdd(rule.happen_info.attr_list)">添加条件</el-button> <el-button
<el-button text :icon="CloseBold" @click="handleRemove(index)"></el-button> text
:icon="Plus"
@click="handleAttrAdd(rule.happen_info.attr_list)"
v-if="rule.happen_info.is_happened"
>添加条件</el-button
>
<el-button text :icon="CloseBold" @click="handleRemove(eventAttrRule.items, index)"></el-button>
</el-row> </el-row>
<template v-if="rule.happen_info.is_happened">
<!-- 属性条件 --> <!-- 属性条件 -->
<el-row class="rule-item" justify="space-between" v-for="(attr, index) in rule.happen_info.attr_list"> <el-row class="rule-item" justify="space-between" v-for="(attr, index) in rule.happen_info.attr_list">
<div> <div>
...@@ -144,7 +164,10 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -144,7 +164,10 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
<el-input v-model="attr.value" /> <el-input v-model="attr.value" />
</el-form-item> </el-form-item>
</div> </div>
<el-button text :icon="CloseBold" @click="handleAttrRemove(rule.happen_info.attr_list, index)"></el-button> <el-button
text
:icon="CloseBold"
@click="handleAttrRemove(rule.happen_info.attr_list, index)"></el-button>
</el-row> </el-row>
<!-- 触发 --> <!-- 触发 -->
<el-row style="margin-top: 10px"> <el-row style="margin-top: 10px">
...@@ -154,7 +177,9 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -154,7 +177,9 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-select v-model="rule.trigger_info.operate" @change="value => handleTriggerOperateChange(value, rule)"> <el-select
v-model="rule.trigger_info.operate"
@change="value => handleTriggerOperateChange(value, rule)">
<el-option <el-option
v-for="option in numberOperatorList" v-for="option in numberOperatorList"
:label="option.alias || option.label" :label="option.alias || option.label"
...@@ -165,10 +190,11 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -165,10 +190,11 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
<el-input v-model="rule.trigger_info.value" /> <el-input v-model="rule.trigger_info.value" />
</el-form-item> </el-form-item>
</el-row> </el-row>
</template>
</section> </section>
</div> </div>
</div> </div>
<el-button text :icon="Plus" @click="handleAdd">添加条件</el-button> <el-button text :icon="Plus" @click="handleAdd(eventAttrRule.items)">添加条件</el-button>
</el-card> </el-card>
</template> </template>
......
<script setup lang="ts"></script> <script setup lang="ts">
import type { TagRule } from '@/types'
import { PriceTag, Plus, CloseBold } from '@element-plus/icons-vue'
import { useTag } from '@/composables/useAllData'
<template></template> const tagRule = ref(inject('tagRule') as TagRule)
const { tagList } = useTag()
// 获取逻辑运算符名称
function getLogicalName(value: 'and' | 'or') {
return value === 'or' ? '或' : '且'
}
// 切换逻辑运算符
function toggleOperate(rule: TagRule) {
rule.current_logic_operate = rule.current_logic_operate === 'or' ? 'and' : 'or'
}
// 添加条件
function handleAdd(items: string[]) {
items.push('')
}
// 删除
function handleRemove(items: string[], index: number) {
items.splice(index, 1)
}
</script>
<template>
<el-card shadow="never">
<template #header>
<el-button circle color="#567722" :icon="PriceTag"></el-button>
标签满足以下条件
</template>
<div class="rule" v-if="tagRule.items.length">
<div class="rule-operator">
<span @click="toggleOperate(tagRule)">{{ getLogicalName(tagRule.current_logic_operate) }}</span>
</div>
<div class="rule-list">
<el-row class="rule-item" v-for="(item, index) in tagRule.items" justify="space-between">
<div>
标签 等于
<el-form-item>
<el-select v-model="tagRule.items[index]">
<el-option
v-for="option in tagList"
:key="option.id"
:label="option.name"
:value="option.id"></el-option>
</el-select>
</el-form-item>
</div>
<el-button text :icon="CloseBold" @click="handleRemove(tagRule.items, index)"></el-button>
</el-row>
</div>
</div>
<el-button text :icon="Plus" @click="handleAdd(tagRule.items)">添加条件</el-button>
</el-card>
</template>
<style src="@/assets/styles/rule.scss"></style>
...@@ -27,21 +27,13 @@ function toggleOperate(rule: UserAttrRule) { ...@@ -27,21 +27,13 @@ function toggleOperate(rule: UserAttrRule) {
} }
// 添加条件 // 添加条件
function handleAdd() { function handleAdd(items: RuleAttr[]) {
userAttrRule.value.items.push({ items.push({ attr_id: '', attr: '', attr_name: '', attr_type: '', operate: '', operate_name: '', value: '' })
attr_id: '',
attr: '',
attr_name: '',
attr_type: '',
operate: '',
operate_name: '',
value: ''
})
} }
// 删除 // 删除
function handleRemove(rule: UserAttrRule, index: number) { function handleRemove(items: RuleAttr[], index: number) {
rule.items.splice(index, 1) items.splice(index, 1)
} }
// 属性改变 // 属性改变
...@@ -98,11 +90,11 @@ function handleOperateChange(value: string, item: RuleAttr) { ...@@ -98,11 +90,11 @@ function handleOperateChange(value: string, item: RuleAttr) {
<el-input v-model="item.value" /> <el-input v-model="item.value" />
</el-form-item> </el-form-item>
</div> </div>
<el-button text :icon="CloseBold" @click="handleRemove(userAttrRule, index)"></el-button> <el-button text :icon="CloseBold" @click="handleRemove(userAttrRule.items, index)"></el-button>
</el-row> </el-row>
</div> </div>
</div> </div>
<el-button text :icon="Plus" @click="handleAdd">添加条件</el-button> <el-button text :icon="Plus" @click="handleAdd(userAttrRule.items)">添加条件</el-button>
</el-card> </el-card>
</template> </template>
......
...@@ -41,10 +41,14 @@ export function useMetaEvent() { ...@@ -41,10 +41,14 @@ export function useMetaEvent() {
return { fetchMetaEventList, metaEventList } return { fetchMetaEventList, metaEventList }
} }
const tagList = ref([]) interface TagType {
id: string
name: string
}
const tagList = ref<TagType[]>([])
export function useTag() { export function useTag() {
function fetchTagList() { function fetchTagList() {
getTagList({ check_role: true }).then((res: any) => { getTagList({ check_role: 1 }).then((res: any) => {
tagList.value = res.data.items tagList.value = res.data.items
}) })
} }
......
...@@ -12,6 +12,11 @@ export function getGroupList(params?: GroupListRequest) { ...@@ -12,6 +12,11 @@ export function getGroupList(params?: GroupListRequest) {
return httpRequest.get('/api/lab/v1/experiment/group/list', { params }) return httpRequest.get('/api/lab/v1/experiment/group/list', { params })
} }
// 获取群组详情
export function getGroupInfo(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/group/detail', { params })
}
// 创建静态群组 // 创建静态群组
export function createStaticGroup(data: StaticGroupCreateRequest) { export function createStaticGroup(data: StaticGroupCreateRequest) {
return httpRequest.post('/api/lab/v1/experiment/group/create-static-group', data) return httpRequest.post('/api/lab/v1/experiment/group/create-static-group', data)
......
...@@ -3,7 +3,10 @@ import type { Group } from '../types' ...@@ -3,7 +3,10 @@ import type { Group } from '../types'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { updateStatusRuleList, dateUnitList, weekList } from '@/utils/dictionary' import { updateStatusRuleList, dateUnitList, weekList } from '@/utils/dictionary'
import { createStaticGroup, updateStaticGroup, createDynamicGroup, updateDynamicGroup } from '../api' import { createStaticGroup, updateStaticGroup, createDynamicGroup, updateDynamicGroup, getGroupInfo } from '../api'
import UserRule from '@/components/rule/UserRule.vue'
import EventRule from '@/components/rule/EventRule.vue'
import LabelRule from '@/components/rule/LabelRule.vue'
import { pick } from 'lodash-es' import { pick } from 'lodash-es'
interface Props { interface Props {
...@@ -33,10 +36,15 @@ const form = reactive({ ...@@ -33,10 +36,15 @@ const form = reactive({
status: '1', status: '1',
update_status: '1', update_status: '1',
update_rule: { type: 1, info: 1 }, update_rule: { type: 1, info: 1 },
user_attr_rule: [], user_attr_rule: { current_logic_operate: 'and', items: [] },
event_attr_rule: [], event_attr_rule: { current_logic_operate: 'and', items: [] },
tag_rule: [] tag_rule: { current_logic_operate: 'and', items: [] }
}) })
provide('userAttrRule', toRef(form, 'user_attr_rule'))
provide('eventAttrRule', toRef(form, 'event_attr_rule'))
provide('tagRule', toRef(form, 'tag_rule'))
watchEffect(() => { watchEffect(() => {
if (props.data?.id) { if (props.data?.id) {
let updateRule = { type: 1, info: 1 } let updateRule = { type: 1, info: 1 }
...@@ -49,6 +57,19 @@ watchEffect(() => { ...@@ -49,6 +57,19 @@ watchEffect(() => {
} }
}) })
function fetchInfo() {
if (!props.data.id) return
getGroupInfo({ id: props.data.id }).then(res => {
const { detail } = res.data
const [user_attr_rule = { current_logic_operate: 'and', items: [] }] = detail.user_attr_rule
const [event_attr_rule = { current_logic_operate: 'and', items: [] }] = detail.event_attr_rule
const [tag_rule = { current_logic_operate: 'and', items: [] }] = detail.tag_rule
Object.assign(form, { user_attr_rule, event_attr_rule, tag_rule })
})
}
watchEffect(() => fetchInfo())
const rules = ref<FormRules>({ const rules = ref<FormRules>({
name: [{ required: true, message: '请输入群组名称' }], name: [{ required: true, message: '请输入群组名称' }],
url: [{ required: true, message: '请选择标签类型图标' }] url: [{ required: true, message: '请选择标签类型图标' }]
...@@ -70,9 +91,9 @@ async function handleCreate() { ...@@ -70,9 +91,9 @@ async function handleCreate() {
{ {
...form, ...form,
update_rule: JSON.stringify(form.update_rule), update_rule: JSON.stringify(form.update_rule),
user_attr_rule: JSON.stringify(form.user_attr_rule), user_attr_rule: JSON.stringify([form.user_attr_rule]),
event_attr_rule: JSON.stringify(form.event_attr_rule), event_attr_rule: JSON.stringify([form.event_attr_rule]),
tag_rule: JSON.stringify(form.tag_rule) tag_rule: JSON.stringify([form.tag_rule])
}, },
['name', 'update_status', 'update_rule', 'user_attr_rule', 'event_attr_rule', 'tag_rule', 'status'] ['name', 'update_status', 'update_rule', 'user_attr_rule', 'event_attr_rule', 'tag_rule', 'status']
) )
...@@ -94,9 +115,9 @@ async function handleUpdate() { ...@@ -94,9 +115,9 @@ async function handleUpdate() {
{ {
...form, ...form,
update_rule: JSON.stringify(form.update_rule), update_rule: JSON.stringify(form.update_rule),
user_attr_rule: JSON.stringify(form.user_attr_rule), user_attr_rule: JSON.stringify([form.user_attr_rule]),
event_attr_rule: JSON.stringify(form.event_attr_rule), event_attr_rule: JSON.stringify([form.event_attr_rule]),
tag_rule: JSON.stringify(form.tag_rule) tag_rule: JSON.stringify([form.tag_rule])
}, },
['id', 'name', 'update_status', 'update_rule', 'user_attr_rule', 'event_attr_rule', 'tag_rule', 'status'] ['id', 'name', 'update_status', 'update_rule', 'user_attr_rule', 'event_attr_rule', 'tag_rule', 'status']
) )
...@@ -109,7 +130,7 @@ async function handleUpdate() { ...@@ -109,7 +130,7 @@ async function handleUpdate() {
</script> </script>
<template> <template>
<el-dialog :title="title" :close-on-click-modal="false" width="600px" @update:modelValue="$emit('update:modelValue')"> <el-dialog :title="title" :close-on-click-modal="false" width="800px" @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="100px"> <el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="100px">
<el-form-item label="群组名称" prop="name"> <el-form-item label="群组名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" /> <el-input v-model="form.name" placeholder="请输入" />
...@@ -149,6 +170,14 @@ async function handleUpdate() { ...@@ -149,6 +170,14 @@ async function handleUpdate() {
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-switch v-model="form.status" active-text="生效" active-value="1" inactive-text="失效" inactive-value="0" /> <el-switch v-model="form.status" active-text="生效" active-value="1" inactive-text="失效" inactive-value="0" />
</el-form-item> </el-form-item>
<template v-if="data.type === '2'">
<!-- 用户属性规则 -->
<UserRule></UserRule>
<!-- 事件属性规则 -->
<EventRule style="margin-top: 20px"></EventRule>
<!-- 标签 -->
<LabelRule style="margin-top: 20px"></LabelRule>
</template>
</el-form> </el-form>
<template #footer> <template #footer>
<el-row justify="center"> <el-row justify="center">
......
...@@ -104,3 +104,9 @@ export interface EventRuleItem { ...@@ -104,3 +104,9 @@ export interface EventRuleItem {
value: string value: string
} }
} }
// 标签规则
export interface TagRule {
current_logic_operate: 'and' | 'or'
items: string[]
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论