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

chore: update

上级 79167b1d
......@@ -43,3 +43,17 @@ export function getUploadVideoAuth(data: { title: string; file_name: string }) {
export function updateUploadVideoAuth(data: { source_id: string }) {
return httpRequest.post('/api/lab/v1/teacher/video/create-auth', data)
}
// 获取实验下的所有用户属性
export function getMetaUserAttrList() {
return httpRequest.get('/api/lab/v1/experiment/meta-member/all')
}
// 获取实验下的所有事件
export function getMetaEventList() {
return httpRequest.get('/api/lab/v1/experiment/meta-event/all')
}
// 获取实验下的所有标签
export function getTagList(params?: { check_role?: boolean }) {
return httpRequest.get('/api/lab/v1/experiment/tag/all', { params })
}
.rule {
display: flex;
.el-form-item {
margin-right: 10px;
margin-bottom: 0;
}
.el-select,
.el-input {
width: 120px;
}
}
.rule-and-or {
.rule-operator {
margin-right: 10px;
position: relative;
min-width: 40px;
min-height: 30px;
min-height: 40px;
&::before {
content: ' ';
position: absolute;
......@@ -31,18 +40,9 @@
cursor: pointer;
}
}
.rule-attr-list {
flex: 1;
}
.rule-attr {
display: flex;
}
.rule-attr + .rule-attr {
margin-top: 10px;
}
.rule-attr-content {
.rule-list {
flex: 1;
}
.rule-attr-tools {
width: 140px;
.rule-item {
margin: 10px 0;
}
<script setup lang="ts">
import { Operation } from '@element-plus/icons-vue'
import type { EventRule, EventRuleItem, RuleAttr } from '@/types'
import { Operation, Plus, CloseBold } from '@element-plus/icons-vue'
import { useMetaEvent } from '@/composables/useAllData'
import {
stringOperatorList,
numberOperatorList,
dateOperatorList,
happenInfoList,
triggerInfoList
} from '@/utils/dictionary'
const eventAttrRule = ref(inject('eventAttrRule') as EventRule)
const { metaEventList } = useMetaEvent()
// 获取逻辑运算符名称
function getLogicalName(value: 'and' | 'or') {
return value === 'or' ? '或' : '且'
}
// 获取运算符列表
function getOperatorList(type: string) {
if (type === '1') return stringOperatorList
if (type === '2' || type === '3') return numberOperatorList
if (type === '4' || type === '5') return dateOperatorList
return stringOperatorList
}
// 获取事件属性列表
function getEventAttrList(eventId: string) {
return metaEventList.value.find(item => item.id === eventId)?.event_attrs || []
}
// 切换逻辑运算符
function toggleOperate(rule: EventRule) {
rule.current_logic_operate = rule.current_logic_operate === 'or' ? 'and' : 'or'
}
// 添加条件
function handleAdd() {
eventAttrRule.value.items.push({
happen_info: { is_happened: true, event_id: '', event_name: '', attr_list: [] },
trigger_info: { operate: '', operate_name: '', value: '' }
})
}
// 删除条件
function handleRemove(index: number) {
eventAttrRule.value.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[]) {
attrs.push({ attr_id: '', attr: '', attr_name: '', attr_type: '', operate: '', operate_name: '', value: '' })
}
// 删除属性条件
function handleAttrRemove(attrs: RuleAttr[], index: number) {
attrs.splice(index, 1)
}
// 属性改变
function handleAttrChange(value: string, attr: RuleAttr, rule: EventRuleItem) {
const found = getEventAttrList(rule.happen_info.event_id).find(item => item.id === value)
attr.attr = found?.english_name || ''
attr.attr_name = found?.name || ''
attr.attr_type = found?.type || ''
// 清空条件数据
attr.operate = ''
attr.operate_name = ''
attr.value = ''
}
// 条件改变
function handleOperateChange(value: string, item: RuleAttr) {
const found = getOperatorList(item.attr_type).find(item => item.value === value)
item.operate_name = found?.label || ''
item.value = ''
}
// 条件改变
function handleTriggerOperateChange(value: string, rule: EventRuleItem) {
const found = numberOperatorList.find(item => item.value === value)
rule.trigger_info.operate_name = found?.label || ''
}
</script>
<template>
<el-card shadow="never" style="margin-top: 20px">
<el-card shadow="never">
<template #header>
<el-button circle color="#f90" :icon="Operation"></el-button>
事件属性满足以下条件</template
>
事件属性满足以下条件
</template>
<div class="rule" v-if="eventAttrRule.items.length">
<div class="rule-operator">
<span @click="toggleOperate(eventAttrRule)">{{ getLogicalName(eventAttrRule.current_logic_operate) }}</span>
</div>
<div class="rule-list">
<section class="rule-item" v-for="(rule, index) in eventAttrRule.items" :key="index">
<el-row>
<!-- 发生 -->
<el-form-item>
<el-select v-model="rule.happen_info.is_happened">
<el-option v-for="option in happenInfoList" v-bind="option"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="rule.happen_info.event_id" @change="value => handleEventChange(value, rule)">
<el-option
v-for="option in metaEventList"
:key="option.id"
:label="option.name"
:value="option.id"></el-option>
</el-select>
</el-form-item>
<el-button text :icon="Plus" @click="handleAttrAdd(rule.happen_info.attr_list)">添加条件</el-button>
<el-button text :icon="CloseBold" @click="handleRemove(index)"></el-button>
</el-row>
<!-- 属性条件 -->
<el-row class="rule-item" justify="space-between" v-for="(attr, index) in rule.happen_info.attr_list">
<div>
<el-form-item>
<el-select v-model="attr.attr_id" @change="value => handleAttrChange(value, attr, rule)">
<el-option
v-for="option in getEventAttrList(rule.happen_info.event_id)"
:key="option.id"
:label="option.name"
:value="option.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="attr.operate" @change="value => handleOperateChange(value, attr)">
<el-option
v-for="option in getOperatorList(attr.attr_type)"
:label="option.alias || option.label"
:value="option.value"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input v-model="attr.value" />
</el-form-item>
</div>
<el-button text :icon="CloseBold" @click="handleAttrRemove(rule.happen_info.attr_list, index)"></el-button>
</el-row>
<!-- 触发 -->
<el-row style="margin-top: 10px">
<el-form-item>
<el-select model-value="触发次数">
<el-option v-for="option in triggerInfoList" v-bind="option"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="rule.trigger_info.operate" @change="value => handleTriggerOperateChange(value, rule)">
<el-option
v-for="option in numberOperatorList"
:label="option.alias || option.label"
:value="option.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-input v-model="rule.trigger_info.value" />
</el-form-item>
</el-row>
</section>
</div>
</div>
<el-button text :icon="Plus" @click="handleAdd">添加条件</el-button>
</el-card>
</template>
<style src="@/assets/styles/rule.scss"></style>
<script setup lang="ts">
import type { UserAttrRule } from '@/types'
import { UserFilled, Plus } from '@element-plus/icons-vue'
import UserRuleGroup from './UserRuleGroup.vue'
const rules = ref<UserAttrRule[]>([
{
items: [
{
attr_id: '属性ID',
attr: '属性',
attr_name: '属性名称',
attr_type: 1,
operate: '操作',
operate_name: '操作名称',
value: '值'
}
],
current_logic_operate: 'and'
}
])
function handleChange(data: UserAttrRule, index: number) {
rules.value[index] = data
import type { UserAttrRule, RuleAttr } from '@/types'
import { UserFilled, Plus, CloseBold } from '@element-plus/icons-vue'
import { useUserAttr } from '@/composables/useAllData'
import { stringOperatorList, numberOperatorList, dateOperatorList } from '@/utils/dictionary'
const userAttrRule = ref(inject('userAttrRule') as UserAttrRule)
const { userAttrList } = useUserAttr()
// 获取逻辑运算符名称
function getLogicalName(value: 'and' | 'or') {
return value === 'or' ? '或' : '且'
}
// 获取运算符列表
function getOperatorList(type: string) {
if (type === '1') return stringOperatorList
if (type === '2' || type === '3') return numberOperatorList
if (type === '4' || type === '5') return dateOperatorList
return stringOperatorList
}
// 切换逻辑运算符
function toggleOperate(rule: UserAttrRule) {
rule.current_logic_operate = rule.current_logic_operate === 'or' ? 'and' : 'or'
}
// 添加条件
function handleAdd() {
rules.value.push({
items: [{ attr_id: '', attr: '', attr_name: '', attr_type: 1, operate: '', operate_name: '', value: '' }],
current_logic_operate: 'and'
userAttrRule.value.items.push({
attr_id: '',
attr: '',
attr_name: '',
attr_type: '',
operate: '',
operate_name: '',
value: ''
})
}
// 删除
function handleRemove(rule: UserAttrRule, index: number) {
rule.items.splice(index, 1)
}
// 属性改变
function handleAttrChange(value: string, item: RuleAttr) {
const found = userAttrList.value.find(item => item.id === value)
item.attr = found?.english_name || ''
item.attr_name = found?.name || ''
item.attr_type = found?.type || ''
// 清空条件数据
item.operate = ''
item.operate_name = ''
item.value = ''
}
// 条件改变
function handleOperateChange(value: string, item: RuleAttr) {
const found = getOperatorList(item.attr_type).find(item => item.value === value)
item.operate_name = found?.label || ''
item.value = ''
}
</script>
<template>
<el-card shadow="never">
<template #header>
<el-button circle color="#006df1" :icon="UserFilled"></el-button>
用户属性满足以下条件</template
>
<UserRuleGroup
v-for="(item, index) in rules"
:data="item"
@update="data => handleChange(data, index)"></UserRuleGroup>
<el-button text :icon="Plus" @click="handleAdd" v-if="!rules.length">添加条件</el-button>
用户属性满足以下条件
</template>
<div class="rule" v-if="userAttrRule.items.length">
<div class="rule-operator">
<span @click="toggleOperate(userAttrRule)">{{ getLogicalName(userAttrRule.current_logic_operate) }}</span>
</div>
<div class="rule-list">
<el-row class="rule-item" v-for="(item, index) in userAttrRule.items" justify="space-between">
<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-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)"
:label="option.alias || option.label"
:value="option.value"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input v-model="item.value" />
</el-form-item>
</div>
<el-button text :icon="CloseBold" @click="handleRemove(userAttrRule, index)"></el-button>
</el-row>
</div>
</div>
<el-button text :icon="Plus" @click="handleAdd">添加条件</el-button>
</el-card>
</template>
<style src="@/assets/styles/rule.scss"></style>
<script setup lang="ts">
import type { UserAttrRule } from '@/types'
import { Plus, CloseBold } from '@element-plus/icons-vue'
interface Props {
data: UserAttrRule
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update', data: UserAttrRule): void
}>()
const andOrText = computed(() => {
const map = { or: '或', and: '且' }
return map[props.data.current_logic_operate]
})
// 切换and 或者 or
function toggleOperate() {
update({ ...props.data, current_logic_operate: props.data.current_logic_operate === 'or' ? 'and' : 'or' })
}
// 新增
function handleAdd(index: number) {
const items = props.data.items.slice()
items.splice(index, 0, {
attr_id: '',
attr: '',
attr_name: '',
attr_type: 1,
operate: '',
operate_name: '',
value: ''
})
update({ ...props.data, items })
}
// 删除
function handleRemove(index: number) {
const items = props.data.items.slice()
items.splice(index, 1)
update({ ...props.data, items })
}
function update(data: UserAttrRule) {
emit('update', data)
}
</script>
<template>
<div class="rule">
<div class="rule-and-or">
<span @click="toggleOperate">{{ andOrText }}</span>
</div>
<div class="rule-attr-list">
<div class="rule-attr" v-for="(item, index) in data.items">
<div class="rule-attr-content">
<el-select style="width: 120px">
<el-option label="1" value="1"></el-option>
</el-select>
<el-select style="width: 120px">
<el-option label="1" value="1"></el-option>
</el-select>
</div>
<div class="rule-attr-tools">
<el-button text :icon="Plus" @click="handleAdd(index)">新增</el-button>
<el-button text :icon="CloseBold" @click="handleRemove(index)" v-if="index"></el-button>
</div>
</div>
</div>
</div>
</template>
<style src="@/assets/styles/rule.scss"></style>
import { getMetaUserAttrList, getMetaEventList, getTagList } from '@/api/base'
interface AttrType {
id: string
name: string
type: string
format: string
english_name: string
pinyin: string
}
const userAttrList = ref<AttrType[]>([])
export function useUserAttr() {
function fetchUserAttrList() {
getMetaUserAttrList().then((res: any) => {
userAttrList.value = res.data.items
})
}
onMounted(() => {
if (!userAttrList.value?.length) fetchUserAttrList()
})
return { fetchUserAttrList, userAttrList }
}
interface MetaEvent {
id: string
name: string
english_name: string
pinyin: string
event_attrs: AttrType[]
}
const metaEventList = ref<MetaEvent[]>([])
export function useMetaEvent() {
function fetchMetaEventList() {
getMetaEventList().then((res: any) => {
metaEventList.value = res.data.items
})
}
onMounted(() => {
if (!metaEventList.value?.length) fetchMetaEventList()
})
return { fetchMetaEventList, metaEventList }
}
const tagList = ref([])
export function useTag() {
function fetchTagList() {
getTagList({ check_role: true }).then((res: any) => {
tagList.value = res.data.items
})
}
onMounted(() => {
if (!tagList.value?.length) fetchTagList()
})
return { fetchTagList, tagList }
}
......@@ -52,3 +52,13 @@ export function deleteLabel(data: { id: string }) {
export function getLabelStatistics(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/tag/statistics', { params })
}
// 获取标签规则
export function getLabelRule(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/tag/rule', { params })
}
// 更新标签规则
export function updateLabelRule(data: { id: string; user_attr_rule: string; event_attr_rule: string }) {
return httpRequest.post('/api/lab/v1/experiment/tag/save-rule', data)
}
......@@ -2,26 +2,44 @@
import type { Label } from '../types'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { useMapStore } from '@/stores/map'
import { getNameByValue, updateStatusRuleList } from '@/utils/dictionary'
import { getLabelRule, updateLabelRule } from '../api'
import UserRule from '@/components/rule/UserRule.vue'
import EventRule from '@/components/rule/EventRule.vue'
interface Props {
const props = defineProps<{
data: Label
}
const props = defineProps<Props>()
}>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const statusList = useMapStore().getMapValuesByKey('system_status')
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
status: ''
id: props.data.id,
user_attr_rule: { current_logic_operate: 'and', items: [] },
event_attr_rule: { current_logic_operate: 'and', items: [] }
})
provide('userAttrRule', toRef(form, 'user_attr_rule'))
provide('eventAttrRule', toRef(form, 'event_attr_rule'))
function fetchInfo() {
getLabelRule({ 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
Object.assign(form, detail, { user_attr_rule, event_attr_rule })
})
}
watchEffect(() => fetchInfo())
const rules = ref<FormRules>({
name: [{ required: true, message: '请输入标签名称' }],
type: [{ required: true, message: '请选择标签类型' }]
......@@ -32,11 +50,18 @@ function handleSubmit() {
formRef?.validate().then(handleUpdate)
}
// 修改
// 保存
function handleUpdate() {
ElMessage({ message: '保存成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
const params = {
id: form.id,
user_attr_rule: JSON.stringify([form.user_attr_rule]),
event_attr_rule: JSON.stringify([form.event_attr_rule])
}
updateLabelRule(params).then(() => {
ElMessage({ message: '保存成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
</script>
......@@ -48,20 +73,32 @@ function handleUpdate() {
@update:modelValue="$emit('update:modelValue')">
<el-form label-suffix=":" label-width="82px">
<el-row>
<el-col :span="12"><el-form-item label="标签名称">标签名称</el-form-item></el-col>
<el-col :span="12">
<el-form-item label="标签类型">标签类型</el-form-item>
<el-form-item label="标签名称">{{ data.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="标签类型">{{ data.tag_type.name }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12"><el-form-item label="更新频率">自动更新</el-form-item></el-col>
<el-col :span="12"><el-form-item label="状态">生效</el-form-item></el-col>
<el-col :span="12">
<el-form-item label="更新频率">{{ getNameByValue(data.update_status, updateStatusRuleList) }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-tag :type="data.status === '1' ? 'success' : 'danger'">
{{ getNameByValue(data.status, statusList) }}
</el-tag>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 用户属性规则 -->
<UserRule></UserRule>
<!-- 事件属性规则 -->
<EventRule></EventRule>
<el-form :model="form" :rules="rules" inline ref="formRef">
<!-- 用户属性规则 -->
<UserRule></UserRule>
<!-- 事件属性规则 -->
<EventRule style="margin-top: 20px"></EventRule>
</el-form>
<template #footer>
<el-row justify="center">
<el-button plain auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
......@@ -70,12 +107,3 @@ function handleUpdate() {
</template>
</el-dialog>
</template>
<style lang="scss">
.update-rule-wrap {
width: 100%;
.el-select {
margin: 0 10px;
}
}
</style>
......@@ -26,9 +26,9 @@ watchEffect(() => fetchInfo())
<el-dialog title="查看标签信息" width="600px">
<el-form label-suffix=":" label-width="82px">
<el-row>
<el-col :span="12"
><el-form-item label="标签名称">{{ data.name }}</el-form-item></el-col
>
<el-col :span="12">
<el-form-item label="标签名称">{{ data.name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="标签类型">{{ data.tag_type.name }}</el-form-item>
</el-col>
......
......@@ -60,25 +60,47 @@ export interface SystemDictionary {
value: string
}
// 操作人
export interface Operator {
avatar: string
id: string
nickname: string
real_name: string
username: string
}
// 用户规则
export interface UserAttrRule {
current_logic_operate: 'and' | 'or'
items: UserAttrRuleItem[]
items: RuleAttr[]
}
export interface UserAttrRuleItem {
export interface RuleAttr {
attr_id: string
attr: string
attr_name: string
attr_type: number
attr_type: string
operate: string
operate_name: string
value: string
}
export interface Operator {
avatar: string
id: string
nickname: string
real_name: string
username: string
// 事件规则
export interface EventRule {
current_logic_operate: 'and' | 'or'
items: EventRuleItem[]
}
export interface EventRuleItem {
happen_info: {
is_happened: boolean
event_id: string
event_name: string
attr_list: RuleAttr[]
}
trigger_info: {
operate: string
operate_name: string
value: string
}
}
......@@ -41,30 +41,47 @@ export const weekList = [
{ label: '周日', value: 7 }
]
export const stringConditionList = [
{ label: '等于', value: 1 },
{ label: '不等于', value: 2 },
{ label: '包含', value: 3 },
{ label: '不包含', value: 4 },
{ label: '空值', value: 5 },
{ label: '非空', value: 6 }
export interface OperatorType {
label: string
value: string
alias?: string
}
// 字符串
export const stringOperatorList: OperatorType[] = [
{ label: '等于', value: '=' },
{ label: '不等于', value: '!=' },
{ label: '包含', value: 'in' },
{ label: '不包含', value: 'not in' },
{ label: '空值', value: 'null' },
{ label: '非空', value: 'not null' }
]
export const numberConditionList = [
{ label: '=', value: 1 },
{ label: '≠', value: 2 },
{ label: '>', value: 3 },
{ label: '≥', value: 4 },
{ label: '<', value: 5 },
{ label: '≤', value: 6 },
{ label: '区间', value: 7 },
{ label: '空值', value: 8 },
{ label: '非空', value: 9 }
// 整数|数字
export const numberOperatorList: OperatorType[] = [
{ label: '=', value: '=' },
{ label: '!=', value: '!=', alias: '≠' },
{ label: '>', value: '>' },
{ label: '>=', value: '>=', alias: '≥' },
{ label: '<', value: '<' },
{ label: '<=', value: '<=', alias: '≤' },
{ label: '区间', value: 'range' },
{ label: '空值', value: 'null' },
{ label: '非空', value: 'not null' }
]
export const dateConditionList = [
{ label: '绝对时间前后', value: 1 },
{ label: '绝对时间区间', value: 2 },
{ label: '相对时间点', value: 3 },
{ label: '在...天内', value: 4 }
// 日期
export const dateOperatorList: OperatorType[] = [
{ label: '绝对时间前', value: 'before' },
{ label: '绝对时间后', value: 'after' },
{ label: '绝对时间区间', value: 'range' },
{ label: '相对时间点', value: '3' },
{ label: '在...天内', value: 'in_day' }
]
export const happenInfoList = [
{ label: '发生过', value: true },
{ label: '未发生过', value: false }
]
export const triggerInfoList = [{ label: '触发次数', value: '触发次数' }]
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论