提交 2ea5d6a3 authored 作者: lihuihui's avatar lihuihui

元数据,链接管理开发

上级 e89409f6
...@@ -113,7 +113,6 @@ ...@@ -113,7 +113,6 @@
"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,
...@@ -197,7 +196,6 @@ ...@@ -197,7 +196,6 @@
"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,
......
...@@ -114,7 +114,6 @@ declare global { ...@@ -114,7 +114,6 @@ 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']
...@@ -198,7 +197,6 @@ declare global { ...@@ -198,7 +197,6 @@ 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']
......
...@@ -5,6 +5,7 @@ const styleHeight = computed(() => { ...@@ -5,6 +5,7 @@ const styleHeight = computed(() => {
}) })
</script> </script>
<template> <template>
<div class="app-card"> <div class="app-card">
<div class="app-card-hd"> <div class="app-card-hd">
......
import httpRequest from '@/utils/axios'
// 链接列表
export function getConnectionList(params: { created_operator?: string; type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/connection/list', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 创建链接
export function createConnection(data: { type: string; config_attributes: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/connection/create', { experiment_id: '7025368348925886464', ...data })
}
// 链接详情
export function getConnectionDetails(params: { id?: string; }) {
return httpRequest.get('/api/experiment/v1/experiment/connection/view', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 更新链接
export function updateConnection(data: { id: string; config_attributes: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/connection/update', { experiment_id: '7025368348925886464', ...data })
}
// 删除链接
export function deleteConnection(data: { id: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/connection/delete', { experiment_id: '7025368348925886464', ...data })
}
\ No newline at end of file
<script setup lang="ts">
import StepOne from '../components/StepOne.vue'
import StepTwo from '../components/StepTwo.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { createConnection, updateConnection } from '../api'
import type { DetailsProp } from '../types'
const props = defineProps<{ data: DetailsProp | undefined }>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
// 请求参数
const params = $ref({ type: '', config_attributes: '' })
// 提交
function handleSubmit() {
if (props.data?.id) {
const updateParams = { id: props.data?.id, config_attributes: JSON.stringify(stepTwo.value.formItem) }
updateConnection(updateParams).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '保修改成功', type: 'success' })
})
} else {
createConnection(params).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '保存成功', type: 'success' })
})
}
}
// tabs
let activeName = $ref(props.data?.id ? 2 : 1)
// 第三步成功弹窗
const openMsg = () => {
ElMessageBox.alert(`成功链接${stepOneValue.name}`, '提示', {
// if you want to disable its autofocus
// autofocus: false,
confirmButtonText: 'OK'
})
}
// 第一步的值
const stepOneValue = $ref({
type: props.data?.type || '',
name: props.data?.type_name || '',
value: props.data?.config_attributes
})
const stepOne = ref()
const handleStepOneNext = function () {
const data = stepOne.value.getData()
params.type = data.name
stepOneValue.type = data.name
stepOneValue.name = data.label
activeName++
}
// 第二步
const stepTwo = ref()
const handleStepTwoNext = function () {
const data = stepTwo.value.formItem
const isData = data.find((item: { label: string; value: string; prop: string }) => item.value === '')
if (!isData) {
activeName++
params.config_attributes = JSON.stringify(data)
} else {
ElMessage('请填写完整')
}
}
</script>
<template>
<el-dialog
class="connect-form"
title="新建链接"
:close-on-click-modal="false"
width="800px"
@update:modelValue="$emit('update:modelValue')"
>
<el-tabs v-model="activeName" class="demo-tabs">
<!-- 第一步 -->
<el-tab-pane disabled label="选择链接类型" :name="1" v-if="!props.data?.id">
<StepOne ref="stepOne"></StepOne>
</el-tab-pane>
<!-- 第二步 -->
<el-tab-pane disabled label="配置链接信息" :name="2">
<StepTwo ref="stepTwo" :data="stepOneValue"></StepTwo>
</el-tab-pane>
<el-tab-pane disabled label="测试链接" :name="3">
<el-button type="primary" @click="openMsg">测试链接</el-button>
</el-tab-pane>
</el-tabs>
<div class="button-flex">
<template v-if="props.data?.id">
<el-button type="primary" @click="activeName--" v-if="activeName === 3">上一步</el-button>
</template>
<el-button v-else type="primary" @click="activeName--" v-if="activeName === 2 || activeName === 3"
>上一步</el-button
>
<el-button type="primary" @click="handleStepOneNext" v-if="activeName === 1">下一步</el-button>
<el-button type="primary" @click="handleStepTwoNext" v-if="activeName === 2">下一步</el-button>
<el-button type="primary" v-if="activeName === 3" @click="handleSubmit">保存</el-button>
</div>
</el-dialog>
</template>
<style lang="scss">
.connect-form {
.el-dialog__body {
padding-top: 10px;
}
}
.button-flex {
display: flex;
justify-content: center;
}
</style>
<script setup lang="ts">
withDefaults(defineProps<{ name: string; color?: string; w?: string; h?: string }>(), {
color: '#000000',
w: '30',
h: '30'
})
</script>
<template>
<div>
<svg
v-if="name === '1'"
t="1675654500635"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10798"
:width="w"
:height="h"
>
<path
d="M664.250054 368.541681c10.015098 0 19.892049 0.732687 29.67281 1.795902-26.647917-122.810047-159.358451-214.077703-310.826188-214.077703-169.353083 0-308.085774 114.232694-308.085774 259.274068 0 83.708494 46.165436 152.460344 123.281791 205.78483l-30.80868 91.730191 107.688651-53.455469c38.558178 7.53665 69.459978 15.308661 107.924012 15.308661 9.66308 0 19.230993-0.470721 28.752858-1.225921-6.025227-20.36584-9.521864-41.723264-9.521864-63.862493C402.328693 476.632491 517.908058 368.541681 664.250054 368.541681zM498.62897 285.87389c23.200398 0 38.557154 15.120372 38.557154 38.061874 0 22.846334-15.356756 38.156018-38.557154 38.156018-23.107277 0-46.260603-15.309684-46.260603-38.156018C452.368366 300.994262 475.522716 285.87389 498.62897 285.87389zM283.016307 362.090758c-23.107277 0-46.402843-15.309684-46.402843-38.156018 0-22.941502 23.295566-38.061874 46.402843-38.061874 23.081695 0 38.46301 15.120372 38.46301 38.061874C321.479317 346.782098 306.098002 362.090758 283.016307 362.090758zM945.448458 606.151333c0-121.888048-123.258255-221.236753-261.683954-221.236753-146.57838 0-262.015505 99.348706-262.015505 221.236753 0 122.06508 115.437126 221.200938 262.015505 221.200938 30.66644 0 61.617359-7.609305 92.423993-15.262612l84.513836 45.786813-23.178909-76.17082C899.379213 735.776599 945.448458 674.90216 945.448458 606.151333zM598.803483 567.994292c-15.332197 0-30.807656-15.096836-30.807656-30.501688 0-15.190981 15.47546-30.477129 30.807656-30.477129 23.295566 0 38.558178 15.286148 38.558178 30.477129C637.361661 552.897456 622.099049 567.994292 598.803483 567.994292zM768.25071 567.994292c-15.213493 0-30.594809-15.096836-30.594809-30.501688 0-15.190981 15.381315-30.477129 30.594809-30.477129 23.107277 0 38.558178 15.286148 38.558178 30.477129C806.808888 552.897456 791.357987 567.994292 768.25071 567.994292z"
:fill="color"
p-id="10799"
></path>
</svg>
<svg
v-if="name === '2'"
t="1675654004777"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="8908"
:width="w"
:height="h"
>
<path
d="M903.282484 382.828702c-2.999866 10.899512-6.899691 21.499038-11.699476 31.698581h0.099995l-0.599973 1.299942c-34.098474 76.596571-123.194485 226.989839-123.194485 226.989839l-0.399982-0.999955-25.998836 47.597869h125.394386L627.294839 1024l54.397565-227.589812h-98.795578l34.298465-150.493263c-27.798756 6.999687-60.497292 16.699252-99.395551 29.798666 0 0-52.49765 32.298554-151.393222-62.197216 0 0-66.697014-61.597243-27.998747-77.096548 16.399266-6.499709 79.796428-14.799337 129.694194-21.999015 67.296987-9.59957 108.79513-14.699342 108.79513-14.699342s-207.690703 3.299852-256.988496-4.899781c-49.297793-8.099637-111.695-94.49577-125.0944-170.392372 0 0-20.599078-41.698133 44.198021-21.999016 64.897095 19.699118 333.385076 76.796562 333.385076 76.796563S223.312923 266.933891 200.113962 239.535117 131.717024 89.741823 137.616759 14.645184c0 0 2.599884-18.799158 20.899065-13.799382 0 0 258.188442 123.994449 434.680541 191.691419C769.688464 260.434182 923.081598 295.032633 903.282484 382.828702z"
:fill="color"
p-id="8909"
></path>
</svg>
<svg
v-if="name === '3'"
t="1675654843770"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="14477"
:width="w"
:height="h"
>
<path
d="M927.100379 675.459361c-1.321995-6.607974-9.439963-4.908981-14.915942-4.90898-32.096875 0-64.193749-2.265991-95.913626 0.377998-61.739759 5.09798-108.185577-26.243897-151.799407-62.683755-24.545904-20.39092-45.879821-44.558826-71.369721-64.00575-42.292835-32.474873-85.717665-62.305757-141.793446-64.759747-15.29294-0.566998-33.22987-1.321995-38.516849-21.524916a124.612513 124.612513 0 0 1-4.530983-28.697888c-0.754997-57.586775-4.530982-114.794552-4.153984-172.380326a397.890446 397.890446 0 0 0-20.012921-138.584459 195.037238 195.037238 0 0 0-49.089809-80.809684C298.563834 4.064984 254.571006-2.353991 207.748188 0.666997a41.631837 41.631837 0 0 0-33.04087 20.389921c-13.216948 17.181933 15.669939 47.768813-36.439858 47.390815-5.475979 0-33.796868-1.320995-41.537838 22.089913-5.285979 15.859938 82.697677 10.006961 100.256609 16.237937a11.913953 11.913953 0 0 0 5.09798-0.376999 94.591631 94.591631 0 0 0 67.780735 30.963879 29.132886 29.132886 0 0 1 28.509888 24.166906 411.692392 411.692392 0 0 1 11.705955 71.179722 447.471252 447.471252 0 0 1-10.19496 155.199394 302.524818 302.524818 0 0 1-33.985868 65.326745 268.70895 268.70895 0 0 0-36.439857 164.828356 191.97925 191.97925 0 0 0 47.201815 108.563576c21.901914 24.355905 52.110796 39.837844 72.124719 65.893742 26.621896 34.928864 52.487795 70.801723 81.186682 104.031594a155.879391 155.879391 0 0 1-1.509994 83.263675 29.887883 29.887883 0 0 1-26.244897 23.411908c-16.047937 1.321995-30.019883 11.139956-46.257819 13.216949 23.789907 2.264991 47.579814 1.320995 71.179721 2.45399 21.524916 1.132996 42.859833-11.705954 64.572748-0.943996a5.928977 5.928977 0 0 0 2.264991-0.754997c-4.530982-3.775985-8.306968-7.551971-12.837949-10.761958a54.319788 54.319788 0 0 1-22.656912-60.039766c2.45399-11.139956 3.586986-22.657911 5.09698-33.985867a419.150363 419.150363 0 0 0 142.549443 17.747931 200.135218 200.135218 0 0 1 7.173972 42.292834 31.359878 31.359878 0 0 1-22.655911 34.362866c-14.915942 4.908981-29.831883 10.005961-45.502822 15.103941a16.218937 16.218937 0 0 0 4.90998 2.076992c20.012922-0.188999 40.025844-0.754997 60.039766-0.565998a35.72186 35.72186 0 0 0 31.907875-12.64995c4.719982-6.608974 9.817962-6.419975 14.726943 0.565997a29.415885 29.415885 0 0 0 30.775879 9.629963 35.060863 35.060863 0 0 0-12.461951-16.615935 65.534744 65.534744 0 0 1-19.635923-27.565893c-3.963985-20.201921-8.117968-40.403842-12.271952-60.795762a92.363639 92.363639 0 0 0 56.830778-30.77488 357.070605 357.070605 0 0 0 59.473767-68.725731 127.500502 127.500502 0 0 1 44.369827-41.914837 228.248108 228.248108 0 0 0 68.347733-61.36176 69.593728 69.593728 0 0 1 42.669833-29.831883c4.531982-0.565998 13.782946 0 12.272953-7.92997zM239.090066 43.52483a9.892961 9.892961 0 0 1-9.062965-12.083953 9.779962 9.779962 0 0 1 9.251964-10.383959 10.081961 10.081961 0 0 1 10.38396 11.327955 10.34696 10.34696 0 0 1-10.572959 11.139957z"
:fill="color"
p-id="14478"
></path>
</svg>
<svg
v-if="name === '4'"
t="1675654964339"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="16272"
:width="w"
:height="h"
>
<path
d="M559.22 180.986667a21.333333 21.333333 0 0 1-19.14-11.893334L512 112.206667l-28.08 56.886666a21.333333 21.333333 0 0 1-38.26-18.88L492.866667 54.56a21.333333 21.333333 0 0 1 38.266666 0l47.206667 95.653333a21.333333 21.333333 0 0 1-19.12 30.773334zM784.233333 377.333333a21.333333 21.333333 0 0 0-18.04-24.18l-94.46-13.706666-42.246666-85.593334a21.333333 21.333333 0 1 0-38.26 18.88l47.206666 95.653334a21.333333 21.333333 0 0 0 16.06 11.666666l105.56 15.333334a21.3 21.3 0 0 0 24.18-18.053334z m137.333334 118.62l76.386666-74.453333a21.333333 21.333333 0 0 0-11.826666-36.386667l-105.553334-15.333333a21.333333 21.333333 0 1 0-6.14 42.22l62.786667 9.126667-45.433333 44.28a21.333333 21.333333 0 0 0 29.773333 30.593333z m-152.393334 266a21.333333 21.333333 0 0 0 17.42-24.666666l-16.14-94.073334L838.8 576.666667a21.333333 21.333333 0 1 0-29.78-30.553334L732.666667 620.546667a21.333333 21.333333 0 0 0-6.14 18.886666l18 105.126667a21.333333 21.333333 0 0 0 21 17.733333 21.066667 21.066667 0 0 0 3.64-0.293333z m46.5 215.28a21.333333 21.333333 0 0 0 8.486667-20.866666l-18-105.133334a21.333333 21.333333 0 1 0-42.046667 7.213334l10.72 62.526666-56.166666-29.493333a21.333333 21.333333 0 0 0-19.853334 37.766667l94.413334 49.633333a21.333333 21.333333 0 0 0 22.466666-1.62zM625.333333 866.506667a21.333333 21.333333 0 0 0-8.96-28.806667l-94.413333-49.64a21.333333 21.333333 0 0 0-19.853333 0l-94.413334 49.64a21.333333 21.333333 0 1 0 19.853334 37.766667L512 831.046667l84.486667 44.42a21.333333 21.333333 0 0 0 28.846666-8.96z m-394.533333 112.373333l94.413333-49.633333a21.333333 21.333333 0 0 0-19.88-37.766667l-56.153333 29.52 10.72-62.526667a21.333333 21.333333 0 1 0-42.046667-7.213333l-18.033333 105.133333a21.333333 21.333333 0 0 0 30.953333 22.486667z m48.666667-234.32l18.033333-105.126667a21.333333 21.333333 0 0 0-6.166667-18.886666L214.98 546.093333A21.333333 21.333333 0 0 0 185.2 576.666667l68.353333 66.626666L237.413333 737.333333a21.333333 21.333333 0 0 0 17.42 24.666667 21.066667 21.066667 0 0 0 3.633334 0.313333 21.333333 21.333333 0 0 0 21-17.753333zM132.606667 495.586667a21.333333 21.333333 0 0 0-0.386667-30.166667l-45.433333-44.28L149.573333 412a21.333333 21.333333 0 0 0-6.14-42.22l-105.553333 15.333333a21.333333 21.333333 0 0 0-11.826667 36.386667L102.433333 496a21.333333 21.333333 0 0 0 30.173334-0.386667z m131.333333-100.193334l105.56-15.333333a21.333333 21.333333 0 0 0 16.06-11.666667l47.213333-95.66a21.333333 21.333333 0 1 0-38.26-18.88L352.266667 339.446667l-94.453334 13.726666a21.333333 21.333333 0 1 0 6.133334 42.22z"
:fill="color"
p-id="16273"
></path>
</svg>
<svg
v-if="name === '5'"
t="1675655043899"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="17225"
:width="w"
:height="h"
>
<path
d="M832 192v640H192V192h640m32-64H160c-17.6 0-32 14.4-32 32v704c0 17.6 14.4 32 32 32h704c17.6 0 32-14.4 32-32V160c0-17.6-14.4-32-32-32zM768 640H576v64h192v-64zM512 512H256v192h256V512z m256 0H576v64h192v-64z m0-192H256v128h512V320z"
:fill="color"
p-id="17226"
></path>
</svg>
<svg
v-if="name === '6'"
t="1675650497733"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="8488"
:width="w"
:height="h"
>
<path
d="M937.4 423.9c-84 0-165.7-27.3-232.9-77.8v352.3c0 179.9-138.6 325.6-309.6 325.6S85.3 878.3 85.3 698.4c0-179.9 138.6-325.6 309.6-325.6 17.1 0 33.7 1.5 49.9 4.3v186.6c-15.5-6.1-32-9.2-48.6-9.2-76.3 0-138.2 65-138.2 145.3 0 80.2 61.9 145.3 138.2 145.3 76.2 0 138.1-65.1 138.1-145.3V0H707c0 134.5 103.7 243.5 231.6 243.5v180.3l-1.2 0.1"
:fill="color"
p-id="8489"
></path>
</svg>
<svg
v-if="name === '7'"
t="1675655112200"
class="icon"
viewBox="0 0 1138 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="18176"
:width="w"
:height="h"
>
<path
d="M914.432 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM656.384 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM522.24 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM359.424 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM778.24 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM778.24 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z"
:fill="color"
p-id="18177"
></path>
</svg>
<svg
v-if="name === '8'"
t="1675654563546"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="12785"
:width="w"
:height="h"
>
<path
d="M288 64l-128 0C106.88 64 64 106.88 64 160l0 512C64 725.12 106.88 768 160 768l128 0C341.12 768 384 810.88 384 864 384 881.92 398.08 896 416 896S448 881.92 448 864l0-640C448 135.68 376.32 64 288 64zM800 64l-128 0C583.68 64 512 135.68 512 224l0 640C512 881.92 526.08 896 544 896 561.92 896 576 881.92 576 864c0-53.12 42.88-96 96-96l128 0c53.12 0 96-42.88 96-96l0-512C896 106.88 853.12 64 800 64z"
:fill="color"
p-id="12786"
></path>
</svg>
<svg
v-if="name === '9'"
t="1675655183921"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="19990"
:width="w"
:height="h"
>
<path
d="M149.6 171.8h691.9c47.2 0 85.9 37.7 86.5 83.9L495.7 493 63.5 256c0.4-46.4 38.8-84.2 86.1-84.2z m-86.1 175l-0.4 419.6c0 46.7 38.9 84.9 86.5 84.9h691.9c47.6 0 86.5-38.2 86.5-84.9V346.6L505.9 572.8c-6.5 3.5-14.3 3.5-20.7 0l-421.7-226z"
:fill="color"
p-id="19991"
></path>
</svg>
<svg
v-if="name === '10'"
t="1675655232589"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="20965"
:width="w"
:height="h"
>
<path
d="M850.727 116.266H171.593c-72.728 0-108.108 35.866-108.108 107.608v430.43c0 71.746 33.193 105.653 104.108 105.653h104.112l-12.808 109.564a35.679 35.679 0 0 0 19.029 31.562 35.753 35.753 0 0 0 17.005 4.307c6.988 0 13.982-2.014 19.962-6.028L521.57 759.957h333.156c72.081 0 104.109-33.906 104.109-105.653v-430.43c0-71.742-36.033-107.608-108.108-107.608zM303.159 490.172c-28.658 0-51.949-23.3-51.949-51.873 0-28.57 23.292-51.968 51.949-51.968 28.655 0 51.95 23.304 51.95 51.968-0.005 28.668-23.392 51.873-51.95 51.873z m207.887 0c-28.809 0-52.214-23.3-52.214-51.873 0-28.57 23.41-51.968 52.214-51.968 28.806 0 52.211 23.304 52.211 51.968 0.001 28.668-23.507 51.873-52.21 51.873z m208.21 0c-28.81 0-52.133-23.3-52.133-51.873 0-28.57 23.323-51.968 52.132-51.968 28.797 0 52.207 23.304 52.207 51.968 0 28.668-23.405 51.873-52.207 51.873z m0 0"
:fill="color"
p-id="20966"
></path>
</svg>
<svg
v-if="name === '11'"
t="1675660021839"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="24527"
:width="w"
:height="h"
>
<path
d="M512 0C229.2 0 0 229.2 0 512s229.2 512 512 512 512-229.2 512-512S794.8 0 512 0z m-32 769V353c0-17.7 14.3-32 32-32s32 14.3 32 32v416c0 8.8-3.6 16.8-9.4 22.6-5.8 5.8-13.8 9.4-22.6 9.4-17.7 0-32-14.3-32-32z m64-543.5c0 8.8-3.6 16.8-9.4 22.6-5.8 5.8-13.8 9.4-22.6 9.4-17.7 0-32-14.3-32-32v-1c0-17.7 14.3-32 32-32s32 14.3 32 32v1z"
:fill="color"
p-id="24528"
></path>
</svg>
<svg
v-if="name === '12'"
t="1675659896272"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="21924"
:width="w"
:height="h"
>
<path
d="M911.275224 233.685939 825.637477 319.323686 704.59016 198.276368 790.227906 112.638622C816.453389 86.413139 859.427341 86.80945 886.152521 113.551861L910.379215 137.761325C937.104395 164.503736 937.500707 207.460456 911.275224 233.685939ZM293.012048 609.888941 414.059366 730.919028 232.479774 791.468533 293.012048 609.888941ZM801.393552 343.567611 438.28606 706.692334 317.238743 585.645016 680.363465 222.520293 801.393552 343.567611ZM179.666958 189.953826C151.166992 189.953826 127.974154 213.146665 127.974154 241.646631L127.974154 844.798277C127.974154 873.298243 151.166992 896.491082 179.666958 896.491082L782.818604 896.491082C811.31857 896.491082 834.511409 873.298243 834.511409 844.798277L834.511409 360.540082 868.973279 326.078212 868.973279 844.798277C868.973279 892.303964 830.324292 930.952951 782.818604 930.952951L179.666958 930.952951C132.161271 930.952951 93.512284 892.303964 93.512284 844.798277L93.512284 241.646631C93.512284 194.140944 132.161271 155.491957 179.666958 155.491957L698.387023 155.491957 663.925153 189.953826 179.666958 189.953826Z"
:fill="color"
p-id="21925"
></path>
</svg>
</div>
</template>
<style lang="scss"></style>
<script setup lang="ts"> <script setup lang="ts">
import { Delete, ElemeFilled } from '@element-plus/icons-vue' import { Delete, Edit } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import Icon from '../components/Icon.vue'
import { deleteConnection } from '../api'
const emits = defineEmits<{ const props = defineProps<{ data: { id: string; type_name: string; type: string } }>()
(e: 'update'): void
}>() const router = useRouter()
const emits = defineEmits(['update', 'edit'])
// 删除 // 删除
function handleRemove() { function handleRemove() {
ElMessageBox.confirm('确定要删除该连接吗?', '提示').then(() => { ElMessageBox.confirm('确定要删除该连接吗?', '提示').then(() => {
emits('update') deleteConnection({ id: props.data?.id }).then(res => {
ElMessage({ message: '删除成功', type: 'success' })
emits('update')
})
}) })
} }
// 去查看
const routerView = function () {
router.push({ path: '/connect/view', query: { id: props.data.id } })
}
const edit = function () {
emits('edit', props.data?.id)
}
</script> </script>
<template> <template>
<div class="connect-item"> <div class="connect-item">
<div class="connect-item__edit">
<el-icon @click="edit"><Edit /></el-icon>
</div>
<div class="connect-item__remove" @click="handleRemove"> <div class="connect-item__remove" @click="handleRemove">
<el-icon><Delete /></el-icon> <el-icon><Delete /></el-icon>
</div> </div>
<div class="connect-item__icon"> <div @click="routerView" style="display: flex; width: 100%; flex-direction: column; align-items: center">
<el-icon><ElemeFilled /></el-icon> <div class="connect-item__icon">
<Icon class="svg" :name="data?.type"></Icon>
</div>
<p>{{ data?.type_name }}</p>
</div> </div>
<p>连接名称</p>
</div> </div>
</template> </template>
...@@ -42,6 +62,9 @@ function handleRemove() { ...@@ -42,6 +62,9 @@ function handleRemove() {
.connect-item__remove { .connect-item__remove {
display: block; display: block;
} }
.connect-item__edit {
display: block;
}
} }
} }
.connect-item__remove { .connect-item__remove {
...@@ -49,5 +72,13 @@ function handleRemove() { ...@@ -49,5 +72,13 @@ function handleRemove() {
position: absolute; position: absolute;
right: 8px; right: 8px;
top: 8px; top: 8px;
z-index: 999;
}
.connect-item__edit {
display: none;
position: absolute;
left: 8px;
top: 8px;
z-index: 999;
} }
</style> </style>
<script setup lang="ts">
import type { IconProp } from '../types'
import Icon from '../components/Icon.vue'
import { useMapStore } from '@/stores/map'
const store = useMapStore()
// 属性字段类型
const experimentAttributeOptions = $ref(store.getMapValuesByKey('experiment_attribute_type'))
// icon
const iconItems = $ref<IconProp[]>([
{ label: '公众号', name: '1', checkbox: true },
{ label: '钉钉', name: '2', checkbox: false },
{ label: '小鹅通', name: '3', checkbox: false },
{ label: '问卷星', name: '4', checkbox: false },
{ label: '今日头条', name: '5', checkbox: false },
{ label: '抖音', name: '6', checkbox: false },
{ label: '微博', name: '7', checkbox: false },
{ label: '小红书', name: '8', checkbox: false },
{ label: '邮箱', name: '9', checkbox: false },
{ label: '短信', name: '10', checkbox: false },
{ label: '内部消息', name: '11', checkbox: false },
{ label: '自定义', name: '12', checkbox: false }
])
let typeValue = ref<IconProp>({ label: '公众号', name: '1', checkbox: true })
const handleIcon = function (data: IconProp) {
iconItems.forEach((item: IconProp) => (item.checkbox = false))
data.checkbox = true
typeValue.value = data
}
const getData = function () {
return typeValue.value
}
defineExpose({ getData })
</script>
<template>
<div class="connect-from_icon__box">
<div v-for="item in iconItems" :key="item.name" :class="item.checkbox ? 'mr20-mt20 active' : 'mr20-mt20'">
<div @click="handleIcon(item)" class="connect-form_icon">
<Icon class="svg" :name="item.name"></Icon>
</div>
<div class="name">{{ item.label }}</div>
</div>
</div>
</template>
<style lang="scss">
.connect-from_icon__box {
padding: 10px;
display: flex;
flex-wrap: wrap;
.mr20-mt20 {
margin-right: 20px;
margin-bottom: 20px;
&.active {
.name {
color: #ba143e;
}
.connect-form_icon {
box-shadow: 0 0 10px rgb(186, 20, 62, 0.5);
border: 1px solid #ba143e;
}
}
}
.name {
text-align: center;
margin-top: 8px;
}
.connect-form_icon {
width: 70px;
height: 70px;
border-radius: 50%;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
box-shadow: 0 0 10px rgb(0 0 0 / 50%);
}
}
}
</style>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
const props = defineProps<{ data: { type: string; name: string; value?: string } }>()
// 用户需知
const checked = $ref(true)
// form
const formRef = $ref<FormInstance>()
const formAll = ref([
{
type: '1',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: '公众号类型', prop: 'type', value: '' },
{ label: '授权方昵称', prop: 'nikeName', value: '' }
]
},
{
type: '2',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'AgentId', prop: 'agentId', value: '' },
{ label: 'AppKey', prop: 'appKey', value: '' },
{ label: 'AppSecret', prop: 'appSecret', value: '' }
]
},
{
type: '3',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'app_id', prop: 'app_id', value: '' },
{ label: 'client_id', prop: 'client_id', value: '' },
{ label: 'secret_key', prop: 'secret_key', value: '' }
]
},
{
type: '4',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'AppKey', prop: 'appKey', value: '' },
{ label: 'AppSecret', prop: 'appSecret', value: '' }
]
},
{
type: '5',
form: [{ label: '链接名称', prop: 'name', value: '' }]
},
{
type: '6',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: '应用类别', prop: 'dyInput1', value: '' },
{ label: '授权域回调', prop: 'dyInput2', value: '' },
{ label: '网站应用简介', prop: 'dyInput3', value: '' },
{ label: '应用官网', prop: 'dyInput4', value: '' },
{ label: '联系人姓名', prop: 'dyInput5', value: '' }
]
},
{
type: '6',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: '应用类别', prop: 'dyInput1', value: '' },
{ label: '授权域回调', prop: 'dyInput2', value: '' },
{ label: '网站应用简介', prop: 'dyInput3', value: '' },
{ label: '应用官网', prop: 'dyInput4', value: '' },
{ label: '联系人姓名', prop: 'dyInput5', value: '' }
]
},
{
type: '7',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'AppKey', prop: 'appKey', value: '' },
{ label: 'AppSecret', prop: 'appSecret', value: '' }
]
},
{
type: '8',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'AppKey', prop: 'appKey', value: '' },
{ label: 'AppSecret', prop: 'appSecret', value: '' }
]
},
{
type: '9',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'client_id', prop: 'client_id', value: '' },
{ label: 'client_secret', prop: 'client_secret', value: '' },
{ label: 'token URL', prop: 'token', value: '' },
{ label: 'API URL', prop: 'apiUrl', value: '' }
]
},
{
type: '10',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'client_id', prop: 'client_id', value: '' },
{ label: 'SdkAppId', prop: 'sdkAppId', value: '' },
{ label: 'token URL', prop: 'token', value: '' },
{ label: 'API URL', prop: 'apiUrl', value: '' }
]
},
{
type: '11',
form: [{ label: '链接名称', prop: 'name', value: '' }]
},
{
type: '12',
form: [
{ label: '链接名称', prop: 'name', value: '' },
{ label: 'APP类型', prop: 'appType', value: '' },
{ label: 'AppId', prop: 'appId', value: '' }
]
}
])
const formItem = computed(() => {
const [data] = formAll.value.filter(item => item.type === props.data.type)
console.log(props.data?.value, 'value')
return props.data?.value ? Object.assign(data?.form, JSON.parse(props.data?.value)) : data?.form
})
defineExpose({ formItem })
</script>
<template>
<div class="step-two_content">
<div class="content-left">
<h2>用户需知</h2>
<p>亲爱的系统用户,您即将进入链接页面,链接前请您认真阅读一下说明:</p>
<p>
1、您即将链接的系统属于第三方平台,关于此系统的一切内容以及疑问,本公司无法代表此系统提供官方的准确回复,建议您<strong
>及时联系此系统的官方客服人员;</strong
>
</p>
<p>
2、本系统是一个客户数据平台,通过链接全局客户数据,帮助企业构建第一方客户池,数据源为各个与本系统链接的第三方平台,如链接的系统出现数据异常,本公司没有权限进入该系统排查,烦请<strong
>及时联系该系统相关技术人员协助处理。</strong
>
</p>
<el-checkbox v-model="checked" label="我确认上述用户需知" size="large" />
</div>
<div class="content-right">
<el-form ref="formRef" label-suffix=":" label-width="122px">
<el-form-item label="链接类型">
<span>{{ props.data.name }}</span>
</el-form-item>
<el-form-item :label="item.label" :prop="item.prop" v-for="item in formItem">
<el-input v-model="item.value" placeholder="请输入"></el-input>
</el-form-item>
</el-form>
</div>
</div>
</template>
<style lang="scss">
.step-two_content {
display: flex;
padding-bottom: 20px;
.content-left {
padding: 0 20px;
flex: 1;
h2 {
font-size: 16px;
text-align: center;
padding: 20px 0 10px;
}
p {
text-indent: 2em;
margin-bottom: 10px;
strong {
font-weight: bold;
}
}
}
.content-right {
padding-top: 20px;
flex: 1;
}
}
</style>
...@@ -5,7 +5,10 @@ const routes: RouteRecordRaw[] = [ ...@@ -5,7 +5,10 @@ const routes: RouteRecordRaw[] = [
{ {
path: '/connect', path: '/connect',
component: Layout, component: Layout,
children: [{ path: '', component: () => import('./views/Index.vue') }] children: [
{ path: '', component: () => import('./views/Index.vue') },
{ path: 'view', component: () => import('./views/View.vue') }
]
} }
] ]
......
export interface IconProp {
label: string
name: string
checkbox: boolean
}
export interface DetailsProp {
id: string
config_attributes: string
type: string
type_name: string
}
\ No newline at end of file
<script setup lang="ts"> <script setup lang="ts">
import type { DetailsProp } from '../types'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import ListItem from '../components/ListItem.vue' import ListItem from '../components/ListItem.vue'
import { getConnectionList, getConnectionDetails } from '../api'
import { useMapStore } from '@/stores/map'
const store = useMapStore()
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
remote: {
httpRequest: getConnectionList,
params: { created_operator: '', type: '' }
},
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入连接名称' }, { type: 'input', prop: 'created_operator', placeholder: '请输入创建人姓名' },
{ type: 'input', prop: 'name', placeholder: '请输入创建人姓名' } {
], type: 'select',
columns: [ prop: 'type',
{ label: '序号', type: 'index', width: 60 }, placeholder: '请选择类型',
{ label: '属性ID', prop: 'id' }, options: store.getMapValuesByKey('experiment_connection_type')
{ label: '属性名称', prop: 'name' }, }
{ label: '属性字段类型', prop: 'name' }, ]
{ label: '状态', prop: 'name' },
{ label: '更新人', prop: 'name' },
{ label: '更新时间', prop: 'name' },
{ label: '操作', slots: 'table-x', width: 240 }
],
data: [{}, {}]
} }
}) })
...@@ -29,6 +34,22 @@ const listOptions = computed(() => { ...@@ -29,6 +34,22 @@ const listOptions = computed(() => {
function handleRefresh() { function handleRefresh() {
appList?.refetch() appList?.refetch()
} }
// 新建
let formVisible = $ref(false)
const createConnect = function () {
formData = undefined
formVisible = true
}
// 编辑
let formData = $ref<DetailsProp | undefined>()
const editConnect = function (id: string) {
getConnectionDetails({ id: id }).then(res => {
formData = res.data
formVisible = true
})
}
</script> </script>
<template> <template>
...@@ -36,9 +57,14 @@ function handleRefresh() { ...@@ -36,9 +57,14 @@ function handleRefresh() {
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #body="{ data }"> <template #body="{ data }">
<div class="connect-list"> <div class="connect-list">
<ListItem v-for="item in data" :key="item.id" @update="handleRefresh"></ListItem> <ListItem
@edit="editConnect"
<div class="connect-item"> :data="item"
v-for="item in data"
:key="item.id"
@update="handleRefresh"
></ListItem>
<div class="connect-item" @click="createConnect">
<div class="connect-add-button"> <div class="connect-add-button">
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
<span>新建连接</span> <span>新建连接</span>
...@@ -48,6 +74,8 @@ function handleRefresh() { ...@@ -48,6 +74,8 @@ function handleRefresh() {
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<!-- 新建链接 -->
<FormDialog :data="formData" v-model="formVisible" v-if="formVisible" @update="handleRefresh" />
</template> </template>
<style lang="scss"> <style lang="scss">
......
<script setup lang="ts">
import Icon from '../components/Icon.vue'
import { ElMessageBox } from 'element-plus'
import { getConnectionDetails } from '../api'
const route = useRoute()
const openMsg = () => {
// ElMessageBox.alert('成功链接xxxx', '提示', {
// confirmButtonText: '关闭'
// })
}
let dataDetail = $ref<any>()
onMounted(() => {
getConnectionDetails({ id: route.query.id as '' }).then(res => {
dataDetail = res.data
})
})
const ability = ref([
{
type: 1,
data: [
{
title: '1.从公众号同步',
child: [
{ title: '重新获取公众号信息', msg: '' },
{ title: '重新获取公众号粉丝', msg: '' },
{ title: '获取公众号统计数据', msg: '' },
{ title: '获取图文群发评论数据', msg: '' }
]
},
{
title: '2.向公众号同步',
child: [{ title: '批量为用户打标签', msg: '' }]
},
{
title: '3.其他设置',
child: [
{ title: '客服会话设置', msg: '' },
{ title: '删除GDPR数据', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: [
{ title: '注公众号', msg: '' },
{ title: '留言文本', msg: '' },
{ title: '留言图片', msg: '' },
{ title: '留言语音', msg: '' },
{ title: '留言视频', msg: '' },
{ title: '点击菜单', msg: '' },
{ title: '点击菜单会话选项', msg: '' },
{ title: '扫描二维码', msg: '' },
{ title: '取消关注公众号', msg: '' },
{ title: '用户领取卡券', msg: '' },
{ title: '用户转赠卡券', msg: '' },
{ title: '用户核销卡券', msg: '' },
{ title: '用户删除卡券', msg: '' }
]
},
{
title: '5.客户旅程能力:执行动作',
child: [
{ title: '发送文本', msg: '' },
{ title: '发送模版消息', msg: '' },
{ title: '发送菜单会话', msg: '' },
{ title: '发送微信图文', msg: '' },
{ title: '发送H5', msg: '' },
{ title: '发送一人一码', msg: '' },
{ title: '发送小程序', msg: '' },
{ title: '发送图片', msg: '' },
{ title: '发送微信语音', msg: '' },
{ title: '发送微信视频', msg: '' },
{ title: '发送卡券', msg: '' }
]
}
]
},
{
type: 2,
data: [
{
title: '1.从钉钉同步',
child: [{ title: '获取用户信息', msg: '' }]
},
{
title: '2.向钉钉同步',
child: [{ title: '导入用户信息', msg: '' }]
},
{
title: '3.其他设置',
child: [{ title: '访问钉钉官方网站', msg: '' }]
},
{
title: '4.客户旅程能力:触发条件',
child: []
},
{
title: '5.客户旅程能力:执行动作',
child: [{ title: '发送消息', msg: '' }]
}
]
},
{
type: 3,
data: [
{
title: '1.从小鹅通同步',
child: [
{ title: '消息推送', msg: '' },
{ title: '同步历史用户', msg: '' },
{ title: '同步直播学员签到事件', msg: '' }
]
},
{
title: '2.向小鹅通同步',
child: []
},
{
title: '3.其他设置',
child: [
{ title: '访问小鹅通官方网站', msg: '' },
{ title: '配置用户属性字段映射', msg: '' },
{ title: '配置事件属性字段映射', msg: '' },
{ title: '配置信息采集表单字段映射', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: [{ title: '新用户注册', msg: '' }]
},
{
title: '5.客户旅程能力:执行动作',
child: []
}
]
},
{
type: 4,
data: [
{
title: '1.从问卷星同步',
child: [{ title: '同步填写者信息', msg: '' }]
},
{
title: '2.向问卷星同步',
child: []
},
{
title: '3.其他设置',
child: [
{ title: '访问问卷星官方网站', msg: '' },
{ title: '管理表单字段映射', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: [{ title: '提交表单', msg: '' }]
},
{
title: '5.客户旅程能力:执行动作',
child: []
}
]
},
{
type: 5,
data: [
{
title: '1.从今日头条同步',
child: [
{ title: '同步头条推广基础数据', msg: '' },
{ title: '同步头条推广展点消数据', msg: '' }
]
},
{
title: '2.向今日头条同步',
child: [
{ title: '飞鱼线索表格导入', msg: '' },
{ title: '设置返点系数', msg: '' }
]
},
{
title: '3.其他设置',
child: [
{ title: '访问今日头条投放管理平台', msg: '' },
{ title: '广告效果分析', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: []
},
{
title: '5.客户旅程能力:执行动作',
child: []
}
]
},
{
type: 6,
data: [
{
title: '1.从抖音同步',
child: [
{ title: '获取用户视频情况', msg: '' },
{ title: '获取用户粉丝数', msg: '' },
{ title: '获取用户点赞数', msg: '' },
{ title: '获取用户分享数', msg: '' },
{ title: '获取用户主页访问数', msg: '' },
{ title: '获取用户信息', msg: '' }
]
},
{
title: '2.向抖音同步',
child: []
},
{
title: '3.其他设置',
child: []
},
{
title: '4.客户旅程能力:触发条件',
child: [
{ title: '用户发送文本私信', msg: '' },
{ title: '用户发送表情私信', msg: '' },
{ title: '用户发送卡片私信', msg: '' },
{ title: '在主页Tab提交预约', msg: '' }
]
},
{
title: '5.客户旅程能力:执行动作',
child: [
{ title: '向用户发送文本私信', msg: '' },
{ title: '向用户发送图片私信', msg: '' },
{ title: '向用户发送视频私信', msg: '' }
]
}
]
},
{
type: 7,
data: [
{
title: '1.从微博同步',
child: [
{ title: '获取用户信息', msg: '' },
{ title: '获取用户私信数', msg: '' },
{ title: '获取用户关注数', msg: '' }
]
},
{
title: '2.向微博同步',
child: []
},
{
title: '3.其他设置',
child: []
},
{
title: '4.客户旅程能力:触发条件',
child: [
{ title: '关注微博', msg: '' },
{ title: '发送私信', msg: '' }
]
},
{
title: '5.客户旅程能力:执行动作',
child: [
{ title: '发送私信', msg: '' },
{ title: '发送图片', msg: '' }
]
}
]
},
{
type: 8,
data: [
{
title: '1.从小红书同步',
child: [
{ title: '获取小红书用户信息', msg: '' },
{ title: '获取主页粉丝数', msg: '' },
{ title: '获取主页赞藏数', msg: '' },
{ title: '获取用户笔记总数', msg: '' },
{ title: '获取笔记收藏数', msg: '' },
{ title: '获取笔记评论数', msg: '' },
{ title: '获取笔记点赞数', msg: '' },
{ title: '获取笔记转发数', msg: '' }
]
},
{
title: '2.向小红书同步',
child: []
},
{
title: '3.其他设置',
child: []
},
{
title: '4.客户旅程能力:触发条件',
child: [
{ title: '被用户关注', msg: '' },
{ title: '主页被点赞', msg: '' },
{ title: '主页被收藏', msg: '' },
{ title: '笔记被点赞', msg: '' },
{ title: '笔记被收藏', msg: '' },
{ title: '笔记被转发', msg: '' }
]
},
{
title: '5.客户旅程能力:执行动作',
child: []
}
]
},
{
type: 9,
data: [
{
title: '1.从邮件同步',
child: []
},
{
title: '2.向邮件同步',
child: []
},
{
title: '3.其他设置',
child: []
},
{
title: '4.客户旅程能力:触发条件',
child: []
},
{
title: '5.客户旅程能力:执行动作',
child: [{ title: '发送邮件', msg: '' }]
}
]
},
{
type: 10,
data: [
{
title: '1.从短信同步',
child: []
},
{
title: '2.向短信同步',
child: []
},
{
title: '3.其他设置',
child: [
{ title: '管理签名', msg: '' },
{ title: '管理模板', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: []
},
{
title: '5.客户旅程能力:执行动作',
child: [{ title: '发送短信', msg: '' }]
}
]
},
{
type: 11,
data: [
{
title: '1.从内部消息同步',
child: []
},
{
title: '2.向内部消息同步',
child: []
},
{
title: '3.其他设置',
child: []
},
{
title: '4.客户旅程能力:触发条件',
child: []
},
{
title: '5.客户旅程能力:执行动作',
child: [{ title: '发送内部消息', msg: '' }]
}
]
},
{
type: 12,
data: [
{
title: '1.从自定义同步',
child: [
{ title: 'IOS移动应用接入', msg: '' },
{ title: '安卓移动应用接入', msg: '' },
{ title: 'JS SDK接入', msg: '' },
{ title: '同步链接用户', msg: '' },
{ title: '同步链接事件', msg: '' }
]
},
{
title: '2.向自定义同步',
child: []
},
{
title: '3.其他设置',
child: [
{ title: '自定义图元', msg: '' },
{ title: '事件元数据', msg: '' },
{ title: '删除用户', msg: '' }
]
},
{
title: '4.客户旅程能力:触发条件',
child: [
{ title: '访问网页', msg: '' },
{ title: '激活APP', msg: '' },
{ title: '启动APP', msg: '' },
{ title: '退出APP', msg: '' },
{ title: '展示APP页面', msg: '' },
{ title: '点击APP元素', msg: '' },
{ title: '退出APP页面', msg: '' },
{ title: '离开网页', msg: '' }
]
},
{
title: '5.客户旅程能力:执行动作',
child: []
}
]
}
])
const abilityItem = computed(() => {
const [data] = ability.value.filter(item => item.type === parseInt(dataDetail?.type))
return data?.data
})
</script>
<template>
<AppCard title="查看链接">
<div class="view-info">
<div class="view-info_icon">
<Icon :name="dataDetail?.type || '0'" w="50" h="50"></Icon>
</div>
<div class="view-info_content">
<p>链接名称:{{ dataDetail?.type_name }}</p>
<!-- <p>公众号类型:订阅号</p> -->
<p>创始人:{{ dataDetail?.created_operator_name }}</p>
<!-- <p>授权方:xxxxxxxx</p> -->
<p>创建时间:{{ dataDetail?.created_time }}</p>
</div>
</div>
</AppCard>
<AppCard title="链接能力">
<el-tabs class="tabs-box" v-for="item in abilityItem">
<el-tab-pane :label="item.title">
<el-tag v-for="cItem in item.child" class="mr-1" size="large" @click="openMsg">{{ cItem.title }}</el-tag>
</el-tab-pane>
</el-tabs>
</AppCard>
</template>
<style lang="scss">
.view-info {
display: flex;
.view-info_icon {
width: 100px;
height: 100px;
border-radius: 50%;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
}
.view-info_content {
margin-left: 20px;
display: flex;
align-items: center;
p {
// margin-bottom: 10px;
margin-right: 30px;
}
}
}
.mr-1 {
margin-right: 10px;
margin-bottom: 10px;
}
.tabs-box {
margin-bottom: 20px;
}
</style>
import httpRequest from '@/utils/axios'
// 事件属性列表
export function getMetaEvent(params: { name?: string; status?: string; experiment_connection_id?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-event/list', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 创建事件属性
export function createMetaEvent(data: { name: string; english_name: string; experiment_connection_id: string; status: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-event/create', { experiment_id: '7025368348925886464', ...data })
}
// 链接列表
export function getConnectionsList() {
return httpRequest.get('/api/experiment/v1/experiment/meta-event/connections', { params: { experiment_id: '7025368348925886464' } })
}
// 修改事件属性
export function updateMetaEvent(data: { id?: string; name: string; english_name: string; status: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-event/update', { experiment_id: '7025368348925886464', ...data })
}
// 删除
export function deleteMetaEvent(data: { id?: string }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-event/delete', { experiment_id: '7025368348925886464', ...data })
}
// 事件属性列表
export function getMetaEventDetail(params: { id: string }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-event/view', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 保存属性
export function updateAttributes(data: { id: string; attributes: string }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-event/attributes', { experiment_id: '7025368348925886464', ...data })
}
// 事件属性列表
export function getIsDeleteAttribute(params: { id: string }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-event/can-delete-attribute', { params: { experiment_id: '7025368348925886464', ...params } })
}
\ No newline at end of file
<script setup lang="ts">
import type { EventProp, EventDetailProp, EventAttributesProp } from '../types'
import { ElMessage } from 'element-plus'
import { useMapStore } from '@/stores/map'
import { Close } from '@element-plus/icons-vue'
import { getMetaEventDetail, updateAttributes, getIsDeleteAttribute } from '../api'
const store = useMapStore()
interface Props {
data?: EventProp
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
// 属性字段类型
const experimentAttributeOptions = $ref(store.getMapValuesByKey('experiment_attribute_type'))
// 添加字段
const addField = function () {
tableData.push({ id: '', name: '', english_name: '', type: '', format: '' })
}
// 删除字段
const deleteField = function (scope: { $index: number; row: { id: string } }) {
if (tableData[scope.$index]?.id === '') {
tableData.splice(scope.$index, 1)
} else {
// 判断当前属性是否可以删除
getIsDeleteAttribute({ id: scope.row.id }).then(res => {
res.data?.can_delete ? tableData.splice(scope.$index, 1) : ElMessage({ message: '不能删除', type: 'warning' })
})
}
}
// 事件详情
let eventDetail = $ref<EventDetailProp>()
onBeforeMount(() => {
getMetaEventDetail({ id: props.data?.id || '' }).then(res => {
eventDetail = res.data
tableData = res.data.attributes
})
})
// 字段
let tableData = $ref<EventAttributesProp[]>([])
// 提交
function handleSubmit() {
handleUpdate()
}
function handleUpdate() {
const params = {
id: eventDetail?.id || '',
attributes: JSON.stringify(tableData)
}
updateAttributes(params).then(res => {
ElMessage({ message: '保存成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
</script>
<template>
<el-dialog
title="事件属性"
:close-on-click-modal="false"
width="800px"
@update:modelValue="$emit('update:modelValue')"
>
<div style="display: flex; justify-content: space-around">
<el-form label-width="120px">
<el-form-item label="事件英文名称:">{{ eventDetail?.english_name }}</el-form-item>
<el-form-item label="事件名称:">{{ eventDetail?.name }}</el-form-item>
</el-form>
<el-form label-width="120px">
<el-form-item label="所属链接:">{{ eventDetail?.connection_name }}</el-form-item>
<el-form-item label="状态:">{{ eventDetail?.status_name }}</el-form-item>
</el-form>
</div>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>事件属性字段</span>
<el-button type="primary" @click="addField">添加</el-button>
</div>
</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>
</el-table-column>
<el-table-column label="属性名称">
<template #default="scope">
<el-input v-model="scope.row.name" placeholder="请输入"></el-input>
</template>
</el-table-column>
<el-table-column label="字段类型">
<template #default="scope">
<el-select :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>
</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 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>
</el-select>
<el-input
v-else
:disabled="scope.row.id !== ''"
type="number"
v-model="scope.row.format"
:placeholder="scope.row.type === '1' ? '请输入字符串长度' : '请输入长度'"
></el-input>
</template>
</el-table-column>
<el-table-column width="30">
<template #default="scope">
<div @click="deleteField(scope)" style="display: flex; justify-content: center; cursor: pointer">
<el-icon size="20"><Close /></el-icon>
</div>
</template>
</el-table-column>
</el-table>
</el-card>
<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">保存</el-button>
</el-row>
</template>
</el-dialog>
</template>
<style lang="scss">
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
<script setup lang="ts"> <script setup lang="ts">
import type { EventProp } from '../types' import type { EventProp, ConnectionOptionProp } 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 { createMetaEvent, updateMetaEvent } from '../api'
import { useMapStore } from '@/stores/map'
const store = useMapStore()
interface Props { interface Props {
data?: EventProp data?: EventProp
option: ConnectionOptionProp[]
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -21,17 +26,19 @@ const title = $computed(() => { ...@@ -21,17 +26,19 @@ const title = $computed(() => {
}) })
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ const form = reactive(
id: '', props.data || {
name: '', name: '',
type: '', english_name: '',
status: '' experiment_connection_id: '',
}) status: '0'
}
)
const rules = ref<FormRules>({ const rules = ref<FormRules>({
id: [{ required: true, message: '请输入事件ID' }], name: [{ required: true, message: '请输入' }],
name: [{ required: true, message: '请输入事件名称' }], english_name: [{ required: true, message: '请输入' }],
type: [{ required: true, message: '请选择属性字段类型' }] experiment_connection_id: [{ required: true, message: '请选择' }]
}) })
// 提交 // 提交
...@@ -43,32 +50,46 @@ function handleSubmit() { ...@@ -43,32 +50,46 @@ function handleSubmit() {
// 新建 // 新建
function handleCreate() { function handleCreate() {
ElMessage({ message: '创建成功', type: 'success' }) createMetaEvent(form).then(res => {
emit('update') ElMessage({ message: '创建成功', type: 'success' })
emit('update:modelValue', false) emit('update')
emit('update:modelValue', false)
})
} }
// 修改 // 修改
function handleUpdate() { function handleUpdate() {
ElMessage({ message: '修改成功', type: 'success' }) updateMetaEvent(form).then(res => {
emit('update') ElMessage({ message: '修改成功', type: 'success' })
emit('update:modelValue', false) emit('update')
emit('update:modelValue', false)
})
} }
</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="600px" @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="140px">
<el-form-item label="事件ID" prop="id"> <el-form-item label="事件ID" prop="id" v-if="isUpdate">
<el-input v-model="form.id" /> <span>{{ props.data?.id }}</span>
</el-form-item>
<el-form-item label="事件英文名称" prop="english_name">
<el-input v-model="form.english_name" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="事件名称" prop="name"> <el-form-item label="事件名称" prop="name">
<el-input v-model="form.name" /> <el-input v-model="form.name" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="所属连接" prop="type"> <el-form-item label="所属连接" prop="experiment_connection_id">
<el-select v-model="form.type" style="width: 100%"></el-select> <el-select
:disabled="isUpdate"
v-model="form.experiment_connection_id"
style="width: 100%"
placeholder="请选择"
>
<el-option :label="item.type_name" :value="item.id" :key="item.id" v-for="item in props.option"></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-switch v-model="form.status" active-text="生效" inactive-text="失效" /> <el-switch v-model="form.status" active-text="生效" inactive-text="失效" active-value="1" inactive-value="0" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
......
...@@ -8,18 +8,21 @@ defineProps<Props>() ...@@ -8,18 +8,21 @@ defineProps<Props>()
<template> <template>
<el-dialog title="查看事件属性" :close-on-click-modal="false" width="600px"> <el-dialog title="查看事件属性" :close-on-click-modal="false" width="600px">
<el-form label-suffix=":" label-width="90px"> <el-form label-suffix=":" label-width="120px">
<el-form-item label="事件ID"> <el-form-item label="事件ID">
{{ data.id }} {{ data.id }}
</el-form-item> </el-form-item>
<el-form-item label="事件英文名称">
{{ data.english_name }}
</el-form-item>
<el-form-item label="事件名称"> <el-form-item label="事件名称">
{{ data.id }} {{ data.name }}
</el-form-item> </el-form-item>
<el-form-item label="所属连接"> <el-form-item label="所属连接">
{{ data.id }} {{ data.connection_name }}
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态">
{{ data.id }} {{ data.status_name }}
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
......
export interface EventProp { export interface EventProp {
id: string id: string
name: string name: string
english_name: string
experiment_connection_id: string
status: string
connection_name: string
status_name: string
}
export interface ConnectionOptionProp { type_name: string; id: string }
export interface EventDetailProp {
id: string
english_name: string
connection_name: string
name: string
status_name: string
attributes: EventAttributesProp[]
}
export interface EventAttributesProp {
id: string
name: string
english_name: string
type: string
format: string
} }
<script setup lang="ts"> <script setup lang="ts">
import type { EventProp } from '../types' import type { EventProp, ConnectionOptionProp } from '../types'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import { getMetaEvent, getConnectionsList, deleteMetaEvent } from '../api'
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 FieldDialog = defineAsyncComponent(() => import('../components/FieldDialog.vue'))
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 所属链接选项
let experimentConnectionOptions = $ref<ConnectionOptionProp[]>()
getConnectionsList().then(res => {
experimentConnectionOptions = res.data
})
// 列表配置 // 列表配置
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
remote: {
httpRequest: getMetaEvent,
params: { name: '', status: '', experiment_connection_id: '' }
},
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入事件名称' }, { type: 'input', prop: 'name', placeholder: '请输入事件名称' },
{ {
type: 'select', type: 'select',
prop: 'type', prop: 'experiment_connection_id',
placeholder: '请选择事件所属连接' placeholder: '请选择事件所属连接',
options: experimentConnectionOptions,
labelKey: 'type_name',
valueKey: 'id'
},
{
type: 'select',
prop: 'status',
placeholder: '请选择生效状态',
options: [
{ label: '有效', value: '1' },
{ label: '失效', value: '0' }
]
} }
], ],
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '事件ID', prop: 'id' }, { label: '事件ID', prop: 'id' },
{ label: '事件英文名称', prop: 'english_name' },
{ label: '事件名称', prop: 'name' }, { label: '事件名称', prop: 'name' },
{ label: '所属连接', prop: 'name' }, { label: '所属连接', prop: 'connection_name' },
{ label: '属性字段数量', prop: 'name' }, { label: '属性字段数量', prop: 'attributes_count' },
{ label: '状态', prop: 'name' }, { label: '状态', prop: 'status_name' },
{ label: '更新人', prop: 'name' }, { label: '更新人', prop: 'updated_operator_name' },
{ label: '更新时间', prop: 'name' }, { label: '更新时间', prop: 'updated_time' },
{ label: '操作', slots: 'table-x', width: 300 } { label: '操作', slots: 'table-x', width: 300 }
], ]
data: [{ id: 1 }, { id: 2 }]
} }
}) })
...@@ -63,13 +88,25 @@ function handleView(row: EventProp) { ...@@ -63,13 +88,25 @@ function handleView(row: EventProp) {
// 删除 // 删除
function handleRemove(row: EventProp) { function handleRemove(row: EventProp) {
ElMessageBox.confirm('确定要删除该属性吗?', '提示').then(() => {}) ElMessageBox.confirm('确定要删除该属性吗?', '提示').then(() => {
deleteMetaEvent({ id: row.id }).then(res => {
ElMessage({ message: '删除成功', type: 'success' })
handleRefresh()
})
})
}
// 字段
let fieldVisible = $ref(false)
const handleField = function (row: EventProp) {
currentRow = row
fieldVisible = true
} }
</script> </script>
<template> <template>
<AppCard> <AppCard>
<AppList v-bind="listOptions"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-space> <el-space>
<el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button> <el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button>
...@@ -79,12 +116,19 @@ function handleRemove(row: EventProp) { ...@@ -79,12 +116,19 @@ function handleRemove(row: EventProp) {
<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>
<el-button type="primary" plain>字段</el-button> <el-button type="primary" plain @click="handleField(row)">字段</el-button>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<!-- 新建/修改 --> <!-- 新建/修改 -->
<FormDialog v-model="formVisible" :data="currentRow" @update="handleRefresh" v-if="formVisible" /> <FormDialog
v-model="formVisible"
:data="currentRow"
@update="handleRefresh"
:option="experimentConnectionOptions || []"
v-if="formVisible"
/>
<!-- 查看 --> <!-- 查看 -->
<ViewDialog v-model="viewVisible" :data="currentRow" v-if="viewVisible && currentRow" /> <ViewDialog v-model="viewVisible" :data="currentRow" v-if="viewVisible && currentRow" />
<FieldDialog v-model="fieldVisible" :data="currentRow" v-if="fieldVisible && currentRow"></FieldDialog>
</template> </template>
import httpRequest from '@/utils/axios'
// 用户属性列表
export function getMemberMeta(params: { name?: string; status?: string; type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-member/list', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 用户属性详情
export function getMemberMetaDetail(params: { id: string }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-member/view', { params: { experiment_id: '7025368348925886464', ...params } })
}
// 创建用户属性
export function createMemberMeta(data: { name: string; english_name: string; type: string; format: string; status: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-member/create', { experiment_id: '7025368348925886464', ...data })
}
// 修改用户属性
export function updateMemberMeta(data: { id?: string; name: string; english_name: string; status: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-member/update', { experiment_id: '7025368348925886464', ...data })
}
// 修改用户属性
export function deleteMemberMeta(data: { id: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/meta-member/delete', { experiment_id: '7025368348925886464', ...data })
}
// 事件属性列表
export function getMetaEvent(params: { name?: string; status?: string; type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/meta-event/list', { params: { experiment_id: '7025368348925886464', ...params } })
}
\ No newline at end of file
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
import type { UserProp } from '../types' import type { UserProp } 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 { useMapStore } from '@/stores/map'
import { createMemberMeta, updateMemberMeta } from '../api'
const store = useMapStore()
interface Props { interface Props {
data?: UserProp data?: UserProp
...@@ -21,19 +25,22 @@ const title = $computed(() => { ...@@ -21,19 +25,22 @@ const title = $computed(() => {
}) })
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive({ const form = reactive(
id: '', props.data || {
name: '', name: '',
type: '', english_name: '',
value: '', type: '',
status: '' format: '',
}) status: '0'
}
)
const rules = ref<FormRules>({ const rules = ref<FormRules>({
id: [{ required: true, message: '请输入属性ID' }], name: [{ required: true, message: '请输入' }],
name: [{ required: true, message: '请输入属性名称' }], english_name: [{ required: true, message: '请输入' }],
type: [{ required: true, message: '请选择属性字段类型' }], type: [{ required: true, message: '请选择' }],
value: [{ required: true, message: '请输入属性ID' }] format: [{ required: true, message: '请输入' }],
status: [{ required: true, message: '请选择' }]
}) })
// 提交 // 提交
...@@ -45,35 +52,73 @@ function handleSubmit() { ...@@ -45,35 +52,73 @@ function handleSubmit() {
// 新建 // 新建
function handleCreate() { function handleCreate() {
ElMessage({ message: '创建成功', type: 'success' }) createMemberMeta(form).then(res => {
emit('update') ElMessage({ message: '创建成功', type: 'success' })
emit('update:modelValue', false) emit('update')
emit('update:modelValue', false)
})
} }
// 修改 // 修改
function handleUpdate() { function handleUpdate() {
ElMessage({ message: '修改成功', type: 'success' }) updateMemberMeta(form).then(res => {
emit('update') ElMessage({ message: '修改成功', type: 'success' })
emit('update:modelValue', false) emit('update')
emit('update:modelValue', false)
})
} }
// 属性字段类型
const experimentAttributeOptions = $ref(store.getMapValuesByKey('experiment_attribute_type'))
// 属性字段类型选择后->格式的placeholder改变
const formatPlaceholder = computed(() => {
return form.type === '1' ? '请输入字符串长度' : '请输入长度'
})
</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="600px" @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="122px"> <el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="122px">
<el-form-item label="属性ID" prop="id"> <el-form-item label="属性ID" v-if="isUpdate">
<el-input v-model="form.id" /> {{ props.data?.id }}
</el-form-item>
<el-form-item label="属性英文名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="属性名称" prop="name"> <el-form-item label="属性名称" prop="english_name">
<el-input v-model="form.name" /> <el-input v-model="form.english_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> <el-select
:disabled="isUpdate"
@change="form.format = ''"
v-model="form.type"
style="width: 100%"
placeholder="请选择"
>
<el-option
:label="item.label"
:value="item.value"
:key="item.id"
v-for="item in experimentAttributeOptions"
></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="属性字段格式" prop="type"> <el-form-item label="属性字段格式" prop="format" v-if="form.type !== ''">
<el-input v-model="form.value" /> <el-select
:disabled="isUpdate"
v-if="form.type === '4' || form.type === '5'"
v-model="form.format"
style="width: 100%"
placeholder="请选择"
>
<el-option label="yyyy-mm-dd" value="yyyy-mm-dd"></el-option>
<el-option v-if="form.type !== '4'" label="yyyy-mm-dd hh:mm:ss" value="yyyy-mm-dd hh:mm:ss"></el-option>
</el-select>
<el-input :disabled="isUpdate" type="number" v-else v-model="form.format" :placeholder="formatPlaceholder" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-switch v-model="form.status" active-text="生效" inactive-text="失效" /> <el-switch v-model="form.status" active-text="生效" inactive-text="失效" active-value="1" inactive-value="0" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
......
...@@ -12,17 +12,20 @@ defineProps<Props>() ...@@ -12,17 +12,20 @@ defineProps<Props>()
<el-form-item label="属性ID"> <el-form-item label="属性ID">
{{ data.id }} {{ data.id }}
</el-form-item> </el-form-item>
<el-form-item label="属性英文名称">
{{ data.english_name }}
</el-form-item>
<el-form-item label="属性名称"> <el-form-item label="属性名称">
{{ data.id }} {{ data.name }}
</el-form-item> </el-form-item>
<el-form-item label="属性字段类型"> <el-form-item label="属性字段类型">
{{ data.id }} {{ data.type_name }}
</el-form-item> </el-form-item>
<el-form-item label="属性字段格式"> <el-form-item label="属性字段格式">
{{ data.id }} {{ data.format }}
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态">
{{ data.id }} {{ data.status_name }}
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
......
export interface UserProp { export interface UserProp {
id: string id: string
name: string name: string
english_name: string
type: string
format: string
status: string
type_name: string
status_name: string
} }
<script setup lang="ts"> <script setup lang="ts">
import type { UserProp } from '../types' import type { UserProp } from '../types'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import { getMemberMeta, deleteMemberMeta } from '../api'
import { useMapStore } from '@/stores/map'
const store = useMapStore()
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'))
...@@ -11,25 +15,40 @@ const appList = $ref<InstanceType<typeof AppList> | null>(null) ...@@ -11,25 +15,40 @@ const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
const listOptions = computed(() => { const listOptions = computed(() => {
return { return {
remote: {
httpRequest: getMemberMeta,
params: { name: '', status: '', type: '' }
},
filters: [ filters: [
{ type: 'input', prop: 'name', placeholder: '请输入用户属性名称' }, { type: 'input', prop: 'name', placeholder: '请输入用户属性名称' },
{ {
type: 'select', type: 'select',
prop: 'experiment_id', prop: 'type',
placeholder: '请选择属性字段类型' placeholder: '请选择属性字段类型',
options: store.getMapValuesByKey('experiment_attribute_type')
},
{
type: 'select',
prop: 'status',
placeholder: '请选择生效状态',
options: [
{ label: '有效', value: '1' },
{ label: '失效', value: '0' }
]
} }
], ],
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '属性ID', prop: 'id' }, { label: '属性ID', prop: 'id' },
{ label: '属性名称', prop: 'name' }, { label: '属性名称', prop: 'name' },
{ label: '属性字段类型', prop: 'name' }, { label: '属性英文名称', prop: 'english_name' },
{ label: '状态', prop: 'name' }, { label: '属性字段类型', prop: 'type_name' },
{ label: '更新人', prop: 'name' }, { label: '属性字段格式', prop: 'format' },
{ label: '更新时间', prop: 'name' }, { label: '状态', prop: 'status_name' },
{ label: '更新人', prop: 'updated_operator_name' },
{ label: '更新时间', prop: 'updated_time' },
{ label: '操作', slots: 'table-x', width: 240 } { label: '操作', slots: 'table-x', width: 240 }
], ]
data: [{ id: 1 }, { id: 2 }]
} }
}) })
...@@ -62,7 +81,12 @@ function handleView(row: UserProp) { ...@@ -62,7 +81,12 @@ function handleView(row: UserProp) {
// 删除 // 删除
function handleRemove(row: UserProp) { function handleRemove(row: UserProp) {
ElMessageBox.confirm('确定要删除该属性吗?', '提示').then(() => {}) ElMessageBox.confirm('确定要删除该属性吗?', '提示').then(() => {
deleteMemberMeta({ id: row.id }).then(res => {
ElMessage({ message: '删除成功', type: 'success' })
handleRefresh()
})
})
} }
</script> </script>
......
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
})
</script>
<template>
<el-dialog
class="connect-form"
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="142px">
<el-form-item label="所属实验" prop="type">
<el-select v-model="form.type" style="width: 100%"></el-select>
</el-form-item>
<el-form-item label="来源链接">
<el-select v-model="form.id" style="width: 100%"></el-select>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="form.id" style="width: 100%"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.id" class="ml-4">
<el-radio label="1" size="large">生效</el-radio>
<el-radio label="2" size="large">失效</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="性别">
<el-input v-model="form.id" style="width: 100%"></el-input>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="form.id" style="width: 100%"></el-input>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">保存</el-button>
<el-button type="primary">关闭</el-button>
</div>
</el-dialog>
</template>
<style lang="scss">
.btn-box {
text-align: center;
margin-bottom: 20px;
}
</style>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
})
</script>
<template>
<el-dialog
title="新建用户事件数据"
:close-on-click-modal="false"
width="500px"
@update:modelValue="$emit('update:modelValue')"
>
<div class="update-event_info">
<span>姓名:王小二</span>
<span>来源链接:抖音</span>
</div>
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="122px">
<el-form-item label="请选择事件" prop="type">
<el-select v-model="form.type" style="width: 100%"></el-select>
</el-form-item>
<el-form-item label="订单金额" prop="type">
<el-input v-model="form.type" style="width: 100%"></el-input>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">关闭</el-button>
<el-button type="primary">保存</el-button>
</div>
</el-dialog>
</template>
<style lang="scss">
.btn-box {
text-align: center;
margin-bottom: 20px;
}
.update-event_info {
padding-left: 25px;
padding-bottom: 20px;
display: flex;
justify-content: space-between;
}
</style>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
})
</script>
<template>
<el-dialog
class="connect-form"
title="导入用户事件数据"
:close-on-click-modal="false"
width="500px"
@update:modelValue="$emit('update:modelValue')"
>
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="122px">
<el-form-item label="请选择事件" prop="type">
<el-select v-model="form.type" style="width: 100%"></el-select>
<span>事件所属链接:抖音</span>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">下载事件数据模板</el-button>
<el-button type="primary">上传事件数据</el-button>
</div>
<div class="btn-box">
<el-button type="primary">关闭</el-button>
<!-- <el-button type="primary">上传事件数据</el-button> -->
</div>
</el-dialog>
</template>
<style lang="scss">
.btn-box {
text-align: center;
margin-bottom: 20px;
}
</style>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
})
</script>
<template>
<el-dialog
class="connect-form"
title="导入用户数据"
:close-on-click-modal="false"
width="500px"
@update:modelValue="$emit('update:modelValue')"
>
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="142px">
<el-form-item label="请选择所属链接" prop="type">
<el-select v-model="form.type" style="width: 100%"></el-select>
</el-form-item>
<el-form-item label="请选择静态群组">
<el-select v-model="form.id" style="width: 100%"></el-select>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">下载用户数据模板</el-button>
<el-button type="primary">上传用户数据</el-button>
</div>
<div class="btn-box">
<el-button type="primary">关闭</el-button>
<!-- <el-button type="primary">上传事件数据</el-button> -->
</div>
</el-dialog>
</template>
<style lang="scss">
.btn-box {
text-align: center;
margin-bottom: 20px;
}
</style>
...@@ -5,8 +5,10 @@ const routes: RouteRecordRaw[] = [ ...@@ -5,8 +5,10 @@ const routes: RouteRecordRaw[] = [
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,
children: [{ path: '', component: () => import('./views/Index.vue') }] children: [
{ path: '', component: () => import('./views/Index.vue') },
{ path: 'eventDetails', component: () => import('./views/EventDetails.vue') }
]
} }
] ]
export { routes } export { routes }
<script setup lang="ts">
import { Plus, Download, Upload, Delete } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue'
import UpdateEventsDialog from '../components/UpdateEventsDialog.vue'
const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置
const listOptions = computed(() => {
return {
columns: [
{ label: '序号', type: 'index', width: 60 },
{ label: '事件名称', prop: 'id' },
{ label: '链接名称', prop: 'name' },
{ label: '事件发生时间', prop: 'name' },
{ label: '操作', slots: 'table-x', width: 380 }
],
data: [{}, {}]
}
})
// 刷新
function handleRefresh() {
appList?.refetch()
}
// 事件弹窗
const eventsVisible = $ref(false)
</script>
<template>
<AppCard title="用户事件数据">
<div class="event-user_info">
<span>姓名:王小二</span>
<span>id:11111</span>
<span>来源链接:抖音</span>
<span>状态:生效</span>
</div>
</AppCard>
<AppCard>
<AppList v-bind="listOptions" ref="appList">
<template #header-buttons>
<el-button type="primary" :icon="Plus" @click="eventsVisible = true">新建用户事件</el-button>
</template>
<template #table-x>
<el-button type="primary" plain>查看</el-button>
<el-button type="primary" plain>编辑</el-button>
<el-button type="primary" plain>删除</el-button>
</template>
</AppList>
</AppCard>
<!-- 新建更新事件 -->
<UpdateEventsDialog v-model="eventsVisible"></UpdateEventsDialog>
</template>
<style lang="scss">
.event-user_info {
span {
margin-right: 50px;
}
}
</style>
<script setup lang="ts"> <script setup lang="ts">
import { Plus, Download, Upload, Delete } from '@element-plus/icons-vue' import { Plus, Download, Upload, Delete } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import UploadEventsDialog from '../components/UploadEventsDialog.vue'
import UploadUserDialog from '../components/UploadUserDialog.vue'
import UpdateDialog from '../components/UpdateDialog.vue'
// import { getMemberMetaDetail } from '../api'
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置 // 列表配置
...@@ -28,6 +32,15 @@ const listOptions = computed(() => { ...@@ -28,6 +32,15 @@ const listOptions = computed(() => {
function handleRefresh() { function handleRefresh() {
appList?.refetch() appList?.refetch()
} }
// 导入事件弹窗
const eventsVisible = $ref(false)
// 导入用户弹窗
const userVisible = $ref(false)
// 新建、更新、查看
const updateVisible = $ref(false)
</script> </script>
<template> <template>
...@@ -49,15 +62,14 @@ function handleRefresh() { ...@@ -49,15 +62,14 @@ function handleRefresh() {
<el-button type="primary" :icon="Upload">导入</el-button> <el-button type="primary" :icon="Upload">导入</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item>用户数据</el-dropdown-item> <el-dropdown-item @click="userVisible = true">用户数据</el-dropdown-item>
<el-dropdown-item>用户事件数据</el-dropdown-item> <el-dropdown-item @click="eventsVisible = true">用户事件数据</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<el-button type="danger" plain :icon="Delete">删除</el-button> <el-button type="danger" plain :icon="Delete">删除</el-button>
</el-space> </el-space>
</template> </template>
<template #table-x> <template #table-x>
<el-button type="primary" plain>画像</el-button> <el-button type="primary" plain>画像</el-button>
<el-button type="primary" plain>查看</el-button> <el-button type="primary" plain>查看</el-button>
...@@ -67,4 +79,10 @@ function handleRefresh() { ...@@ -67,4 +79,10 @@ function handleRefresh() {
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<!-- 导入事件弹窗 -->
<UploadEventsDialog v-model="eventsVisible"></UploadEventsDialog>
<!-- 导入用户弹窗 -->
<UploadUserDialog v-model="userVisible"></UploadUserDialog>
<!-- 新建、更新、查看 -->
<UpdateDialog v-model="updateVisible"></UpdateDialog>
</template> </template>
...@@ -26,11 +26,11 @@ export default defineConfig(({ mode }) => ({ ...@@ -26,11 +26,11 @@ 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/lab': { '/api/experiment': {
// target: 'http://test-resource-api.ezijing.com:8001', target: 'http://localhost-resource-experiment.ezijing.com',
// changeOrigin: true, changeOrigin: true,
// rewrite: path => path.replace(/^\/api\/lab/, '') rewrite: path => path.replace(/^\/api\/experiment/, '')
// }, },
'/api': 'https://saas-lab.ezijing.com' '/api': 'https://saas-lab.ezijing.com'
} }
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论