Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
5e027871
提交
5e027871
authored
6月 21, 2024
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: 新增用户旅程数据生成
上级
13df73f3
隐藏空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
376 行增加
和
91 行删除
+376
-91
generateEvent.ts
src/api/generateEvent.ts
+11
-0
ViewGenerateEventData.vue
src/components/ViewGenerateEventData.vue
+87
-0
FieldDialog.vue
src/modules/metadata/event/components/FieldDialog.vue
+34
-52
types.ts
src/modules/metadata/event/types.ts
+5
-1
api.ts
src/modules/trip/my/api.ts
+5
-0
GenerateData.vue
src/modules/trip/my/components/GenerateData.vue
+81
-0
types.ts
src/modules/trip/my/types.ts
+1
-0
Index.vue
src/modules/trip/my/views/Index.vue
+17
-13
api.ts
src/modules/trip/template/api.ts
+17
-1
GenerateRule.vue
src/modules/trip/template/components/GenerateRule.vue
+91
-0
Index.vue
src/modules/trip/template/views/Index.vue
+11
-1
Index.vue
src/modules/user/views/Index.vue
+16
-23
没有找到文件。
src/api/generateEvent.ts
0 → 100644
浏览文件 @
5e027871
import
httpRequest
from
'@/utils/axios'
// 旅程生成用户事件数据列表(搜索条件)
export
function
getGenerateListFilter
()
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/member/itinerary-generate-data-condition'
)
}
// 旅程生成用户事件数据列表
export
function
getGenerateList
(
params
:
any
)
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/member/itinerary-generate-data'
,
{
params
})
}
src/components/ViewGenerateEventData.vue
0 → 100644
浏览文件 @
5e027871
<
script
setup
>
import
AppList
from
'@/components/base/AppList.vue'
import
{
getGenerateListFilter
,
getGenerateList
}
from
'@/api/generateEvent'
const
ViewEvent
=
defineAsyncComponent
(()
=>
import
(
'@/components/ViewEvent.vue'
))
import
{
useUserStore
}
from
'@/stores/user'
const
userStore
=
useUserStore
()
const
filter
=
reactive
({
students
:
[],
connections
:
[],
events
:
[]
})
async
function
fetchListFilters
()
{
const
{
data
}
=
await
getGenerateListFilter
()
Object
.
assign
(
filter
,
data
)
}
onMounted
(()
=>
{
fetchListFilters
()
})
const
students
=
computed
(()
=>
{
return
filter
.
students
.
map
((
item
)
=>
{
return
{
...
item
,
name
:
`
${
item
.
name
}
/
${
item
.
mobile
}
`
}
})
})
// 列表配置
const
listOptions
=
computed
(()
=>
{
const
userId
=
userStore
.
role
.
id
==
1
?
userStore
.
user
?.
id
:
''
return
{
remote
:
{
httpRequest
:
getGenerateList
,
params
:
{
created_operator
:
userId
,
name
:
''
,
connection_id
:
''
,
experiment_meta_event_id
:
''
,
created_time_start
:
''
,
created_time_end
:
''
}
},
filters
:
[
{
type
:
'select'
,
prop
:
'created_operator'
,
placeholder
:
'请选择学生姓名'
,
options
:
students
.
value
,
labelKey
:
'name'
,
valueKey
:
'sso_id'
,
disabled
:
!!
userId
},
{
type
:
'input'
,
prop
:
'name'
,
placeholder
:
'请输入用户姓名'
},
{
type
:
'select'
,
prop
:
'connection_id'
,
placeholder
:
'请选择来源连接'
,
options
:
filter
.
connections
,
labelKey
:
'type_name'
,
valueKey
:
'id'
},
{
type
:
'select'
,
prop
:
'experiment_meta_event_id'
,
placeholder
:
'请选择事件'
,
options
:
filter
.
events
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'input'
,
prop
:
'created_time_start'
,
slots
:
'filter-start'
},
{
type
:
'input'
,
prop
:
'created_time_end'
,
slots
:
'filter-end'
}
],
columns
:
[
{
label
:
'序号'
,
type
:
'index'
,
width
:
60
},
{
label
:
'连接'
,
prop
:
'connection_name'
},
{
label
:
'事件名称'
,
prop
:
'event_name'
},
{
label
:
'用户名称'
,
prop
:
'member.name'
},
{
label
:
'手机号'
,
prop
:
'member.mobile'
},
{
label
:
'事件发生时间'
,
prop
:
'created_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
220
}
]
}
})
const
viewEventVisible
=
ref
(
false
)
const
currentViewEvent
=
ref
()
function
handleViewEvent
(
item
)
{
viewEventVisible
.
value
=
true
currentViewEvent
.
value
=
item
}
</
script
>
<
template
>
<el-dialog
title=
"用户事件数据"
width=
"1000px"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
filter-start=
"
{ params }">
<el-date-picker
v-model=
"params.created_time_start"
type=
"datetime"
placeholder=
"请选择事件发生起始时间"
value-format=
"YYYY-MM-DD HH:mm:ss"
/>
</
template
>
<
template
#
filter-end=
"{ params }"
>
<el-date-picker
v-model=
"params.created_time_end"
type=
"datetime"
placeholder=
"请选择事件发生截止时间"
value-format=
"YYYY-MM-DD HH:mm:ss"
/>
</
template
>
<
template
#
table-x=
"{ row }"
>
<el-button
type=
"primary"
plain
@
click=
"handleViewEvent(row)"
>
事件详情
</el-button>
<el-button
type=
"primary"
plain
>
<router-link
target=
"_blank"
:to=
"
{ path: '/user/image', query: { user_id: row.member.id, experiment_id: row.experiment_id } }">用户详情
</router-link>
</el-button>
</
template
>
</AppList>
<!-- 事件详情 -->
<ViewEvent
v-model=
"viewEventVisible"
:event=
"currentViewEvent"
:user=
"currentViewEvent.member"
v-if=
"viewEventVisible && currentViewEvent"
></ViewEvent>
</el-dialog>
</template>
src/modules/metadata/event/components/FieldDialog.vue
浏览文件 @
5e027871
...
...
@@ -26,12 +26,13 @@ const addField = function () {
}
// 删除字段
const
deleteField
=
function
(
scope
:
{
$index
:
number
;
row
:
{
id
:
string
}
})
{
const
deleteField
=
function
(
scope
:
{
$index
:
number
;
row
:
EventAttributesProp
})
{
if
(
scope
.
row
.
isDefault
)
return
if
(
tableData
[
scope
.
$index
]?.
id
===
''
)
{
tableData
.
splice
(
scope
.
$index
,
1
)
}
else
{
// 判断当前属性是否可以删除
getIsDeleteAttribute
({
id
:
scope
.
row
.
id
}).
then
(
res
=>
{
getIsDeleteAttribute
({
id
:
scope
.
row
.
id
}).
then
(
(
res
)
=>
{
res
.
data
?.
can_delete
?
tableData
.
splice
(
scope
.
$index
,
1
)
:
ElMessage
({
message
:
'不能删除'
,
type
:
'warning'
})
})
}
...
...
@@ -41,12 +42,19 @@ const deleteField = function (scope: { $index: number; row: { id: string } }) {
let
eventDetail
=
$ref
<
EventDetailProp
>
()
onBeforeMount
(()
=>
{
getMetaEventDetail
({
id
:
props
.
data
?.
id
||
''
}).
then
(
res
=>
{
getMetaEventDetail
({
id
:
props
.
data
?.
id
||
''
}).
then
(
(
res
)
=>
{
eventDetail
=
res
.
data
tableData
=
res
.
data
.
attributes
tableData
=
defaultFields
.
concat
(
res
.
data
.
attributes
)
})
})
// 默认字段
const
defaultFields
=
[
{
id
:
'1'
,
name
:
'事件ID'
,
english_name
:
'action_id'
,
type
:
'1'
,
format
:
'25'
,
isDefault
:
true
},
{
id
:
'2'
,
name
:
'事件发生时间'
,
english_name
:
'action_time'
,
type
:
'5'
,
format
:
'yyyy-mm-dd hh:mm:ss'
,
isDefault
:
true
},
{
id
:
'3'
,
name
:
'用户ID'
,
english_name
:
'user_id'
,
type
:
'1'
,
format
:
'25'
,
isDefault
:
true
}
]
// 字段
let
tableData
=
$ref
<
EventAttributesProp
[]
>
([])
...
...
@@ -58,7 +66,7 @@ function handleSubmit() {
function
handleUpdate
()
{
const
params
=
{
id
:
eventDetail
?.
id
||
''
,
attributes
:
JSON
.
stringify
(
tableData
)
attributes
:
JSON
.
stringify
(
tableData
.
filter
((
item
)
=>
!
item
.
isDefault
)
)
}
updateAttributes
(
params
).
then
(()
=>
{
ElMessage
({
message
:
'保存成功'
,
type
:
'success'
})
...
...
@@ -111,12 +119,7 @@ const popoverText = function (row: any) {
</
script
>
<
template
>
<el-dialog
title=
"事件属性"
:close-on-click-modal=
"false"
width=
"800px"
@
update:modelValue=
"value => $emit('update:modelValue', value)"
>
<el-dialog
title=
"事件属性"
:close-on-click-modal=
"false"
width=
"800px"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
<div
style=
"display: flex; justify-content: space-around"
>
<el-form
label-width=
"120px"
>
<el-form-item
label=
"事件英文名称:"
>
{{
eventDetail
?.
english_name
}}
</el-form-item>
...
...
@@ -136,71 +139,51 @@ const popoverText = function (row: any) {
</
template
>
<el-table
:data=
"tableData"
style=
"width: 100%"
>
<el-table-column
label=
"属性英文名"
>
<
template
#
default=
"
scope
"
>
<el-input
v-model=
"
scope.row.english_name"
placeholder=
"请输入
"
></el-input>
<
template
#
default=
"
{ row }
"
>
<el-input
v-model=
"
row.english_name"
placeholder=
"请输入"
:disabled=
"row.isDefault
"
></el-input>
</
template
>
</el-table-column>
<el-table-column
label=
"属性名称"
>
<
template
#
default=
"
scope
"
>
<el-input
v-model=
"
scope.row.name"
placeholder=
"请输入
"
></el-input>
<
template
#
default=
"
{ row }
"
>
<el-input
v-model=
"
row.name"
placeholder=
"请输入"
:disabled=
"row.isDefault
"
></el-input>
</
template
>
</el-table-column>
<el-table-column
label=
"字段类型"
>
<
template
#
default=
"scope"
>
<el-select
@
change=
"changeFormatType(scope.row)"
:disabled=
"scope.row.id !== ''"
v-model=
"scope.row.type"
placeholder=
"请选择"
>
<el-option
:label=
"item.label"
:value=
"item.value"
:key=
"item.id"
v-for=
"item in experimentAttributeOptions"
></el-option>
<
template
#
default=
"{ row }"
>
<el-select
@
change=
"changeFormatType(row)"
:disabled=
"row.id !== ''"
v-model=
"row.type"
placeholder=
"请选择"
>
<el-option
:label=
"item.label"
:value=
"item.value"
:key=
"item.id"
v-for=
"item in experimentAttributeOptions"
></el-option>
</el-select>
</
template
>
</el-table-column>
<el-table-column
label=
"字段格式"
>
<
template
#
default=
"scope"
>
<el-select
:disabled=
"scope.row.id !== ''"
v-if=
"scope.row.type === '4' || scope.row.type === '5'"
v-model=
"scope.row.format"
placeholder=
"请选择"
>
<el-option
v-if=
"scope.row.type !== '5'"
label=
"yyyy-mm-dd"
value=
"yyyy-mm-dd"
></el-option>
<el-option
v-if=
"scope.row.type !== '4'"
label=
"yyyy-mm-dd hh:mm:ss"
value=
"yyyy-mm-dd hh:mm:ss"
></el-option>
<
template
#
default=
"{ row }"
>
<el-select
:disabled=
"row.id !== ''"
v-if=
"row.type === '4' || row.type === '5'"
v-model=
"row.format"
placeholder=
"请选择"
>
<el-option
v-if=
"row.type !== '5'"
label=
"yyyy-mm-dd"
value=
"yyyy-mm-dd"
></el-option>
<el-option
v-if=
"row.type !== '4'"
label=
"yyyy-mm-dd hh:mm:ss"
value=
"yyyy-mm-dd hh:mm:ss"
></el-option>
</el-select>
<el-input
v-else
:disabled=
"
scope.
row.id !== ''"
:disabled=
"row.id !== ''"
type=
"number"
v-model=
"scope.row.format"
:placeholder=
"scope.row.type === '1' ? '请输入字符串长度' : '请输入长度'"
></el-input>
v-model=
"row.format"
:placeholder=
"row.type === '1' ? '请输入字符串长度' : '请输入长度'"
></el-input>
</
template
>
</el-table-column>
<el-table-column
width=
"30"
>
<
template
#
default=
"
scope
"
>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"hover"
:title=
"
scope?.
row.type_name"
>
<
template
#
default=
"
{ row }
"
>
<el-popover
placement=
"top-start"
:width=
"300"
trigger=
"hover"
:title=
"row.type_name"
>
<template
#
reference
>
<div
style=
"display: flex; justify-content: center; cursor: pointer"
>
<el-icon
size=
"20"
><QuestionFilled
/></el-icon>
</div>
</
template
>
<div
v-html=
"popoverText(
scope.
row)"
></div>
<div
v-html=
"popoverText(row)"
></div>
</el-popover>
</template>
</el-table-column>
<el-table-column
width=
"30"
v-if=
"props.data?.can_edit !== '0'"
>
<
template
#
default=
"scope"
>
<div
@
click=
"deleteField(scope)"
style=
"display: flex; justify-content: center; cursor: pointer"
>
<div
@
click=
"deleteField(scope)"
style=
"display: flex; justify-content: center; cursor: pointer"
v-if=
"!scope.row.isDefault"
>
<el-icon
size=
"20"
><Close
/></el-icon>
</div>
</
template
>
...
...
@@ -210,13 +193,12 @@ const popoverText = function (row: any) {
<
template
#
footer
>
<el-row
justify=
"center"
>
<el-button
round
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
v-if=
"props.data?.can_edit !== '0'"
>
保存
</el-button
>
<el-button
type=
"primary"
round
auto-insert-space
@
click=
"handleSubmit"
v-if=
"props.data?.can_edit !== '0'"
>
保存
</el-button>
</el-row>
</
template
>
</el-dialog>
</template>
<
style
lang=
"scss"
>
.card-header
{
display
:
flex
;
...
...
src/modules/metadata/event/types.ts
浏览文件 @
5e027871
...
...
@@ -11,7 +11,10 @@ export interface EventProp {
can_edit
:
string
}
export
interface
ConnectionOptionProp
{
type_name
:
string
;
id
:
string
}
export
interface
ConnectionOptionProp
{
type_name
:
string
id
:
string
}
export
interface
EventDetailProp
{
id
:
string
...
...
@@ -27,4 +30,5 @@ export interface EventAttributesProp {
english_name
:
string
type
:
string
format
:
string
isDefault
?:
boolean
}
src/modules/trip/my/api.ts
浏览文件 @
5e027871
...
...
@@ -19,3 +19,8 @@ export function bindTripConnections(data: { itinerary_id: string; connections_id
export
function
getTripTemplateDemo
(
params
:
{
itinerary_id
?:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/itinerary/get-itinerary-demo'
,
{
params
})
}
// 一键生成旅程数据
export
function
studentGenerateData
(
data
:
{
itinerary_id
:
string
;
type
:
number
})
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/itinerary/student-generate-data'
,
data
)
}
src/modules/trip/my/components/GenerateData.vue
0 → 100644
浏览文件 @
5e027871
<
script
setup
lang=
"ts"
>
import
type
{
Trip
}
from
'../types'
import
{
studentGenerateData
}
from
'../api'
import
{
ElMessage
}
from
'element-plus'
const
props
=
defineProps
<
{
data
:
Trip
}
>
()
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
}
>
()
const
dialogVisible
=
ref
(
false
)
const
generateVisible
=
ref
(
false
)
const
generateLoading
=
ref
(
false
)
const
params
=
reactive
({
type
:
1
,
itinerary_id
:
props
.
data
.
id
})
async
function
handleGenerate
()
{
dialogVisible
.
value
=
false
generateLoading
.
value
=
true
generateVisible
.
value
=
true
try
{
await
studentGenerateData
(
params
)
emit
(
'update'
)
ElMessage
.
success
(
'生成数据成功'
)
}
catch
(
error
)
{
console
.
error
(
error
)
}
finally
{
generateLoading
.
value
=
false
generateVisible
.
value
=
false
}
}
</
script
>
<
template
>
<el-button
type=
"primary"
:disabled=
"generateLoading"
@
click=
"dialogVisible = true"
>
一键生成旅程数据
</el-button>
<el-dialog
v-model=
"dialogVisible"
width=
"400"
title=
"生成旅程数据"
>
<p
class=
"dialog-text"
v-if=
"data.has_itinerary_generate_data"
>
系统检测到您正在重复生成用户旅程事件数据!
<br
/>
该操作将会覆盖您之前生成的数据且无法恢复,请确认!
</p>
<p
class=
"dialog-text"
v-else
>
即将生成用户旅程相关事件数据,
<br
/>
请确认您的用户旅程的每一个节点已经完成配置!
</p>
<el-radio-group
v-model=
"params.type"
class=
"dialog-radio-group"
>
<el-radio
label=
"今日"
:value=
"1"
></el-radio>
<el-radio
label=
"前7日"
:value=
"2"
></el-radio>
<el-radio
label=
"前30日"
:value=
"3"
></el-radio>
</el-radio-group>
<template
#
footer
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleGenerate"
>
生成数据
</el-button>
</
template
>
</el-dialog>
<el-dialog
v-model=
"generateVisible"
title=
"提示"
width=
"400"
>
<p
class=
"dialog-text"
>
正在生成数据中,请耐心等待
</p>
<
template
#
footer
>
<el-button
@
click=
"generateVisible = false"
>
关闭
</el-button>
</
template
>
</el-dialog>
</template>
<
style
lang=
"scss"
>
.dialog-text
{
line-height
:
24px
;
text-align
:
center
;
}
.dialog-radio-group
{
margin
:
10px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
</
style
>
src/modules/trip/my/types.ts
浏览文件 @
5e027871
...
...
@@ -22,4 +22,5 @@ export interface Trip {
experiment_itinerary_name
:
string
experiment_itinerary_type
:
string
experiment_itinerary_type_name
:
string
has_itinerary_generate_data
:
boolean
}
src/modules/trip/my/views/Index.vue
浏览文件 @
5e027871
...
...
@@ -6,6 +6,8 @@ import { ElMessage } from 'element-plus'
import
{
getStudentTrip
,
getTripTemplateDemo
,
updateTrip
}
from
'../api'
const
BindConnection
=
defineAsyncComponent
(()
=>
import
(
'../components/BindConnection.vue'
))
const
ViewGenerateEventData
=
defineAsyncComponent
(()
=>
import
(
'@/components/ViewGenerateEventData.vue'
))
const
GenerateData
=
defineAsyncComponent
(()
=>
import
(
'../components/GenerateData.vue'
))
const
detail
=
ref
<
Trip
>
()
const
elements
=
ref
([])
...
...
@@ -61,16 +63,22 @@ function handleConnectionUpdate(value: string[]) {
if
(
!
detail
.
value
)
return
detail
.
value
.
connect_ids
=
value
}
const
generateEventVisible
=
ref
(
false
)
</
script
>
<
template
>
<AppCard
:title=
"detail?.experiment_itinerary_type_name"
v-if=
"detail"
>
<el-card
shadow=
"never"
style=
"margin-bottom: 20px"
v-if=
"detail"
>
<el-descriptions
class=
"info"
>
<el-descriptions-item
label=
"课程名称:"
>
{{
detail
.
course_name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"实验名称:"
>
{{
detail
.
experiment_name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"旅程类型:"
>
{{
detail
.
experiment_itinerary_type_name
}}
</el-descriptions-item>
</el-descriptions>
<div
style=
"display: flex; align-items: center"
>
<el-descriptions
class=
"info"
style=
"flex: 1"
>
<el-descriptions-item
label=
"课程名称:"
>
{{
detail
.
course_name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"实验名称:"
>
{{
detail
.
experiment_name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"旅程类型:"
>
{{
detail
.
experiment_itinerary_type_name
}}
</el-descriptions-item>
</el-descriptions>
<GenerateData
:data=
"detail"
@
update=
"fetchInfo"
></GenerateData>
<el-button
type=
"primary"
@
click=
"generateEventVisible = true"
v-if=
"detail.has_itinerary_generate_data"
>
查看用户旅程数据
</el-button>
</div>
</el-card>
<TripFlow
v-model=
"elements"
...
...
@@ -84,9 +92,7 @@ function handleConnectionUpdate(value: string[]) {
</
template
>
<
template
#
header
>
<el-row
align=
"middle"
>
<el-button
type=
"primary"
size=
"large"
@
click=
"handleConfig"
style=
"margin-right: 20px"
v-if=
"false"
>
配置连接
</el-button
>
<el-button
type=
"primary"
size=
"large"
@
click=
"handleConfig"
style=
"margin-right: 20px"
v-if=
"false"
>
配置连接
</el-button>
<el-alert
center
style=
"flex: 1"
>
<p
style=
"text-align: center"
>
<template
v-if=
"isFree"
>
...
...
@@ -107,9 +113,7 @@ function handleConnectionUpdate(value: string[]) {
</AppCard>
<!-- 配置连接 -->
<BindConnection
v-model=
"configVisible"
:data=
"detail"
@
update=
"handleConnectionUpdate"
v-if=
"configVisible && detail"
></BindConnection>
<BindConnection
v-model=
"configVisible"
:data=
"detail"
@
update=
"handleConnectionUpdate"
v-if=
"configVisible && detail"
></BindConnection>
<!-- 用户事件数据 -->
<ViewGenerateEventData
v-model=
"generateEventVisible"
v-if=
"generateEventVisible"
></ViewGenerateEventData>
</template>
src/modules/trip/template/api.ts
浏览文件 @
5e027871
...
...
@@ -52,7 +52,13 @@ export function ruleQuery(data: { experiment_id: string; filters: string }) {
}
// 保存实验旅程数据规则
export
function
saveRule
(
data
:
{
itinerary_id
:
string
;
data_generate_mode
:
string
;
data_generate_frequency
:
string
;
auto_generate_rule
:
string
;
graph
:
string
})
{
export
function
saveRule
(
data
:
{
itinerary_id
:
string
data_generate_mode
:
string
data_generate_frequency
:
string
auto_generate_rule
:
string
graph
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/v1/backend/experiment-itinerary/save-data-config'
,
data
)
}
...
...
@@ -60,3 +66,13 @@ export function saveRule(data: { itinerary_id: string; data_generate_mode: strin
export
function
updateTriggerStatus
(
data
:
{
itinerary_id
:
string
;
trigger_status
:
0
|
1
})
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/itinerary/trigger'
,
data
)
}
// 获取配置旅程数据规则
export
function
getGenerateDataRule
(
params
:
{
itinerary_id
:
string
})
{
return
httpRequest
.
get
(
'/api/lab/v1/experiment/itinerary/generate-data-config'
,
{
params
})
}
// 保存配置旅程数据规则
export
function
updateGenerateDataRule
(
data
:
{
itinerary_id
:
string
;
config
:
any
})
{
return
httpRequest
.
post
(
'/api/lab/v1/experiment/itinerary/generate-data-config'
,
data
)
}
src/modules/trip/template/components/GenerateRule.vue
0 → 100644
浏览文件 @
5e027871
<
script
setup
lang=
"ts"
>
import
type
{
TripTemplate
}
from
'../types'
import
{
getGenerateDataRule
,
updateGenerateDataRule
}
from
'../api'
import
{
ElMessage
}
from
'element-plus'
const
props
=
defineProps
<
{
data
:
TripTemplate
}
>
()
const
emit
=
defineEmits
<
{
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
}
>
()
const
dataset
:
any
=
reactive
({
events
:
[],
list
:
[]
})
async
function
fetchGenerateDataRule
()
{
const
{
data
}
=
await
getGenerateDataRule
({
itinerary_id
:
props
.
data
.
id
})
data
.
list
=
data
.
list
.
map
((
item
:
any
)
=>
{
return
{
...
item
,
ratio
:
parseFloat
(
item
.
ratio
)
}
})
Object
.
assign
(
dataset
,
data
)
}
onMounted
(()
=>
{
fetchGenerateDataRule
()
})
const
listOptions
=
computed
(()
=>
{
return
{
data
:
dataset
.
list
,
columns
:
[
{
label
:
'连接名称'
,
prop
:
'connection_name'
,
width
:
100
},
{
label
:
'动作类型'
,
prop
:
'action'
,
width
:
100
},
{
label
:
'旅程动作'
,
prop
:
'itinerary'
,
width
:
100
},
{
label
:
'旅程事件'
,
prop
:
'event'
},
{
label
:
'对应用户事件'
,
prop
:
'user_event_id'
,
slots
:
'table-event'
},
{
label
:
'生成数据比例规则'
,
prop
:
'ratio'
,
slots
:
'table-ratio'
,
width
:
140
}
]
}
})
function
isDisabled
(
connectionType
:
string
)
{
if
(
connectionType
===
'15'
)
return
true
return
false
}
function
getConnection
(
connectionType
:
string
)
{
return
dataset
.
events
.
filter
((
item
:
any
)
=>
item
.
connection_type
===
connectionType
)
}
async
function
handleSubmit
()
{
const
config
=
dataset
.
list
.
reduce
((
result
:
any
,
item
:
any
)
=>
{
const
{
ratio
,
user_event_id
}
=
item
result
[
item
.
id
]
=
{
ratio
,
user_event_id
}
return
result
},
{})
await
updateGenerateDataRule
({
itinerary_id
:
props
.
data
.
id
,
config
:
JSON
.
stringify
(
config
)
})
ElMessage
.
success
(
'保存成功'
)
emit
(
'update:modelValue'
,
false
)
}
</
script
>
<
template
>
<el-dialog
title=
"旅程数据规则"
width=
"900"
@
update:modelValue=
"(value) => $emit('update:modelValue', value)"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
table-event=
"
{ row }">
<el-select
v-model=
"row.user_event_id"
:disabled=
"isDisabled(row.connection_type)"
>
<el-option
v-for=
"item in getConnection(row.connection_type)"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
></el-option>
</el-select>
</
template
>
<
template
#
table-ratio=
"{ row }"
>
<div
class=
"table-ratio"
>
<el-input-number
v-model=
"row.ratio"
:controls=
"false"
:max=
"100"
:min=
"0"
:disabled=
"isDisabled(row.connection_type)"
></el-input-number>
%
</div>
</
template
>
</AppList>
<
template
#
footer
>
<el-row
justify=
"center"
>
<el-button
plain
auto-insert-space
@
click=
"$emit('update:modelValue', false)"
>
关闭
</el-button>
<el-button
type=
"primary"
auto-insert-space
@
click=
"handleSubmit"
>
保存
</el-button>
</el-row>
</
template
>
</el-dialog>
</template>
<
style
lang=
"scss"
>
.table-ratio
{
display
:
flex
;
align-items
:
center
;
gap
:
5px
;
.el-input__inner
{
text-align
:
center
;
}
}
</
style
>
src/modules/trip/template/views/Index.vue
浏览文件 @
5e027871
...
...
@@ -9,6 +9,7 @@ import { getNameByValue, tripTemplateTypeList } from '@/utils/dictionary'
const
FormDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/FormDialog.vue'
))
const
ViewDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ViewDialog.vue'
))
const
BindConnection
=
defineAsyncComponent
(()
=>
import
(
'../components/BindConnection.vue'
))
const
GenerateRule
=
defineAsyncComponent
(()
=>
import
(
'../components/GenerateRule.vue'
))
const
statusList
=
useMapStore
().
getMapValuesByKey
(
'system_status'
)
...
...
@@ -53,7 +54,7 @@ const listOptions = computed(() => {
},
{
label
:
'更新人'
,
prop
:
'updated_operator.real_name'
},
{
label
:
'更新时间'
,
prop
:
'updated_time'
},
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
3
0
0
}
{
label
:
'操作'
,
slots
:
'table-x'
,
width
:
3
6
0
}
]
}
})
...
...
@@ -95,6 +96,12 @@ function handleConfig(row: TripTemplate) {
configVisible
=
true
}
}
let
ruleVisible
=
$ref
(
true
)
function
handleRule
(
row
:
TripTemplate
)
{
currentRow
=
row
ruleVisible
=
true
}
</
script
>
<
template
>
...
...
@@ -110,6 +117,7 @@ function handleConfig(row: TripTemplate) {
<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=
"handleUpdate(row)"
>
编辑
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleRule(row)"
>
旅程数据规则
</el-button>
</
template
>
</AppList>
</AppCard>
...
...
@@ -119,4 +127,6 @@ function handleConfig(row: TripTemplate) {
<ViewDialog
v-model=
"viewVisible"
:data=
"currentRow"
v-if=
"viewVisible && currentRow"
></ViewDialog>
<!-- 配置 -->
<BindConnection
v-model=
"configVisible"
:data=
"currentRow"
v-if=
"configVisible && currentRow"
></BindConnection>
<!-- 旅程数据规则 -->
<GenerateRule
v-model=
"ruleVisible"
:data=
"currentRow"
v-if=
"ruleVisible && currentRow"
></GenerateRule>
</template>
src/modules/user/views/Index.vue
浏览文件 @
5e027871
...
...
@@ -12,6 +12,7 @@ const UpdateDialog = defineAsyncComponent(() => import('../components/UpdateDial
const
UploadEventsDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/UploadEventsDialog.vue'
))
const
UploadUserDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/UploadUserDialog.vue'
))
const
ViewProgressDialog
=
defineAsyncComponent
(()
=>
import
(
'../components/ViewProgressDialog.vue'
))
const
ViewGenerateEventData
=
defineAsyncComponent
(()
=>
import
(
'@/components/ViewGenerateEventData.vue'
))
const
router
=
useRouter
()
...
...
@@ -117,7 +118,7 @@ const handleRemove = function (row: { id: string; have_event: boolean }) {
}
}
const
handleRemoves
=
function
(
isAll
?:
boolean
)
{
const
ids
=
multipleSelection
.
map
(
item
=>
item
.
id
).
join
(
','
)
const
ids
=
multipleSelection
.
map
(
(
item
)
=>
item
.
id
).
join
(
','
)
if
(
isAll
)
{
ElMessageBox
.
confirm
(
'确定要删除全部用户数据吗?'
,
'提示'
,
{
confirmButtonText
:
'确认'
,
...
...
@@ -202,6 +203,8 @@ const downloadMember = function (isAll?: boolean) {
window
.
open
(
`/api/lab/v1/experiment/member/download?experiment_id=
${
route
.
query
.
experiment_id
}
&ids=
${
ids
}
`
)
}
}
const
generateEventVisible
=
ref
(
false
)
</
script
>
<
template
>
...
...
@@ -210,12 +213,7 @@ const downloadMember = function (isAll?: boolean) {
<template
#
header-buttons
>
<el-row
justify=
"space-between"
>
<el-space>
<el-button
v-if=
"!userStore.status.status"
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
v-permission=
"'v1-experiment-member-create'"
<el-button
v-if=
"!userStore.status.status"
type=
"primary"
:icon=
"Plus"
@
click=
"handleAdd"
v-permission=
"'v1-experiment-member-create'"
>
新建
</el-button
>
<el-dropdown
v-permission=
"'v1-experiment-member-download'"
>
...
...
@@ -223,9 +221,7 @@ const downloadMember = function (isAll?: boolean) {
<template
#
dropdown
>
<el-dropdown-menu>
<el-dropdown-item
@
click=
"downloadMember(true)"
>
全部用户数据
</el-dropdown-item>
<el-dropdown-item
:disabled=
"!multipleSelection.length"
@
click=
"downloadMember(false)"
>
勾选用户数据
</el-dropdown-item
>
<el-dropdown-item
:disabled=
"!multipleSelection.length"
@
click=
"downloadMember(false)"
>
勾选用户数据
</el-dropdown-item>
</el-dropdown-menu>
</
template
>
</el-dropdown>
...
...
@@ -239,9 +235,7 @@ const downloadMember = function (isAll?: boolean) {
</el-dropdown-menu>
</
template
>
</el-dropdown>
<el-button
type=
"primary"
@
click=
"progressVisible = true"
v-permission=
"'v1-experiment-member-tasks'"
>
数据导入进度
</el-button
>
<el-button
type=
"primary"
@
click=
"progressVisible = true"
v-permission=
"'v1-experiment-member-tasks'"
>
数据导入进度
</el-button>
<!-- <el-button type="danger" plain :icon="Delete" :disabled="!multipleSelection.length" @click="handleRemoves()" v-permission="'v1-experiment-member-delete'">删除</el-button> -->
<!-- v-permission="'v1-experiment-member-delete'" -->
<el-dropdown>
...
...
@@ -249,25 +243,22 @@ const downloadMember = function (isAll?: boolean) {
<
template
#
dropdown
>
<el-dropdown-menu>
<el-dropdown-item
@
click=
"handleRemoves(true)"
>
删除全部用户
</el-dropdown-item>
<el-dropdown-item
:disabled=
"!multipleSelection.length"
@
click=
"handleRemoves(false)"
>
删除勾选用户
</el-dropdown-item
>
<el-dropdown-item
:disabled=
"!multipleSelection.length"
@
click=
"handleRemoves(false)"
>
删除勾选用户
</el-dropdown-item>
</el-dropdown-menu>
</
template
>
</el-dropdown>
</el-space>
<router-link
to=
"/analyze/user"
><el-button
type=
"primary"
>
用户分析
</el-button></router-link>
<el-space>
<router-link
to=
"/analyze/user"
><el-button
type=
"primary"
>
用户分析
</el-button></router-link>
<el-button
type=
"primary"
@
click=
"generateEventVisible = true"
>
用户事件数据
</el-button>
</el-space>
</el-row>
</template>
<
template
#
table-x=
"{ row }"
>
<el-button
type=
"primary"
plain
@
click=
"handleImage(row)"
>
画像
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleView(row)"
>
查看
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleEdit(row)"
v-permission=
"'v1-experiment-member-update'"
>
编辑
</el-button
>
<el-button
type=
"primary"
plain
@
click=
"handleRemove(row)"
v-permission=
"'v1-experiment-member-delete'"
>
删除
</el-button
>
<el-button
type=
"primary"
plain
@
click=
"handleEdit(row)"
v-permission=
"'v1-experiment-member-update'"
>
编辑
</el-button>
<el-button
type=
"primary"
plain
@
click=
"handleRemove(row)"
v-permission=
"'v1-experiment-member-delete'"
>
删除
</el-button>
<el-button
type=
"primary"
plain
@
click=
"goPage(row)"
>
事件
</el-button>
</
template
>
</AppList>
...
...
@@ -280,4 +271,6 @@ const downloadMember = function (isAll?: boolean) {
<UpdateDialog
v-if=
"updateVisible"
:data=
"currentRow"
v-model=
"updateVisible"
@
update=
"handleRefresh"
></UpdateDialog>
<!-- 查看上传 -->
<ViewProgressDialog
v-if=
"progressVisible"
v-model=
"progressVisible"
></ViewProgressDialog>
<!-- 用户事件数据 -->
<ViewGenerateEventData
v-model=
"generateEventVisible"
v-if=
"generateEventVisible"
></ViewGenerateEventData>
</template>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论