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

chore: update

上级 9e7cbfb7
...@@ -87,3 +87,7 @@ textarea:focus { ...@@ -87,3 +87,7 @@ textarea:focus {
.info .el-form-item { .info .el-form-item {
margin-bottom: 0; margin-bottom: 0;
} }
.info tr:last-child td {
padding-bottom: 0 !important;
}
...@@ -83,12 +83,7 @@ const onDrop = (event: DragEvent) => { ...@@ -83,12 +83,7 @@ const onDrop = (event: DragEvent) => {
<slot name="left-panel"> </slot> <slot name="left-panel"> </slot>
<el-card shadow="never" class="flow-main" @drop="onDrop"> <el-card shadow="never" class="flow-main" @drop="onDrop">
<slot name="header"> </slot> <slot name="header"> </slot>
<VueFlow <VueFlow :zoom-on-scroll="false" :prevent-scrolling="false" @dragover="onDragOver" v-bind="$attrs">
fit-view-on-init
:zoom-on-scroll="false"
:prevent-scrolling="false"
@dragover="onDragOver"
v-bind="$attrs">
<template #node-custom="node"> <template #node-custom="node">
<CustomNode :node="node" /> <CustomNode :node="node" />
</template> </template>
......
import httpRequest from '@/utils/axios' import httpRequest from '@/utils/axios'
// 获取实验详情
export function getExperiment() {
return httpRequest.get('/api/lab/v1/student/experiment/detail')
}
// 学生获取旅程 // 学生获取旅程
export function getStudentTrip() { export function getStudentTrip() {
return httpRequest.get('/api/lab/v1/experiment/itinerary/student-get-itinerary') return httpRequest.get('/api/lab/v1/experiment/itinerary/student-get-itinerary')
} }
// 更新旅程
export function updateTrip(data: { itinerary_id: string; graph: string; status: number }) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/student-save-itinerary', data)
}
// 旅程绑定连接
export function bindTripConnections(data: { itinerary_id: string; connections_id: string }) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/student-bind-connections', data)
}
// 获取旅程模板demo
export function getTripTemplateDemo(params: { itinerary_id?: string }) {
return httpRequest.get('/api/lab/v1/experiment/itinerary/get-itinerary-demo', { params })
}
<script setup lang="ts">
import type { Trip } from '../types'
import { ElMessage } from 'element-plus'
import { bindTripConnections } from '../api'
import type { ConnectionType } from '@/composables/useAllData'
import { useConnection } from '@/composables/useAllData'
import ConnectionIcon from '@/components/ConnectionIcon.vue'
const props = defineProps<{
data: Trip
}>()
const emit = defineEmits<{
(e: 'update', value: string[]): void
(e: 'update:modelValue', visible: boolean): void
}>()
const { connectionList } = useConnection()
const multipleSelection = ref<string[]>([])
function toggleSelection(data: ConnectionType) {
multipleSelection.value.includes(data.id)
? multipleSelection.value.filter(id => id !== data.id)
: multipleSelection.value.push(data.id)
}
function isActive(data: ConnectionType) {
return multipleSelection.value.includes(data.id)
}
// 保存
function handleSave() {
bindTripConnections({ itinerary_id: props.data.id, connections_id: multipleSelection.value.join(',') }).then(() => {
ElMessage({ message: '保存成功', type: 'success' })
emit('update', multipleSelection.value)
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 @change="toggleSelection(item)" :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>
export interface Trip {
id: string
experiment_id: string
itinerary_id: string
student_id: string
connect_ids: string[]
graph: string
score: string
status: string
commit_time: string
comment_sso_id: string
comment_time: string
comment_status: string
comment: string
created_time: string
updated_time: string
status_name: string
comment_status_name: string
course_id: string
course_name: string
experiment_name: string
experiment_itinerary_type: string
experiment_itinerary_type_name: string
}
<script setup lang="ts"> <script setup lang="ts">
import type { Trip } from '../types'
import TripFlow from '@/components/flow/Index.vue' import TripFlow from '@/components/flow/Index.vue'
import { getExperiment, getStudentTrip } from '../api' import TripFlowSidebar from '@/components/flow/Sidebar.vue'
import { ElMessage } from 'element-plus'
import { getStudentTrip, getTripTemplateDemo, updateTrip } from '../api'
const experiment = ref<any>() const BindConnection = defineAsyncComponent(() => import('../components/BindConnection.vue'))
function fetchExperiment() {
getExperiment().then(res => {
experiment.value = res.data.detail
})
}
onMounted(() => fetchExperiment())
const detail = ref<Trip>()
const elements = ref([])
const connectionIds = computed(() => {
return detail.value?.connect_ids || []
})
// 是否是自由旅程
const isFree = computed(() => {
return detail.value?.experiment_itinerary_type === '1'
})
// 获取旅程信息 // 获取旅程信息
const detail = ref<any>() async function fetchInfo() {
function fetchInfo() { const res = await getStudentTrip()
getStudentTrip().then(res => { detail.value = res.data
detail.value = res.data.detail try {
}) elements.value = res.data.graph ? JSON.parse(res.data.graph) : []
} catch (error) {
console.log(error)
}
} }
onMounted(() => fetchInfo()) onMounted(async () => {
await fetchInfo()
fetchDemo()
})
const elements = ref([ // 获取模板配置数据
{ async function fetchDemo() {
id: '1', if (!detail.value) return
type: 'custom', if (isFree.value || detail.value.graph) return
label: '实时触发', const res = await getTripTemplateDemo({ itinerary_id: detail.value.itinerary_id })
position: { x: 0, y: 0 }, try {
data: { name: '实时触发', type: '触发条件', score: 10, componentName: 'TriggeringConditions6' } elements.value = res.data.graph ? JSON.parse(res.data.graph) : []
} catch (error) {
console.log(error)
} }
]) }
watchEffect(() => {
console.log(elements)
})
// 保存 // 保存
function handleSubmit() {} function handleSubmit() {
if (!detail.value) return
const params = { itinerary_id: detail.value.itinerary_id, graph: JSON.stringify(elements.value), status: 1 }
updateTrip(params).then(() => {
ElMessage.success('保存成功')
})
}
// 配置
let configVisible = $ref(false)
function handleConfig() {
configVisible = true
}
function handleConnectionUpdate(value: string[]) {
if (!detail.value) return
detail.value.connect_ids = value
}
</script> </script>
<template> <template>
<AppCard title="自由旅程"> <AppCard :title="detail?.experiment_itinerary_type_name">
<el-card shadow="never" style="margin-bottom: 20px" v-if="experiment"> <el-card shadow="never" style="margin-bottom: 20px" v-if="detail">
<el-descriptions label-suffix=":"> <el-descriptions class="info">
<el-descriptions-item label="课程名称:">{{ experiment.course.name }}</el-descriptions-item> <el-descriptions-item label="课程名称:">{{ detail.course_name }}</el-descriptions-item>
<el-descriptions-item label="实验名称:">{{ experiment.name }}</el-descriptions-item> <el-descriptions-item label="实验名称:">{{ detail.experiment_name }}</el-descriptions-item>
<el-descriptions-item label="旅程类型:">自由旅程</el-descriptions-item> <el-descriptions-item label="旅程类型:">{{ detail.experiment_itinerary_type_name }}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
<TripFlow v-model="elements" action="edit" role="student" style="height: 80vh"> <TripFlow v-model="elements" action="edit" role="student">
<template #left-panel v-if="isFree">
<TripFlowSidebar :connectionIds="connectionIds" />
</template>
<template #header>
<el-row align="middle">
<el-button type="primary" size="large" @click="handleConfig" style="margin-right: 20px" v-if="isFree"
>配置连接</el-button
>
<el-alert center style="flex: 1">
<p style="text-align: center">
<template v-if="isFree">
用户旅程的基本组成:触发条件+营销动作+条件分支<br />
您可以从左侧组件区域选择的对应的触发条件、营销动作和条件分支,拖拽到右侧的画布里面,进行编排组合个性化的用户旅程。
</template>
<template v-else>请给本用户旅程的每一个节点进行详细配置,确保每一个节点能够顺利执行。</template>
</p>
</el-alert>
</el-row>
</template>
<template #footer> <template #footer>
<el-row justify="center"> <el-row justify="center">
<el-button type="primary" auto-insert-space @click="handleSubmit">保存</el-button> <el-button type="primary" auto-insert-space @click="handleSubmit">保存</el-button>
...@@ -53,4 +99,11 @@ function handleSubmit() {} ...@@ -53,4 +99,11 @@ function handleSubmit() {}
</template> </template>
</TripFlow> </TripFlow>
</AppCard> </AppCard>
<!-- 配置连接 -->
<BindConnection
v-model="configVisible"
:data="detail"
@update="handleConnectionUpdate"
v-if="configVisible && detail"></BindConnection>
</template> </template>
...@@ -11,7 +11,7 @@ const props = defineProps<{ ...@@ -11,7 +11,7 @@ const props = defineProps<{
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update', value: ConnectionType[]): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
...@@ -40,7 +40,7 @@ function handleSave() { ...@@ -40,7 +40,7 @@ function handleSave() {
const ids = multipleSelection.value.map(item => item.id) const ids = multipleSelection.value.map(item => item.id)
bindTripConnections({ itinerary_id: props.data.id, connection_ids: ids }).then(() => { bindTripConnections({ itinerary_id: props.data.id, connection_ids: ids }).then(() => {
ElMessage({ message: '保存成功', type: 'success' }) ElMessage({ message: '保存成功', type: 'success' })
emit('update') emit('update', multipleSelection.value)
emit('update:modelValue', false) emit('update:modelValue', false)
}) })
} }
...@@ -54,8 +54,7 @@ function handleSave() { ...@@ -54,8 +54,7 @@ function handleSave() {
v-for="item in connectionList" v-for="item in connectionList"
:key="item.id" :key="item.id"
:class="{ 'is-active': isActive(item) }" :class="{ 'is-active': isActive(item) }"
@click="toggleSelection(item)" @click="toggleSelection(item)">
>
<el-checkbox @change="toggleSelection(item)" :model-value="isActive(item)" /> <el-checkbox @change="toggleSelection(item)" :model-value="isActive(item)" />
<div class="connection-item__icon"><ConnectionIcon :name="item.type + ''" /></div> <div class="connection-item__icon"><ConnectionIcon :name="item.type + ''" /></div>
<p>{{ item.name }}</p> <p>{{ item.name }}</p>
......
...@@ -26,7 +26,7 @@ export default defineConfig(({ mode }) => ({ ...@@ -26,7 +26,7 @@ export default defineConfig(({ mode }) => ({
cert: fs.readFileSync(path.join(__dirname, './https/ezijing.com.pem')) cert: fs.readFileSync(path.join(__dirname, './https/ezijing.com.pem'))
}, },
proxy: { proxy: {
'/api': 'https://saas-lab.ezijing.com' '/api': 'https://saas-dml.ezijing.com'
} }
}, },
resolve: { resolve: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论