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

chore: 用户属性支持多选

上级 cd0d6051
......@@ -106,6 +106,6 @@ export function getMemberEvents() {
}
// 用户属性搜索
export function searchEventAttrs(params?: { search: string; experiment_meta_event_id?: string; page?: number; per_page?: number }) {
export function searchEventAttrs(params?: { search: string; experiment_meta_event_id?: string; experiment_meta_event_attr_id?: string; page?: number; per_page?: number }) {
return httpRequest.get('/api/lab/v1/experiment/event/search-attributes', { params })
}
......@@ -12,6 +12,12 @@
.el-input {
width: 130px;
}
.el-select,
.el-autocomplete {
.el-input {
width: 100%;
}
}
}
.rule-operator {
margin-right: 10px;
......@@ -50,3 +56,8 @@
.rule-item {
margin: 10px 0;
}
.event-rule {
.rule-item + .rule-item {
margin-top: 30px;
}
}
......@@ -103,15 +103,49 @@ function handleTriggerOperateChange(value: string, item: EventRuleItem) {
item.trigger_info.value = ''
}
function querySearch(item: RuleAttr, search: string, cb: (arg: any) => void) {
searchEventAttrs({ search, experiment_meta_event_id: item.attr_id, per_page: 100 }).then(res => {
cb(res.data.list)
function querySearch(rule: EventRuleItem, attr: RuleAttr, search: string, cb: (arg: any) => void) {
const found = getEventAttrList(rule.happen_info.event_id).find(item => item.id === attr.attr_id)
const experiment_meta_event_id = found?.experiment_meta_event_id || ''
searchEventAttrs({ search, experiment_meta_event_id: experiment_meta_event_id, experiment_meta_event_attr_id: attr.attr_id, per_page: 1000 }).then(res => {
const list: string[] = []
res.data.list.forEach((item: any) => {
try {
const fields = JSON.parse(item.fields)
const value = fields[attr.attr_id]
if (!list.includes(value)) list.push(value)
} catch (error) {
console.log(error)
}
})
cb(list.map((item: string) => ({ value: item })))
})
}
const options = ref<{ label: string; value: string }[]>([])
const loading = ref(false)
function remoteMethod(rule: EventRuleItem, attr: RuleAttr, search: string) {
const found = getEventAttrList(rule.happen_info.event_id).find(item => item.id === attr.attr_id)
const experiment_meta_event_id = found?.experiment_meta_event_id || ''
loading.value = true
searchEventAttrs({ search, experiment_meta_event_id: experiment_meta_event_id, experiment_meta_event_attr_id: attr.attr_id, per_page: 1000 }).then(res => {
const list: string[] = []
res.data.list.forEach((item: any) => {
try {
const fields = JSON.parse(item.fields)
const value = fields[attr.attr_id]
if (!list.includes(value)) list.push(value)
} catch (error) {
console.log(error)
}
})
options.value = list.map((item: string) => ({ value: item, label: item }))
loading.value = false
})
}
</script>
<template>
<el-card shadow="never">
<el-card shadow="never" class="event-rule">
<template #header>
<el-button circle color="#f90" :icon="Operation"></el-button>
事件属性满足以下条件
......@@ -173,8 +207,19 @@ function querySearch(item: RuleAttr, search: string, cb: (arg: any) => void) {
<el-date-picker v-model="attr.value" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width: 180px" />
</template>
<template v-else>
<!-- <el-input v-model="attr.value" /> -->
<el-autocomplete v-model="attr.value" value-key="attr_value" :fetch-suggestions="(query, cb) => querySearch(attr, query, cb)" />
<el-select
v-model="attr.value"
filterable
remote
allow-create
multiple
:remote-method="(query:string) => remoteMethod(rule, attr, query)"
:loading="loading"
style="width: 320px"
v-if="['in', 'not in'].includes(attr.operate)">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-autocomplete v-model="attr.value" :fetch-suggestions="(query, cb) => querySearch(rule, attr, query, cb)" style="width: 320px" v-else />
</template>
</el-form-item>
</div>
......
......@@ -47,6 +47,7 @@ function handleAttrChange(value: string, item: RuleAttr) {
item.operate = ''
item.operate_name = ''
item.value = ''
remoteMethod(item)
}
// 条件改变
......@@ -62,13 +63,28 @@ function handleOperateChange(value: string, item: RuleAttr) {
function querySearch(item: RuleAttr, search: string, cb: (arg: any) => void) {
if (item.attr_id) {
searchMetaMemberAttrs({ search: '', member_meta_id: item.attr_id, per_page: 100 }).then(res => {
searchMetaMemberAttrs({ search, member_meta_id: item.attr_id, per_page: 100 }).then(res => {
cb(res.data.list)
})
} else {
cb([])
}
}
const options = ref<{ label: string; value: string }[]>([])
const loading = ref(false)
function remoteMethod(item: RuleAttr, search: string = '') {
options.value = []
if (item.attr_id) {
loading.value = true
searchMetaMemberAttrs({ search, member_meta_id: item.attr_id, per_page: 100 }).then(res => {
options.value = res.data.list.map((item: any) => {
return { label: item.attr_value, value: item.attr_value }
})
})
loading.value = false
}
}
</script>
<template>
......@@ -86,20 +102,12 @@ function querySearch(item: RuleAttr, search: string, cb: (arg: any) => void) {
<div>
<el-form-item>
<el-select v-model="item.attr_id" @change="value => handleAttrChange(value, item)">
<el-option
v-for="option in userAttrList"
:key="option.id"
:label="option.name"
:value="option.id"></el-option>
<el-option v-for="option in userAttrList" :key="option.id" :label="option.name" :value="option.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="item.operate" @change="value => handleOperateChange(value, item)">
<el-option
v-for="option in getOperatorList(item.attr_type)"
:key="option.value"
:label="option.alias || option.label"
:value="option.value"></el-option>
<el-option v-for="option in getOperatorList(item.attr_type)" :key="option.value" :label="option.alias || option.label" :value="option.value"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="!['null', 'not null'].includes(item.operate)">
......@@ -115,32 +123,29 @@ function querySearch(item: RuleAttr, search: string, cb: (arg: any) => void) {
</template>
<!-- 时间区间 -->
<template v-else-if="item.attr_type === '5' && item.operate === 'range'">
<el-date-picker
v-model="item.value.start"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 180px" />
<el-date-picker
v-model="item.value.end"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 180px" />
<el-date-picker v-model="item.value.start" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width: 180px" />
<el-date-picker v-model="item.value.end" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width: 180px" />
</template>
<template v-else-if="item.attr_type === '4' && (item.operate === 'after' || item.operate === 'before')">
<el-date-picker v-model="item.value" type="date" value-format="YYYY-MM-DD" />
</template>
<template v-else-if="item.attr_type === '5' && (item.operate === 'after' || item.operate === 'before')">
<el-date-picker
v-model="item.value"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 180px" />
<el-date-picker v-model="item.value" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width: 180px" />
</template>
<template v-else>
<el-autocomplete
<el-select
v-model="item.value"
value-key="attr_value"
:fetch-suggestions="(query, cb) => querySearch(item, query, cb)" />
filterable
remote
allow-create
:multiple="['in', 'not in'].includes(item.operate)"
:remote-method="(query:string) => remoteMethod(item, query)"
:loading="loading"
style="width: 320px"
v-if="['in', 'not in'].includes(item.operate)">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-autocomplete v-model="item.value" value-key="attr_value" :fetch-suggestions="(query, cb) => querySearch(item, query, cb)" style="width: 320px" v-else />
</template>
</el-form-item>
</div>
......
......@@ -8,6 +8,7 @@ export interface AttrType {
format: string
english_name: string
pinyin: string
experiment_meta_event_id?: string
}
// 事件类型
interface MetaEventType {
......@@ -81,8 +82,7 @@ export function useConnection() {
function fetchConnectionList() {
getConnectionList().then((res: any) => {
connectionList.value = res.data.items.map((item: any) => {
const attrs =
typeof item.config_attributes === 'string' ? JSON.parse(item.config_attributes) : item.config_attributes
const attrs = typeof item.config_attributes === 'string' ? JSON.parse(item.config_attributes) : item.config_attributes
const name = Array.isArray(attrs) ? attrs.find((item: any) => item.prop === 'name')?.value : attrs.name
return { ...item, config_attributes: attrs, name }
})
......
......@@ -66,7 +66,16 @@ function fetchInfo() {
const [tag_rule = { current_logic_operate: 'and', items: [] }] = detail.tag_rule.map((item: any) => {
return { ...item, items: item.items.map((item: any) => item.id) }
})
Object.assign(form, { user_attr_rule, event_attr_rule, tag_rule })
const attrRuleItems = user_attr_rule.items.map((item: any) => {
item.value = ['in', 'not in'].includes(item.operate) ? item.value.split(',') : item.value
return item
})
const eventRuleItems = event_attr_rule.items.map((item: any) => {
item.value = ['in', 'not in'].includes(item.operate) ? item.value.split(',') : item.value
return item
})
Object.assign(form, { user_attr_rule: { ...user_attr_rule, attrRuleItems }, event_attr_rule: { ...event_attr_rule, eventRuleItems }, tag_rule })
})
}
......@@ -112,13 +121,21 @@ async function handleUpdate() {
const params = pick(form, ['id', 'name', 'status'])
await updateStaticGroup(params)
} else {
const attrRuleItems = form.user_attr_rule.items.map((item: any) => {
item.value = Array.isArray(item.value) ? item.value.join(',') : item.value
return item
})
const eventRuleItems = form.event_attr_rule.items.map((item: any) => {
item.value = Array.isArray(item.value) ? item.value.join(',') : item.value
return item
})
// 动态群组
const params = pick(
{
...form,
update_rule: JSON.stringify(form.update_rule),
user_attr_rule: JSON.stringify([form.user_attr_rule]),
event_attr_rule: JSON.stringify([form.event_attr_rule]),
user_attr_rule: JSON.stringify([{ ...form.user_attr_rule, items: attrRuleItems }]),
event_attr_rule: JSON.stringify([{ ...form.event_attr_rule, items: eventRuleItems }]),
tag_rule: JSON.stringify([form.tag_rule])
},
['id', 'name', 'update_status', 'update_rule', 'user_attr_rule', 'event_attr_rule', 'tag_rule', 'status']
......@@ -140,22 +157,14 @@ async function handleUpdate() {
<template v-if="data.type === '2'">
<el-form-item label="更新频率" prop="update_status">
<el-radio-group v-model="form.update_status">
<el-radio
v-for="item in updateStatusRuleList"
:key="item.value"
:label="item.value"
:disabled="item.value === '1'">
<el-radio v-for="item in updateStatusRuleList" :key="item.value" :label="item.value" :disabled="item.value === '1'">
{{ item.label }}
</el-radio>
</el-radio-group>
<div class="update-rule-wrap" v-if="form.update_status === '1'">
<span></span>
<el-select v-model="form.update_rule.type" placeholder=" " style="width: 60px">
<el-option
v-for="item in dateUnitList"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
<el-option v-for="item in dateUnitList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<template v-if="form.update_rule.type === 1">
<span>的凌晨更新</span>
......@@ -163,11 +172,7 @@ async function handleUpdate() {
<template v-if="form.update_rule.type === 2">
<span></span>
<el-select v-model="form.update_rule.info" placeholder=" " style="width: 80px">
<el-option
v-for="item in weekList"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
<el-option v-for="item in weekList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<span>的凌晨更新</span>
</template>
......
......@@ -39,7 +39,15 @@ function fetchInfo() {
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
Object.assign(form, detail, { user_attr_rule, event_attr_rule })
const attrRuleItems = user_attr_rule.items.map((item: any) => {
item.value = ['in', 'not in'].includes(item.operate) ? item.value.split(',') : item.value
return item
})
const eventRuleItems = event_attr_rule.items.map((item: any) => {
item.value = ['in', 'not in'].includes(item.operate) ? item.value.split(',') : item.value
return item
})
Object.assign(form, detail, { user_attr_rule: { ...user_attr_rule, attrRuleItems }, event_attr_rule: { ...event_attr_rule, eventRuleItems } })
})
}
......@@ -57,10 +65,18 @@ function handleSubmit() {
// 保存
function handleUpdate() {
const attrRuleItems = form.user_attr_rule.items.map((item: any) => {
item.value = Array.isArray(item.value) ? item.value.join(',') : item.value
return item
})
const eventRuleItems = form.event_attr_rule.items.map((item: any) => {
item.value = Array.isArray(item.value) ? item.value.join(',') : item.value
return item
})
const params = {
id: form.id,
user_attr_rule: JSON.stringify([form.user_attr_rule]),
event_attr_rule: JSON.stringify([form.event_attr_rule])
user_attr_rule: JSON.stringify([{ ...form.user_attr_rule, items: attrRuleItems }]),
event_attr_rule: JSON.stringify([{ ...form.event_attr_rule, items: eventRuleItems }])
}
updateLabelRule(params).then(() => {
ElMessage({ message: '保存成功', type: 'success' })
......@@ -71,11 +87,7 @@ function handleUpdate() {
</script>
<template>
<el-dialog
title="标签规则管理"
:close-on-click-modal="false"
width="800px"
@update:modelValue="$emit('update:modelValue')">
<el-dialog title="标签规则管理" :close-on-click-modal="false" width="800px" @update:modelValue="$emit('update:modelValue')">
<el-form label-suffix=":" label-width="82px">
<el-row>
<el-col :span="12">
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论