提交 1fb15727 authored 作者: lihuihui's avatar lihuihui
...@@ -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,
......
...@@ -3,7 +3,12 @@ require('@rushstack/eslint-patch/modern-module-resolution') ...@@ -3,7 +3,12 @@ require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = { module.exports = {
root: true, root: true,
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript'], extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'./.eslintrc-auto-import.json'
],
parserOptions: { parserOptions: {
ecmaVersion: 'latest' ecmaVersion: 'latest'
}, },
......
...@@ -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']
......
差异被折叠。
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
"@element-plus/icons-vue": "^2.0.10", "@element-plus/icons-vue": "^2.0.10",
"@tinymce/tinymce-vue": "^5.0.0", "@tinymce/tinymce-vue": "^5.0.0",
"@vueuse/core": "^9.12.0", "@vueuse/core": "^9.12.0",
"axios": "^1.3.1", "axios": "^1.3.3",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"element-plus": "^2.2.28", "element-plus": "^2.2.30",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"pinia": "^2.0.30", "pinia": "^2.0.30",
"vue": "^3.2.47", "vue": "^3.2.47",
...@@ -29,18 +29,18 @@ ...@@ -29,18 +29,18 @@
"devDependencies": { "devDependencies": {
"@rushstack/eslint-patch": "^1.2.0", "@rushstack/eslint-patch": "^1.2.0",
"@types/blueimp-md5": "^2.18.0", "@types/blueimp-md5": "^2.18.0",
"@types/node": "^18.11.18", "@types/node": "^18.13.0",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",
"@vue/eslint-config-typescript": "^11.0.2", "@vue/eslint-config-typescript": "^11.0.2",
"@vue/tsconfig": "^0.1.3", "@vue/tsconfig": "^0.1.3",
"ali-oss": "^6.17.1", "ali-oss": "^6.17.1",
"chalk": "^5.2.0", "chalk": "^5.2.0",
"eslint": "^8.33.0", "eslint": "^8.34.0",
"eslint-plugin-vue": "^9.9.0", "eslint-plugin-vue": "^9.9.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"sass": "^1.58.0", "sass": "^1.58.1",
"typescript": "~4.9.5", "typescript": "~4.9.5",
"unplugin-auto-import": "^0.13.0", "unplugin-auto-import": "^0.14.2",
"vite": "^4.1.1", "vite": "^4.1.1",
"vue-tsc": "^1.0.24" "vue-tsc": "^1.0.24"
} }
......
...@@ -54,6 +54,16 @@ export function getMetaEventList() { ...@@ -54,6 +54,16 @@ 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 })
} }
// 获取实验下的所有连接
export function getConnectionList() {
return httpRequest.get('/api/lab/v1/experiment/connection/all')
}
// 搜索紫荆用户
export function searchUser(params: any) {
return httpRequest.get('/api/lab/v1/experiment/system/search-user', { 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;
......
差异被折叠。
<script setup lang="ts">
import { searchUser } from '@/api/base'
interface SearchUser {
id: string
realname: string
nickname: string
username: string
mobile: string
email: string
}
let loading = $ref(false)
let userList = $ref<SearchUser[]>()
const remoteMethod = (q: string) => {
if (!q) return
loading = true
searchUser({ q: q }).then(res => {
loading = false
userList = res.data.items
})
}
</script>
<template>
<el-select remote filterable value-key="id" :loading="loading" :remote-method="remoteMethod" style="width: 100%">
<el-option
v-for="item in userList"
:key="item.id"
:label="item.realname || item.nickname || item.username"
:value="item.id">
<span>{{ item.realname || item.nickname || item.username }}</span>
<template v-if="item.mobile">
<el-divider direction="vertical" />
<span>{{ item.mobile }}</span>
</template>
<template v-if="item.email">
<el-divider direction="vertical" />
<span>{{ item.email }}</span>
</template>
</el-option>
</el-select>
</template>
...@@ -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
<el-option v-for="option in happenInfoList" v-bind="option"></el-option> v-model="rule.happen_info.is_happened"
@change="value => handleHappenOperateChange(value, rule)">
<el-option v-for="option in happenInfoList" :key="option.label" 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,58 +130,77 @@ function handleTriggerOperateChange(value: string, rule: EventRuleItem) { ...@@ -117,58 +130,77 @@ 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"> <!-- 属性条件 -->
<div> <el-row
justify="space-between"
class="rule-item"
v-for="(attr, index) in rule.happen_info.attr_list"
:key="index">
<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)"
:key="option.value"
: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-form-item>
<el-select v-model="attr.attr_id" @change="value => handleAttrChange(value, attr, rule)"> <el-select model-value="触发次数">
<el-option <el-option v-for="option in triggerInfoList" :key="option.value" v-bind="option"></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-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-select v-model="attr.operate" @change="value => handleOperateChange(value, attr)"> <el-select
v-model="rule.trigger_info.operate"
@change="value => handleTriggerOperateChange(value, rule)">
<el-option <el-option
v-for="option in getOperatorList(attr.attr_type)" v-for="option in numberOperatorList"
:key="option.value"
:label="option.alias || option.label" :label="option.alias || option.label"
:value="option.value"></el-option> :value="option.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-input v-model="attr.value" /> <el-input v-model="rule.trigger_info.value" />
</el-form-item> </el-form-item>
</div> </el-row>
<el-button text :icon="CloseBold" @click="handleAttrRemove(rule.happen_info.attr_list, index)"></el-button> </template>
</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> </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 justify="space-between" class="rule-item" v-for="(item, index) in tagRule.items" :key="index">
<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)
} }
// 属性改变 // 属性改变
...@@ -75,7 +67,7 @@ function handleOperateChange(value: string, item: RuleAttr) { ...@@ -75,7 +67,7 @@ function handleOperateChange(value: string, item: RuleAttr) {
<span @click="toggleOperate(userAttrRule)">{{ getLogicalName(userAttrRule.current_logic_operate) }}</span> <span @click="toggleOperate(userAttrRule)">{{ getLogicalName(userAttrRule.current_logic_operate) }}</span>
</div> </div>
<div class="rule-list"> <div class="rule-list">
<el-row class="rule-item" v-for="(item, index) in userAttrRule.items" justify="space-between"> <el-row justify="space-between" class="rule-item" v-for="(item, index) in userAttrRule.items" :key="index">
<div> <div>
<el-form-item> <el-form-item>
<el-select v-model="item.attr_id" @change="value => handleAttrChange(value, item)"> <el-select v-model="item.attr_id" @change="value => handleAttrChange(value, item)">
...@@ -90,6 +82,7 @@ function handleOperateChange(value: string, item: RuleAttr) { ...@@ -90,6 +82,7 @@ function handleOperateChange(value: string, item: RuleAttr) {
<el-select v-model="item.operate" @change="value => handleOperateChange(value, item)"> <el-select v-model="item.operate" @change="value => handleOperateChange(value, item)">
<el-option <el-option
v-for="option in getOperatorList(item.attr_type)" v-for="option in getOperatorList(item.attr_type)"
:key="option.value"
:label="option.alias || option.label" :label="option.alias || option.label"
:value="option.value"></el-option> :value="option.value"></el-option>
</el-select> </el-select>
...@@ -98,11 +91,11 @@ function handleOperateChange(value: string, item: RuleAttr) { ...@@ -98,11 +91,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>
......
import { getMetaUserAttrList, getMetaEventList, getTagList } from '@/api/base' import { getMetaUserAttrList, getMetaEventList, getTagList, getConnectionList } from '@/api/base'
interface AttrType { // 用户属性类型
export interface AttrType {
id: string id: string
name: string name: string
type: string type: string
...@@ -8,6 +9,31 @@ interface AttrType { ...@@ -8,6 +9,31 @@ interface AttrType {
english_name: string english_name: string
pinyin: string pinyin: string
} }
// 事件类型
interface MetaEventType {
id: string
name: string
english_name: string
pinyin: string
event_attrs: AttrType[]
}
// 标签类型
export interface TagType {
id: string
name: string
}
// 连接类型
export interface ConnectionType {
id: string
name: string
type: string
status: '0' | '1'
config_attributes: any
}
// 所有用户属性
const userAttrList = ref<AttrType[]>([]) const userAttrList = ref<AttrType[]>([])
export function useUserAttr() { export function useUserAttr() {
function fetchUserAttrList() { function fetchUserAttrList() {
...@@ -21,14 +47,8 @@ export function useUserAttr() { ...@@ -21,14 +47,8 @@ export function useUserAttr() {
return { fetchUserAttrList, userAttrList } return { fetchUserAttrList, userAttrList }
} }
interface MetaEvent { // 所有事件
id: string const metaEventList = ref<MetaEventType[]>([])
name: string
english_name: string
pinyin: string
event_attrs: AttrType[]
}
const metaEventList = ref<MetaEvent[]>([])
export function useMetaEvent() { export function useMetaEvent() {
function fetchMetaEventList() { function fetchMetaEventList() {
getMetaEventList().then((res: any) => { getMetaEventList().then((res: any) => {
...@@ -41,10 +61,11 @@ export function useMetaEvent() { ...@@ -41,10 +61,11 @@ export function useMetaEvent() {
return { fetchMetaEventList, metaEventList } return { fetchMetaEventList, metaEventList }
} }
const tagList = ref([]) // 所有标签
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
}) })
} }
...@@ -53,3 +74,21 @@ export function useTag() { ...@@ -53,3 +74,21 @@ export function useTag() {
}) })
return { fetchTagList, tagList } return { fetchTagList, tagList }
} }
// 所有标签
const connectionList = ref<ConnectionType[]>([])
export function useConnection() {
function fetchConnectionList() {
getConnectionList().then((res: any) => {
connectionList.value = res.data.items.map((item: any) => {
const attrs = JSON.parse(item.config_attributes)
const name = Array.isArray(attrs) ? attrs.find((item: any) => item.prop === 'name')?.value : attrs.name
return { ...item, config_attributes: attrs, name }
})
})
}
onMounted(() => {
if (!connectionList.value?.length) fetchConnectionList()
})
return { fetchConnectionList, connectionList }
}
...@@ -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)
...@@ -42,6 +47,11 @@ export function getGroupStatistics(params: { group_id: string }) { ...@@ -42,6 +47,11 @@ export function getGroupStatistics(params: { group_id: string }) {
return httpRequest.get('/api/lab/v1/experiment/group/statistics-detail', { params }) return httpRequest.get('/api/lab/v1/experiment/group/statistics-detail', { params })
} }
// 更新群组数据信息
export function updateGroupStatistics(data: { id: string }) {
return httpRequest.post('/api/lab/v1/experiment/group/statistics-user-group', data)
}
// 获取群组成员 // 获取群组成员
export function getGroupMembers(params: { group_id: string; name?: string; id?: string }) { export function getGroupMembers(params: { group_id: string; name?: string; id?: string }) {
return httpRequest.get('/api/lab/v1/experiment/group/members', { params }) return httpRequest.get('/api/lab/v1/experiment/group/members', { params })
......
...@@ -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 {
...@@ -31,12 +34,17 @@ const form = reactive({ ...@@ -31,12 +34,17 @@ const form = reactive({
name: '', name: '',
type: '', type: '',
status: '1', status: '1',
update_status: '1', update_status: '2',
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="请输入" />
...@@ -117,14 +138,22 @@ async function handleUpdate() { ...@@ -117,14 +138,22 @@ async function handleUpdate() {
<template v-if="data.type === '2'"> <template v-if="data.type === '2'">
<el-form-item label="更新频率" prop="update_status"> <el-form-item label="更新频率" prop="update_status">
<el-radio-group v-model="form.update_status"> <el-radio-group v-model="form.update_status">
<el-radio v-for="item in updateStatusRuleList" :key="item.value" :label="item.value"> <el-radio
v-for="item in updateStatusRuleList"
:key="item.value"
:label="item.value"
:disabled="item.value === '1'">
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<div class="update-rule-wrap" v-if="form.update_status === '1'"> <div class="update-rule-wrap" v-if="form.update_status === '1'">
<span></span> <span></span>
<el-select v-model="form.update_rule.type" placeholder=" " style="width: 60px"> <el-select v-model="form.update_rule.type" placeholder=" " style="width: 60px">
<el-option v-for="item in dateUnitList" :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> </el-select>
<template v-if="form.update_rule.type === 1"> <template v-if="form.update_rule.type === 1">
<span>的凌晨更新</span> <span>的凌晨更新</span>
...@@ -132,14 +161,18 @@ async function handleUpdate() { ...@@ -132,14 +161,18 @@ async function handleUpdate() {
<template v-if="form.update_rule.type === 2"> <template v-if="form.update_rule.type === 2">
<span></span> <span></span>
<el-select v-model="form.update_rule.info" placeholder=" " style="width: 80px"> <el-select v-model="form.update_rule.info" placeholder=" " style="width: 80px">
<el-option v-for="item in weekList" :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> </el-select>
<span>的凌晨更新</span> <span>的凌晨更新</span>
</template> </template>
<template v-if="form.update_rule.type === 3"> <template v-if="form.update_rule.type === 3">
<span></span> <span></span>
<el-select v-model="form.update_rule.info" placeholder=" " style="width: 60px"> <el-select v-model="form.update_rule.info" placeholder=" " style="width: 60px">
<el-option v-for="item in 6" :label="item" :value="item"></el-option> <el-option v-for="item in 6" :key="item" :label="item" :value="item"></el-option>
</el-select> </el-select>
<span>天的凌晨更新</span> <span>天的凌晨更新</span>
</template> </template>
...@@ -149,6 +182,14 @@ async function handleUpdate() { ...@@ -149,6 +182,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">
......
...@@ -3,23 +3,23 @@ import type { Group } from '../types' ...@@ -3,23 +3,23 @@ import type { Group } from '../types'
import { UserFilled, Plus, Delete } from '@element-plus/icons-vue' import { UserFilled, Plus, Delete } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import { getNameByValue, groupTypeList, updateStatusRuleList } from '@/utils/dictionary' import { getNameByValue, groupTypeList, updateStatusRuleList, updateStatusList } from '@/utils/dictionary'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import { getGroupStatistics, getGroupMembers, clearGroupMembers } from '../api' import { getGroupStatistics, getGroupMembers, clearGroupMembers, updateGroupStatistics } from '../api'
import BindMembers from './BindMembers.vue' import BindMembers from './BindMembers.vue'
const props = defineProps<{ const props = defineProps<{
data: Group data: Group
}>() }>()
const emit = defineEmits<{ defineEmits<{
(e: 'update'): void (e: 'update'): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
const statusList = useMapStore().getMapValuesByKey('system_status') const statusList = useMapStore().getMapValuesByKey('system_status')
const detail = reactive({ count: 0, status: 1, updated_time: '-' }) const detail = reactive({ count: 0, status: '1', updated_time: '-' })
function fetchInfo() { function fetchInfo() {
getGroupStatistics({ group_id: props.data.id }).then(res => { getGroupStatistics({ group_id: props.data.id }).then(res => {
Object.assign(detail, res.data.detail) Object.assign(detail, res.data.detail)
...@@ -27,6 +27,14 @@ function fetchInfo() { ...@@ -27,6 +27,14 @@ function fetchInfo() {
} }
watchEffect(() => fetchInfo()) watchEffect(() => fetchInfo())
// 立即更新
function handleUpdate() {
updateGroupStatistics({ id: props.data.id }).then(() => {
ElMessage({ type: 'success', message: '更新成功' })
fetchInfo()
})
}
// 清空群组成员 // 清空群组成员
function handleClearMembers() { function handleClearMembers() {
ElMessageBox.confirm('确定要删清空该群组成员吗?', '提示').then(() => { ElMessageBox.confirm('确定要删清空该群组成员吗?', '提示').then(() => {
...@@ -36,6 +44,11 @@ function handleClearMembers() { ...@@ -36,6 +44,11 @@ function handleClearMembers() {
}) })
}) })
} }
// 添加群组成员
let selectMembersVisible = $ref(false)
function handleAdd() {
selectMembersVisible = true
}
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
...@@ -63,11 +76,6 @@ function handleRefresh() { ...@@ -63,11 +76,6 @@ function handleRefresh() {
fetchInfo() fetchInfo()
appList?.refetch() appList?.refetch()
} }
// 添加群组成员
let selectMembersVisible = $ref(false)
function handleAdd() {
selectMembersVisible = true
}
</script> </script>
<template> <template>
...@@ -120,8 +128,8 @@ function handleAdd() { ...@@ -120,8 +128,8 @@ function handleAdd() {
<dl> <dl>
<dt>更新状态</dt> <dt>更新状态</dt>
<dd> <dd>
<span>完成</span> <span style="margin-right: 10px">{{ getNameByValue(detail.status, updateStatusList) }}</span>
<el-button type="primary" plain size="small">立即更新</el-button> <el-button type="primary" plain @click="handleUpdate" size="small">立即更新</el-button>
</dd> </dd>
</dl> </dl>
</template> </template>
......
...@@ -6,6 +6,7 @@ import { ElMessageBox, ElMessage } from 'element-plus' ...@@ -6,6 +6,7 @@ import { ElMessageBox, ElMessage } from 'element-plus'
import { getNameByValue, groupTypeList, updateStatusRuleList } from '@/utils/dictionary' import { getNameByValue, groupTypeList, updateStatusRuleList } from '@/utils/dictionary'
import { getGroupList, deleteGroup } from '../api' import { getGroupList, deleteGroup } from '../api'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import SelectUser from '@/components/SelectUser.vue'
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue')) const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue')) const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue'))
...@@ -14,17 +15,23 @@ const statusList = useMapStore().getMapValuesByKey('system_status') ...@@ -14,17 +15,23 @@ const statusList = useMapStore().getMapValuesByKey('system_status')
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
const listParams = reactive({ name: '', id: '', status: '', updated_operator: '' })
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
remote: { remote: {
httpRequest: getGroupList, httpRequest: getGroupList,
params: { name: '', id: '', status: '', updated_operator: '' } params: listParams,
beforeRequest(params: any, isReset: boolean) {
if (isReset) listParams.updated_operator = ''
params.updated_operator = listParams.updated_operator
return params
}
}, },
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入群组名称' }, { type: 'input', prop: 'name', placeholder: '请输入群组名称' },
{ type: 'input', prop: 'id', placeholder: '请输入群组ID' }, { type: 'input', prop: 'id', placeholder: '请输入群组ID' },
{ type: 'select', prop: 'status', placeholder: '请选择群组状态', options: statusList }, { type: 'select', prop: 'status', placeholder: '请选择群组状态', options: statusList },
{ type: 'input', prop: 'updated_operator', placeholder: '更新人' } { type: 'input', prop: 'updated_operator', placeholder: '更新人', slots: 'filter-user' }
], ],
columns: [ columns: [
{ type: 'selection' }, { type: 'selection' },
...@@ -119,7 +126,9 @@ function handleView(row: Group) { ...@@ -119,7 +126,9 @@ function handleView(row: Group) {
> >
</el-space> </el-space>
</template> </template>
<template #filter-user>
<SelectUser v-model="listParams.updated_operator" placeholder="更新人" @change="handleRefresh"></SelectUser>
</template>
<template #table-status="{ row }: { row: Group }"> <template #table-status="{ row }: { row: Group }">
<el-tag :type="row.status === '1' ? 'success' : 'danger'"> <el-tag :type="row.status === '1' ? 'success' : 'danger'">
{{ getNameByValue(row.status, statusList) }} {{ getNameByValue(row.status, statusList) }}
......
...@@ -53,6 +53,11 @@ export function getLabelStatistics(params: { id: string }) { ...@@ -53,6 +53,11 @@ export function getLabelStatistics(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/tag/statistics', { params }) return httpRequest.get('/api/lab/v1/experiment/tag/statistics', { params })
} }
// 更新标签数据信息
export function updateLabelStatistics(data: { id: string }) {
return httpRequest.post('/api/lab/v1/experiment/tag/statistics-user-tag', data)
}
// 获取标签规则 // 获取标签规则
export function getLabelRule(params: { id: string }) { export function getLabelRule(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/tag/rule', { params }) return httpRequest.get('/api/lab/v1/experiment/tag/rule', { params })
......
...@@ -26,7 +26,7 @@ const form = reactive({ ...@@ -26,7 +26,7 @@ const form = reactive({
id: '', id: '',
name: '', name: '',
type_id: '', type_id: '',
update_status: '1', update_status: '2',
update_rule: { type: 1, info: 1 }, update_rule: { type: 1, info: 1 },
status: '1' status: '1'
}) })
...@@ -98,14 +98,22 @@ function handleUpdate() { ...@@ -98,14 +98,22 @@ function handleUpdate() {
</el-form-item> </el-form-item>
<el-form-item label="更新频率" prop="update_status"> <el-form-item label="更新频率" prop="update_status">
<el-radio-group v-model="form.update_status"> <el-radio-group v-model="form.update_status">
<el-radio v-for="item in updateStatusRuleList" :key="item.value" :label="item.value"> <el-radio
v-for="item in updateStatusRuleList"
:key="item.value"
:label="item.value"
:disabled="item.value === '1'">
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<div class="update-rule-wrap" v-if="form.update_status === '1'"> <div class="update-rule-wrap" v-if="form.update_status === '1'">
<span></span> <span></span>
<el-select v-model="form.update_rule.type" placeholder=" " style="width: 60px"> <el-select v-model="form.update_rule.type" placeholder=" " style="width: 60px">
<el-option v-for="item in dateUnitList" :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> </el-select>
<template v-if="form.update_rule.type === 1"> <template v-if="form.update_rule.type === 1">
<span>的凌晨更新</span> <span>的凌晨更新</span>
...@@ -113,14 +121,14 @@ function handleUpdate() { ...@@ -113,14 +121,14 @@ function handleUpdate() {
<template v-if="form.update_rule.type === 2"> <template v-if="form.update_rule.type === 2">
<span></span> <span></span>
<el-select v-model="form.update_rule.info" placeholder=" " style="width: 80px"> <el-select v-model="form.update_rule.info" placeholder=" " style="width: 80px">
<el-option v-for="item in weekList" :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> </el-select>
<span>的凌晨更新</span> <span>的凌晨更新</span>
</template> </template>
<template v-if="form.update_rule.type === 3"> <template v-if="form.update_rule.type === 3">
<span></span> <span></span>
<el-select v-model="form.update_rule.info" placeholder=" " style="width: 60px"> <el-select v-model="form.update_rule.info" placeholder=" " style="width: 60px">
<el-option v-for="item in 6" :label="item" :value="item"></el-option> <el-option v-for="item in 6" :key="item" :label="item" :value="item"></el-option>
</el-select> </el-select>
<span>天的凌晨更新</span> <span>天的凌晨更新</span>
</template> </template>
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
import type { Label } from '../types' import type { Label } from '../types'
import { UserFilled } from '@element-plus/icons-vue' import { UserFilled } from '@element-plus/icons-vue'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import { getNameByValue, updateStatusRuleList } from '@/utils/dictionary' import { getNameByValue, updateStatusRuleList, updateStatusList } from '@/utils/dictionary'
import { getLabelStatistics } from '../api' import { getLabelStatistics, updateLabelStatistics } from '../api'
// import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
const props = defineProps<{ const props = defineProps<{
data: Label data: Label
...@@ -12,14 +12,20 @@ const props = defineProps<{ ...@@ -12,14 +12,20 @@ const props = defineProps<{
const statusList = useMapStore().getMapValuesByKey('system_status') const statusList = useMapStore().getMapValuesByKey('system_status')
const detail = reactive({ count: 0, status: 1, updated_time: '-' }) const detail = reactive({ count: 0, status: '1', updated_time: '-' })
function fetchInfo() { function fetchInfo() {
getLabelStatistics({ id: props.data.id }).then(res => { getLabelStatistics({ id: props.data.id }).then(res => {
console.log(res)
Object.assign(detail, res.data.detail) Object.assign(detail, res.data.detail)
}) })
} }
watchEffect(() => fetchInfo()) watchEffect(() => fetchInfo())
function handleUpdate() {
updateLabelStatistics({ id: props.data.id }).then(() => {
ElMessage({ type: 'success', message: '更新成功' })
fetchInfo()
})
}
</script> </script>
<template> <template>
...@@ -62,8 +68,8 @@ watchEffect(() => fetchInfo()) ...@@ -62,8 +68,8 @@ watchEffect(() => fetchInfo())
<dl> <dl>
<dt>更新状态</dt> <dt>更新状态</dt>
<dd> <dd>
<span>完成</span> <span style="margin-right: 10px">{{ getNameByValue(detail.status, updateStatusList) }}</span>
<el-button type="primary" plain size="small">立即更新</el-button> <el-button type="primary" plain @click="handleUpdate" size="small">立即更新</el-button>
</dd> </dd>
</dl> </dl>
</div> </div>
......
...@@ -8,6 +8,7 @@ import { getLabelList, deleteLabel } from '../api' ...@@ -8,6 +8,7 @@ import { getLabelList, deleteLabel } from '../api'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import { getNameByValue, updateStatusRuleList } from '@/utils/dictionary' import { getNameByValue, updateStatusRuleList } from '@/utils/dictionary'
import { useLabelType } from '../composables/useLabelType' import { useLabelType } from '../composables/useLabelType'
import SelectUser from '@/components/SelectUser.vue'
const LabelFormDialog = defineAsyncComponent(() => import('../components/LabelFormDialog.vue')) const LabelFormDialog = defineAsyncComponent(() => import('../components/LabelFormDialog.vue'))
const LabelViewDialog = defineAsyncComponent(() => import('../components/LabelViewDialog.vue')) const LabelViewDialog = defineAsyncComponent(() => import('../components/LabelViewDialog.vue'))
...@@ -18,11 +19,17 @@ const { typeList } = useLabelType() ...@@ -18,11 +19,17 @@ const { typeList } = useLabelType()
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
const listParams = reactive({ name: '', type_id: '', status: '', updated_operator: '' })
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
remote: { remote: {
httpRequest: getLabelList, httpRequest: getLabelList,
params: { name: '', type_id: '', status: '', updated_operator: '' } params: listParams,
beforeRequest(params: any, isReset: boolean) {
if (isReset) listParams.updated_operator = ''
params.updated_operator = listParams.updated_operator
return params
}
}, },
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入标签名称' }, { type: 'input', prop: 'name', placeholder: '请输入标签名称' },
...@@ -35,7 +42,7 @@ const listOptions = computed(() => { ...@@ -35,7 +42,7 @@ const listOptions = computed(() => {
valueKey: 'id' valueKey: 'id'
}, },
{ type: 'select', prop: 'status', placeholder: '请选择标签状态', options: statusList }, { type: 'select', prop: 'status', placeholder: '请选择标签状态', options: statusList },
{ type: 'input', prop: 'updated_operator', placeholder: '更新人' } { type: 'input', prop: 'updated_operator', placeholder: '更新人', slots: 'filter-user' }
], ],
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
...@@ -107,6 +114,9 @@ function handleRule(row: Label) { ...@@ -107,6 +114,9 @@ function handleRule(row: Label) {
<el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button> <el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button>
</el-space> </el-space>
</template> </template>
<template #filter-user>
<SelectUser v-model="listParams.updated_operator" placeholder="更新人" @change="handleRefresh"></SelectUser>
</template>
<template #table-status="{ row }: { row: Label }"> <template #table-status="{ row }: { row: Label }">
<el-tag :type="row.status === '1' ? 'success' : 'danger'"> <el-tag :type="row.status === '1' ? 'success' : 'danger'">
{{ getNameByValue(row.status, statusList) }} {{ getNameByValue(row.status, statusList) }}
......
import httpRequest from '@/utils/axios' import httpRequest from '@/utils/axios'
import type { TripTemplateListRequest, TripTemplateCreateRequest, TripTemplateUpdateRequest } from './types' import type { TripTemplateListRequest, TripTemplateCreateRequest, TripTemplateUpdateRequest } from './types'
// 获取旅程模板列表 // 获取旅程模板列表
export function getTripTemplateList(params: TripTemplateListRequest) { export function getTripTemplateList(params: TripTemplateListRequest) {
return httpRequest.get('/api/lab/v1/experiment/itinerary/list', { params }) return httpRequest.get('/api/lab/v1/experiment/itinerary/list', { params })
...@@ -14,3 +15,13 @@ export function createTripTemplate(data: TripTemplateCreateRequest) { ...@@ -14,3 +15,13 @@ export function createTripTemplate(data: TripTemplateCreateRequest) {
export function updateTripTemplate(data: TripTemplateUpdateRequest) { export function updateTripTemplate(data: TripTemplateUpdateRequest) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/update', data) return httpRequest.post('/api/lab/v1/experiment/itinerary/update', data)
} }
// 获取旅程连接
export function getTripConnections(params: { itinerary_id: string }) {
return httpRequest.get('/api/lab/v1/experiment/itinerary/connections', { params })
}
// 旅程绑定连接
export function bindTripConnections(data: { itinerary_id: string; connection_ids: string[] }) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/bind-connections', data)
}
<script setup lang="ts">
import type { TripTemplate } from '../types'
import { ElMessage } from 'element-plus'
import { getTripConnections, bindTripConnections } from '../api'
import type { ConnectionType } from '@/composables/useAllData'
import { useConnection } from '@/composables/useAllData'
import ConnectionIcon from '@/components/ConnectionIcon.vue'
const props = defineProps<{
data: TripTemplate
}>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const { connectionList } = useConnection()
const multipleSelection = ref<ConnectionType[]>([])
function fetchList() {
getTripConnections({ itinerary_id: props.data.id }).then(res => {
multipleSelection.value = res.data.items
})
}
watchEffect(() => fetchList())
function toggleSelection(data: ConnectionType) {
const foundIndex = multipleSelection.value.findIndex(item => item.id === data.id)
foundIndex === -1 ? multipleSelection.value.push(data) : multipleSelection.value.splice(foundIndex, 1)
}
function isActive(data: ConnectionType) {
return !!multipleSelection.value.find(item => item.id === data.id)
}
// 保存
function handleSave() {
const ids = multipleSelection.value.map(item => item.id)
bindTripConnections({ itinerary_id: props.data.id, connection_ids: ids }).then(() => {
ElMessage({ message: '保存成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
</script>
<template>
<el-dialog title="配置连接" width="800px" append-to-body @update:modelValue="$emit('update:modelValue')">
<div class="connection-list">
<div
class="connection-item"
v-for="item in connectionList"
:key="item.id"
:class="{ 'is-active': isActive(item) }"
@click="toggleSelection(item)">
<el-checkbox :model-value="isActive(item)" />
<div class="connection-item__icon"><ConnectionIcon :name="item.type + ''" /></div>
<p>{{ item.name }}</p>
</div>
</div>
<template #footer>
<el-row justify="center">
<el-button plain auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
<el-button type="primary" plain auto-insert-space @click="handleSave">保存</el-button>
</el-row>
</template>
</el-dialog>
</template>
<style lang="scss">
.connection-list {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.connection-item {
position: relative;
height: 100px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #fff;
border: 1px dashed #bbb;
cursor: pointer;
&.is-active {
background-color: rgb(204 247 131 / 38%);
}
.el-checkbox {
position: absolute;
left: 10px;
top: 0;
}
}
</style>
...@@ -32,7 +32,7 @@ watchEffect(() => { ...@@ -32,7 +32,7 @@ watchEffect(() => {
const rules = ref<FormRules>({ const rules = ref<FormRules>({
name: [{ required: true, message: '请输入模板名称' }], name: [{ required: true, message: '请输入模板名称' }],
type: [{ required: true, message: '请选择模板类型' }], type: [{ required: true, message: '请选择旅程类型' }],
score: [{ required: true, message: '请输入不超过100的整数数值' }] score: [{ required: true, message: '请输入不超过100的整数数值' }]
}) })
...@@ -66,7 +66,7 @@ function handleUpdate() { ...@@ -66,7 +66,7 @@ function handleUpdate() {
<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="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="模板类型" prop="type"> <el-form-item label="旅程类型" prop="type">
<el-select v-model="form.type" style="width: 100%"> <el-select v-model="form.type" style="width: 100%">
<el-option v-for="item in tripTemplateTypeList" :key="item.value" v-bind="item"></el-option> <el-option v-for="item in tripTemplateTypeList" :key="item.value" v-bind="item"></el-option>
</el-select> </el-select>
......
...@@ -13,7 +13,7 @@ const statusList = useMapStore().getMapValuesByKey('system_status') ...@@ -13,7 +13,7 @@ const statusList = useMapStore().getMapValuesByKey('system_status')
<el-form ref="formRef" label-suffix=":"> <el-form ref="formRef" label-suffix=":">
<el-row justify="space-between"> <el-row justify="space-between">
<el-form-item label="模板名称" prop="name"> {{ data.name }} </el-form-item> <el-form-item label="模板名称" prop="name"> {{ data.name }} </el-form-item>
<el-form-item label="模板类型" prop="type"> <el-form-item label="旅程类型" prop="type">
{{ getNameByValue(data.type, tripTemplateTypeList) }} {{ getNameByValue(data.type, tripTemplateTypeList) }}
</el-form-item> </el-form-item>
<el-form-item label="旅程分值" prop="score"> {{ data.score }} </el-form-item> <el-form-item label="旅程分值" prop="score"> {{ data.score }} </el-form-item>
......
...@@ -9,6 +9,7 @@ import { getNameByValue, tripTemplateTypeList } from '@/utils/dictionary' ...@@ -9,6 +9,7 @@ import { getNameByValue, tripTemplateTypeList } from '@/utils/dictionary'
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue')) const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue')) const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue'))
const BindConnection = defineAsyncComponent(() => import('../components/BindConnection.vue'))
const statusList = useMapStore().getMapValuesByKey('system_status') const statusList = useMapStore().getMapValuesByKey('system_status')
...@@ -22,7 +23,7 @@ const listOptions = computed(() => { ...@@ -22,7 +23,7 @@ const listOptions = computed(() => {
}, },
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入旅程模板名称' }, { type: 'input', prop: 'name', placeholder: '请输入旅程模板名称' },
{ type: 'select', prop: 'type', placeholder: '请选择旅程模板类型', options: tripTemplateTypeList }, { type: 'select', prop: 'type', placeholder: '请选择旅程类型', options: tripTemplateTypeList },
{ type: 'select', prop: 'status', placeholder: '请选择旅程模板状态', options: statusList } { type: 'select', prop: 'status', placeholder: '请选择旅程模板状态', options: statusList }
], ],
columns: [ columns: [
...@@ -30,7 +31,7 @@ const listOptions = computed(() => { ...@@ -30,7 +31,7 @@ const listOptions = computed(() => {
{ label: '模板名称', prop: 'name' }, { label: '模板名称', prop: 'name' },
{ label: '所属实验', prop: 'experiment.name' }, { label: '所属实验', prop: 'experiment.name' },
{ {
label: '模板类型', label: '旅程类型',
prop: 'type', prop: 'type',
computed({ row }: { row: TripTemplate }) { computed({ row }: { row: TripTemplate }) {
return getNameByValue(row.type, tripTemplateTypeList) return getNameByValue(row.type, tripTemplateTypeList)
...@@ -81,6 +82,13 @@ function handleView(row: TripTemplate) { ...@@ -81,6 +82,13 @@ function handleView(row: TripTemplate) {
currentRow = row currentRow = row
viewVisible = true viewVisible = true
} }
// 配置
let configVisible = $ref(false)
function handleConfig(row: TripTemplate) {
currentRow = row
configVisible = true
}
</script> </script>
<template> <template>
...@@ -95,7 +103,7 @@ function handleView(row: TripTemplate) { ...@@ -95,7 +103,7 @@ function handleView(row: TripTemplate) {
<el-tag :type="row.status === '1' ? 'success' : 'danger'">{{ getNameByValue(row.status, statusList) }}</el-tag> <el-tag :type="row.status === '1' ? 'success' : 'danger'">{{ getNameByValue(row.status, statusList) }}</el-tag>
</template> </template>
<template #table-x="{ row }: { row: TripTemplate }"> <template #table-x="{ row }: { row: TripTemplate }">
<el-button type="primary" plain>配置</el-button> <el-button type="primary" plain @click="handleConfig(row)">配置</el-button>
<el-button type="primary" plain @click="handleView(row)">查看</el-button> <el-button type="primary" plain @click="handleView(row)">查看</el-button>
<el-button type="primary" plain @click="handleUpdate(row)">编辑</el-button> <el-button type="primary" plain @click="handleUpdate(row)">编辑</el-button>
<el-button type="primary" plain @click="handleRemove(row)">删除</el-button> <el-button type="primary" plain @click="handleRemove(row)">删除</el-button>
...@@ -106,4 +114,6 @@ function handleView(row: TripTemplate) { ...@@ -106,4 +114,6 @@ function handleView(row: TripTemplate) {
<FormDialog v-model="formVisible" :data="currentRow" @update="handleRefresh" v-if="formVisible"></FormDialog> <FormDialog v-model="formVisible" :data="currentRow" @update="handleRefresh" v-if="formVisible"></FormDialog>
<!-- 查看 --> <!-- 查看 -->
<ViewDialog v-model="viewVisible" :data="currentRow" v-if="viewVisible && currentRow"></ViewDialog> <ViewDialog v-model="viewVisible" :data="currentRow" v-if="viewVisible && currentRow"></ViewDialog>
<!-- 配置 -->
<BindConnection v-model="configVisible" :data="currentRow" v-if="configVisible && currentRow"></BindConnection>
</template> </template>
...@@ -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[]
}
...@@ -7,7 +7,7 @@ export function getNameByValue(value: string | number, list: Dictionary[]) { ...@@ -7,7 +7,7 @@ export function getNameByValue(value: string | number, list: Dictionary[]) {
return list.find(item => item.value === value)?.label || value return list.find(item => item.value === value)?.label || value
} }
// 旅程模板类型 // 旅程类型
export const tripTemplateTypeList = [ export const tripTemplateTypeList = [
{ label: '自由旅程', value: '1' }, { label: '自由旅程', value: '1' },
{ label: '固定旅程', value: '2' } { label: '固定旅程', value: '2' }
...@@ -25,6 +25,13 @@ export const updateStatusRuleList = [ ...@@ -25,6 +25,13 @@ export const updateStatusRuleList = [
{ label: '手动更新', value: '2' } { label: '手动更新', value: '2' }
] ]
// 更新状态
export const updateStatusList = [
{ label: '未开始', value: '1' },
{ label: '进行中', value: '2' },
{ label: '完成', value: '3' }
]
export const dateUnitList = [ export const dateUnitList = [
{ label: '天', value: 1 }, { label: '天', value: 1 },
{ label: '周', value: 2 }, { label: '周', value: 2 },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论