提交 90d00e72 authored 作者: lihuihui's avatar lihuihui

update

上级 fa868381
......@@ -202,7 +202,6 @@
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
......
......@@ -203,7 +203,6 @@ declare global {
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
......
......@@ -123,7 +123,7 @@ function handleUpdate() {
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 !== '5'" label="yyyy-mm-dd" value="yyyy-mm-dd"></el-option>
<el-option
v-if="scope.row.type !== '4'"
label="yyyy-mm-dd hh:mm:ss"
......
import httpRequest from '@/utils/axios'
// 人员列表
export function getMemberList(params: { name?: string; id?: string; mobile?: string; status?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/member/list', { params })
}
// 链接列表
export function getMemberConnectionsList() {
return httpRequest.get('/api/experiment/v1/experiment/member/connections')
}
// 用户属性
export function getMemberFieldsList() {
return httpRequest.get('/api/experiment/v1/experiment/member/member-fields')
}
// 新建用户
export function createMember(data: { name: string; status: string; experiment_connection_id: string; gender: string; mobile: string; fields: string }) {
return httpRequest.post('/api/experiment/v1/experiment/member/create', data)
}
// 删除用户
export function deleteMember(data: { ids: string; }) {
return httpRequest.post('/api/experiment/v1/experiment/member/delete', data)
}
// 新建用户
export function updateMember(data: { id?: string; name: string; status: string; experiment_connection_id: string; gender: string; mobile: string; fields: string }) {
return httpRequest.post('/api/experiment/v1/experiment/member/update', data)
}
// 单人员事件列表
export function getMemberEventList(params: { id: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/experiment/v1/experiment/member/member-events', { params })
}
// 事件列表
export function getEventList() {
return httpRequest.get('/api/experiment/v1/experiment/member/events')
}
// 新建事件
export function createEvent(data: { experiment_member_id: string; experiment_meta_event_id: string; fields: any }) {
return httpRequest.post('/api/experiment/v1/experiment/member/event-create', data)
}
// 更新事件
export function updateEvent(data: { id: string; fields: any }) {
return httpRequest.post('/api/experiment/v1/experiment/member/event-update', data)
}
// 删除事件
export function deleteEvent(data: { id: string }) {
return httpRequest.post('/api/experiment/v1/experiment/member/event-delete', data)
}
// 用户画像
export function getMemberImage(params: { id: string }) {
return httpRequest.get('/api/experiment/v1/experiment/member/member-image', { params })
}
// 导入事件
export function importEvent(data: { event_id: string; file: any }) {
return httpRequest.post('/api/experiment/v1/experiment/member/event-upload', data, {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
// 导入用户
export function importMember(data: { groups_id?: string; connection_id: string; file: any }) {
return httpRequest.post('/api/experiment/v1/experiment/member/member-upload', data, {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
// 用户画像
export function getMemberGroups() {
return httpRequest.get('/api/experiment/v1/experiment/member/groups')
}
\ No newline at end of file
差异被折叠。
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage } from 'element-plus'
import { getMemberConnectionsList, getMemberFieldsList, createMember, updateMember } from '../api'
import type { ConnectionsProp, MemberFieldsProp, MemberProp } from '../types'
import { useMapStore } from '@/stores/map'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
const store = useMapStore()
defineEmits<{
const ruleFormRef = ref<FormInstance>()
onMounted(() => {
getConnectionsList()
getFieldsList()
})
// 链接列表(所属链接选项)
let connectionOptions = $ref<ConnectionsProp[]>()
const getConnectionsList = function () {
getMemberConnectionsList().then((res: { data: ConnectionsProp[] }) => {
connectionOptions = res.data
})
}
// 用户属性
let fieldsList = $ref<MemberFieldsProp[]>([])
const getFieldsList = function () {
getMemberFieldsList().then((res: { data: MemberFieldsProp[] }) => {
fieldsList = res.data.map(item => {
item.value = ''
if (props.data) {
item.value = JSON.parse(props.data?.fields)[item.id]
}
return item
})
})
}
interface Props {
data?: MemberProp
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const form = $ref(
props.data || {
name: '',
status: '0',
experiment_connection_id: '',
gender: '',
mobile: ''
}
)
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
name: [{ required: true, message: '请输入' }],
status: [{ required: true, message: '请选择' }],
experiment_connection_id: [{ required: true, message: '请选择' }],
gender: [{ required: true, message: '请选择' }],
mobile: [{ required: true, message: '请输入' }]
})
// 提交
const submitForm = (formEl: FormInstance | undefined) => {
const fields = fieldsList.reduce((a: any, b: { id: string; value: string }) => {
a[b.id] = b.value
return a
}, {})
const params = { ...form, fields: fields }
if (!formEl) return
formEl.validate(valid => {
if (valid) {
if (props.data?.id) {
updateMember(params).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '更新成功', type: 'success' })
})
} else {
createMember(params).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '添加成功', type: 'success' })
})
}
} else {
console.log('error submit!')
return false
}
})
}
</script>
<template>
<el-dialog
class="connect-form"
title="新建用户"
:title="props.data ? (props.data?.isView ? '查看用户' : '编辑用户') : '新建用户'"
: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
:disabled="props.data?.isView"
ref="ruleFormRef"
style="width: 400px; margin: 0 auto; padding: 0 30px 30px 0"
:model="form"
:rules="rules"
label-suffix=":"
label-width="110px"
>
<el-form-item label="来源链接" prop="experiment_connection_id">
<el-select v-model="form.experiment_connection_id" style="width: 100%">
<el-option v-for="item in connectionOptions" :label="item?.type_name" :value="item?.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" style="width: 100%"></el-input>
</el-form-item>
<el-form-item label="来源链接">
<el-select v-model="form.id" style="width: 100%"></el-select>
<el-form-item label="状态" prop="status">
<el-switch v-model="form.status" active-text="生效" active-value="1" inactive-text="失效" inactive-value="0" />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="form.id" style="width: 100%"></el-input>
<el-form-item label="性别" prop="gender">
<el-select v-model="form.gender" style="width: 100%">
<el-option
v-for="item in store.getMapValuesByKey('system_gender')"
:label="item?.label"
:value="item?.value"
></el-option>
</el-select>
</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 label="手机号码" prop="mobile">
<el-input v-model="form.mobile" 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 :label="item.name" v-for="item in fieldsList">
<template v-if="item.type === '4' || item.type === '5'">
<el-date-picker
v-if="item.format === 'yyyy-mm-dd'"
v-model="item.value"
type="date"
placeholder="请选择"
style="width: 100%"
value-format="YYYY-MM-DD"
/>
<el-date-picker
value-format="YYYY-MM-DD HH:mm:ss"
v-else
v-model="item.value"
type="datetime"
placeholder="请选择"
style="width: 100%"
/>
</template>
<el-input v-else v-model="item.value" style="width: 100%" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="form.id" style="width: 100%"></el-input>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">提交</el-button>
<el-button @click="$emit('update:modelValue', false)">关闭</el-button>
</el-form-item>
</el-form>
<div class="btn-box">
<!-- <div class="btn-box">
<el-button type="primary">保存</el-button>
<el-button type="primary">关闭</el-button>
</div>
</div> -->
</el-dialog>
</template>
<style lang="scss">
......
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { getEventList, createEvent, updateEvent } from '../api'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { EventProp, MemberProp, AttributesProp } from '../types'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
const route = useRoute()
defineEmits<{
interface Props {
info?: MemberProp
data?: AttributesProp
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
})
const form = $ref(
props.data || {
experiment_meta_event_id: ''
}
)
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
experiment_meta_event_id: [{ required: true, message: '请选择' }]
})
let eventList = $ref<EventProp[]>()
onMounted(() => {
getEventList().then(res => {
eventList = res.data.map(
(item: any) =>
item.attributes.map((cItem: any) =>
props.data ? (cItem.value = JSON.parse(props.data.fields)[cItem.id]) : (cItem.value = '') && cItem
) && item
)
})
})
// 属性
const eventAttributes = computed(() => {
return eventList?.find(item => item.id === form.experiment_meta_event_id)?.attributes
})
// 提交
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
const attributes = eventAttributes.value?.reduce((a: any, b: any) => {
a[b.id] = b.value
return a
}, {})
console.log(eventList, '123attributes')
const [data] = eventAttributes.value || []
formEl.validate(valid => {
if (valid) {
if (props.data) {
const params = {
id: props.data?.id,
fields: attributes
}
updateEvent(params).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '更新成功', type: 'success' })
})
} else {
const params = {
experiment_member_id: route.query?.user_id as '',
experiment_meta_event_id: data.experiment_meta_event_id,
fields: attributes
}
createEvent(params).then(res => {
emit('update')
emit('update:modelValue', false)
ElMessage({ message: '创建成功', type: 'success' })
})
}
} else {
return false
}
})
}
</script>
<template>
......@@ -34,21 +93,49 @@ const rules = ref<FormRules>({
@update:modelValue="$emit('update:modelValue')"
>
<div class="update-event_info">
<span>姓名:王小二</span>
<span>来源链接:抖音</span>
<span>姓名:{{ props.info?.name }}</span>
<span>来源链接:{{ props.info?.connection_name }}</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
:disabled="props.data?.isView"
ref="formRef"
:model="form"
:rules="rules"
label-suffix=":"
label-width="122px"
>
<el-form-item label="请选择事件" prop="experiment_meta_event_id">
<el-select :disabled="!!props.data" v-model="form.experiment_meta_event_id" style="width: 100%">
<el-option v-for="item in eventList" :label="item.name" :value="item.id"></el-option>
</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 :label="item.name" v-for="item in eventAttributes">
<template v-if="item.type === '4' || item.type === '5'">
<el-date-picker
v-if="item.format === 'yyyy-mm-dd'"
v-model="item.value"
type="date"
placeholder="请选择"
style="width: 100%"
value-format="YYYY-MM-DD"
/>
<el-date-picker
value-format="YYYY-MM-DD HH:mm:ss"
v-else
v-model="item.value"
type="datetime"
placeholder="请选择"
style="width: 100%"
/>
</template>
<el-input v-else v-model="item.value" style="width: 100%" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(formRef)">提交</el-button>
<el-button @click="$emit('update:modelValue', false)">关闭</el-button>
</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">
......
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getEventList, importEvent } from '../api'
import type { EventProp } from '../types'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
const route = useRoute()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
event_id: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
event_id: [{ required: true, message: '请选择' }]
})
// 选择事件
let eventList = $ref<EventProp[]>()
onMounted(() => {
getEventList().then(res => {
eventList = res.data
})
})
const connectionName = computed(() => {
return eventList?.find((item: EventProp) => item.id === form.event_id)?.connection_name
})
// 下载数据模板
const downloadTemplate = function () {
if (form.event_id !== '')
window.open(
`/api/experiment/v1/experiment/member/event-download?event_id=${form.event_id}&experiment_id=${route.query.experiment_id}`
)
}
// 上传
const fetchFileUpload = (option: any) => {
return new Promise(() => {
importEvent({ event_id: form.event_id, file: option.file }).then(() => {
ElMessage.success('导入数据成功')
emit('update')
emit('update:modelValue', false)
// emit('update:isShowImportDialog', false)
// emit('create')
})
})
}
</script>
<template>
......@@ -35,24 +68,37 @@ const rules = ref<FormRules>({
@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 label="请选择事件" prop="event_id">
<el-select v-model="form.event_id" style="width: 100%">
<el-option v-for="item in eventList" :label="item.name" :value="item.id"></el-option>
</el-select>
<span v-if="connectionName">事件所属链接:{{ connectionName }}</span>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">下载事件数据模板</el-button>
<el-button type="primary">上传事件数据</el-button>
<el-button style="margin-right: 20px" type="primary" @click="downloadTemplate">下载事件数据模板</el-button>
<el-upload
class="upload-demo"
action="#"
multiple
ref="upload"
:auto-upload="true"
:limit="1"
:http-request="fetchFileUpload"
>
<el-button type="primary">上传事件数据</el-button>
</el-upload>
</div>
<div class="btn-box">
<el-button type="primary">关闭</el-button>
<!-- <el-button type="primary">上传事件数据</el-button> -->
<el-button type="primary" @click="$emit('update:modelValue', false)">关闭</el-button>
</div>
</el-dialog>
</template>
<style lang="scss">
.btn-box {
display: flex;
text-align: center;
margin-bottom: 20px;
justify-content: center;
}
</style>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getMemberConnectionsList, getMemberGroups, importMember } from '../api'
import type { ConnectionsProp } from '../types'
// interface Props {
// data?: UserProp
// }
// const props = defineProps<Props>()
defineEmits<{
const route = useRoute()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '',
value: '',
status: ''
connection_id: '',
groups_id: ''
})
const rules = ref<FormRules>({
type: [{ required: true, message: '请选择属性字段类型' }]
connection_id: [{ required: true, message: '请选择' }]
})
// 链接列表
let connectionList = $ref<ConnectionsProp[]>()
// 群组列表
let groupList = $ref<{ name: string; id: string }[]>()
onMounted(() => {
getMemberConnectionsList().then(res => {
connectionList = res.data
})
getMemberGroups().then(res => {
groupList = res.data
})
})
// 下载数据模板
const downloadTemplate = function () {
window.open(`/api/experiment/v1/experiment/member/member-download?experiment_id=${route.query.experiment_id}`)
}
// 上传
const fetchFileUpload = (option: any) => {
return new Promise(() => {
const params = Object.assign(form, { file: option.file })
importMember(params).then(() => {
ElMessage.success('导入数据成功')
emit('update')
emit('update:modelValue', false)
// emit('update:isShowImportDialog', false)
// emit('create')
})
})
}
</script>
<template>
......@@ -35,16 +68,30 @@ const rules = ref<FormRules>({
@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 label="请选择所属链接" prop="connection_id">
<el-select v-model="form.connection_id" style="width: 100%">
<el-option v-for="item in connectionList" :label="item.type_name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="请选择静态群组">
<el-select v-model="form.id" style="width: 100%"></el-select>
<el-select v-model="form.groups_id" style="width: 100%">
<el-option v-for="item in groupList" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button type="primary">下载用户数据模板</el-button>
<el-button type="primary">上传用户数据</el-button>
<el-button style="margin-right: 20px" type="primary" @click="downloadTemplate">下载用户数据模板</el-button>
<el-upload
class="upload-demo"
action="#"
multiple
ref="upload"
:auto-upload="true"
:limit="1"
:http-request="fetchFileUpload"
>
<el-button type="primary">上传用户数据</el-button>
</el-upload>
</div>
<div class="btn-box">
<el-button type="primary">关闭</el-button>
......@@ -56,5 +103,7 @@ const rules = ref<FormRules>({
.btn-box {
text-align: center;
margin-bottom: 20px;
display: flex;
justify-content: center;
}
</style>
......@@ -7,7 +7,8 @@ const routes: RouteRecordRaw[] = [
component: Layout,
children: [
{ path: '', component: () => import('./views/Index.vue') },
{ path: 'eventDetails', component: () => import('./views/EventDetails.vue') }
{ path: 'eventDetails', component: () => import('./views/EventDetails.vue') },
{ path: 'image', component: () => import('./views/Image.vue') }
]
}
]
......
export interface ConnectionsProp {
id: string
type: string
type_name: string
}
export interface MemberFieldsProp {
id: string
name: string
english_name: string
type: string
type_name: string
format: string
value: string
isShow: boolean
}
export interface MemberProp {
id: string
name: string
status: string
experiment_connection_id: string
gender: string
mobile: string
fields: string
isView?: boolean
connection_name: string
status_name: string
}
export interface EventProp {
name: string
id: string
attributes: AttributesProp[]
connection_name: string
}
export interface AttributesProp {
name: string
id: string
type: string
format: string
value: string
experiment_meta_event_id: string
fields: string
connection_id: string
isView: boolean
}
export interface ImageProp {
tag: string[]
static_groups: string[]
dynamic_groups: string[]
events: {
list: {
updated_time: string
connection_type: string
connection_name: string
event_name: string
}[]
}
}
<script setup lang="ts">
import { Plus, Download, Upload, Delete } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue'
import UpdateEventsDialog from '../components/UpdateEventsDialog.vue'
import { getMemberEventList, deleteEvent } from '../api'
import type { MemberProp, AttributesProp } from '../types'
const route = useRoute()
const appList = $ref<InstanceType<typeof AppList> | null>(null)
let userInfo = $ref<MemberProp>()
// 列表配置
const listOptions = computed(() => {
return {
remote: {
httpRequest: getMemberEventList,
params: { id: route.query.user_id },
callback: (data: any) => {
userInfo = data
return data.events
}
},
columns: [
{ label: '序号', type: 'index', width: 60 },
{ label: '事件名称', prop: 'id' },
{ label: '链接名称', prop: 'name' },
{ label: '事件发生时间', prop: 'name' },
{ label: '事件名称', prop: 'event_name' },
{ label: '链接名称', prop: 'connection_name' },
{ label: '事件发生时间', prop: 'created_time' },
{ label: '操作', slots: 'table-x', width: 380 }
],
data: [{}, {}]
]
}
})
......@@ -24,32 +38,69 @@ function handleRefresh() {
}
// 事件弹窗
const eventsVisible = $ref(false)
let eventsVisible = $ref(false)
// 编辑
let currentRow = $ref<AttributesProp>()
const handleEdit = function (row: AttributesProp) {
row.isView = false
currentRow = row
eventsVisible = true
}
// 删除
function handleRemove(row: AttributesProp) {
ElMessageBox.confirm('确定要删除该属性吗?', '提示').then(() => {
deleteEvent({ id: row.id }).then(res => {
ElMessage({ message: '删除成功', type: 'success' })
handleRefresh()
})
})
}
// 新建
const handleAdd = function () {
currentRow = undefined
eventsVisible = true
}
// 查看
const handleView = function (row: AttributesProp) {
row.isView = true
currentRow = row
eventsVisible = true
}
</script>
<template>
<AppCard title="用户事件数据">
<div class="event-user_info">
<span>姓名:王小二</span>
<span>id:11111</span>
<span>来源链接:抖音</span>
<span>状态:生效</span>
<span>姓名:{{ userInfo?.name }}</span>
<span>id:{{ userInfo?.id }}</span>
<span>来源链接:{{ userInfo?.connection_name }}</span>
<span>状态:{{ userInfo?.status_name }}</span>
</div>
</AppCard>
<AppCard>
<AppList v-bind="listOptions" ref="appList">
<template #header-buttons>
<el-button type="primary" :icon="Plus" @click="eventsVisible = true">新建用户事件</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">新建用户事件</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 #table-x="{ row }">
<el-button type="primary" plain @click="handleView(row)">查看</el-button>
<el-button type="primary" plain @click="handleEdit(row)">编辑</el-button>
<el-button type="primary" plain @click="handleRemove(row)">删除</el-button>
</template>
</AppList>
</AppCard>
<!-- 新建更新事件 -->
<UpdateEventsDialog v-model="eventsVisible"></UpdateEventsDialog>
<UpdateEventsDialog
@update="handleRefresh()"
:data="currentRow"
v-if="eventsVisible"
:info="userInfo"
v-model="eventsVisible"
></UpdateEventsDialog>
</template>
<style lang="scss">
.event-user_info {
......
<script setup lang="ts">
import { getMemberImage, getMemberFieldsList } from '../api'
import type { MemberFieldsProp, ImageProp } from '../types'
import Icon from '../components/Icon.vue'
const route = useRoute()
// 画像数据
let data = $ref<ImageProp>()
// 属性
let fieldsList = $ref<MemberFieldsProp[]>()
onMounted(() => {
// 画像
getMemberImage({ id: route.query.user_id as '' }).then(res => {
data = res.data
getFields(res.data)
})
// 属性
})
const getFields = function (data: { fields: any }) {
getMemberFieldsList().then(res => {
// fieldsList = res.data
fieldsList = res.data.map((item: MemberFieldsProp) => {
if (data.fields[item.id]) {
item.value = data.fields[item.id]
item.isShow = true
}
return item
})
})
}
// 获取上下午
const getDate = function (date: string) {
return parseInt(date.slice(date.indexOf(' '), date.indexOf(' ') + 3)) > 12 ? '下午' : '上午'
}
</script>
<template>
<div class="card-box">
<AppCard class="card" title="用户属性">
<div style="display: flex; justify-content: center; padding-right: 20px">
<el-form label-suffix=":" label-width="110px">
<template v-for="item in fieldsList">
<el-form-item v-if="item?.isShow" :label="item?.name"
><span>{{ item?.value }}</span></el-form-item
>
</template>
</el-form>
</div>
</AppCard>
<AppCard class="card" title="标签与群组">
<el-tabs class="demo-tabs">
<el-tab-pane label="用户标签">
<div class="scroll">
<el-tag class="ml-2" type="success" v-for="item in data?.tag">{{ item }}</el-tag>
</div>
</el-tab-pane>
</el-tabs>
<el-tabs class="demo-tabs">
<el-tab-pane label="静态分组">
<div class="scroll">
<el-tag class="ml-2" type="success" v-for="item in data?.static_groups">{{ item }}</el-tag>
</div>
</el-tab-pane>
</el-tabs>
<el-tabs class="demo-tabs">
<el-tab-pane label="动态分组">
<div class="scroll">
<el-tag class="ml-2" type="success" v-for="item in data?.dynamic_groups">{{ item }}</el-tag>
</div>
</el-tab-pane>
</el-tabs>
</AppCard>
<AppCard class="card" title="用户行为轨迹">
<div class="event-box" v-for="item in data?.events?.list">
<div class="date">{{ item.updated_time?.slice(0, item.updated_time.indexOf(' ')) }}</div>
<div class="event-content">
<div class="time">
{{ item.updated_time?.slice(item.updated_time.indexOf(' '), item.updated_time.length - 3) }}
{{ getDate(item.updated_time) }}
</div>
<Icon class="icon" :name="item.connection_type" w="30" h="30"></Icon>
<div class="event">
<span>"{{ item.connection_name }}"</span><span>"{{ item.event_name }}"</span>
</div>
</div>
</div>
<div class="event-box" v-for="item in data?.events?.list">
<div class="date">{{ item.updated_time?.slice(0, item.updated_time.indexOf(' ')) }}</div>
<div class="event-content">
<div class="time">
{{ item.updated_time?.slice(item.updated_time.indexOf(' '), item.updated_time.length - 3) }}
{{ getDate(item.updated_time) }}
</div>
<Icon class="icon" :name="item.connection_type" w="30" h="30"></Icon>
<div class="event">
<span>"{{ item.connection_name }}"</span><span>"{{ item.event_name }}"</span>
</div>
</div>
</div>
</AppCard>
</div>
</template>
<style lang="scss">
.ml-2 {
margin-right: 10px;
}
.card-box {
display: flex;
.card {
flex: 1;
margin-top: 0;
height: 90vh;
margin-right: 10px;
.demo-tabs {
height: 26vh;
}
}
}
.event-box {
border-bottom: 1px solid #ccc;
padding: 20px 0 5px;
.date {
font-size: 14px;
}
}
.event-content {
display: flex;
font-size: 12px;
align-items: center;
// margin-bottom: 20px;
flex-wrap: wrap;
.time {
color: #ccc;
}
.icon {
margin: 0 5px;
}
span {
color: #ba143e;
font-weight: bold;
}
}
</style>
<script setup lang="ts">
import { Plus, Download, Upload, Delete } from '@element-plus/icons-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'
import { getMemberList, deleteMember } from '../api'
import { ElMessage } from 'element-plus'
import type { MemberProp } from '../types'
const UpdateDialog = defineAsyncComponent(() => import('../components/UpdateDialog.vue'))
const UploadEventsDialog = defineAsyncComponent(() => import('../components/UploadEventsDialog.vue'))
const UploadUserDialog = defineAsyncComponent(() => import('../components/UploadUserDialog.vue'))
const router = useRouter()
const route = useRoute()
const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置
const listOptions = computed(() => {
return {
filters: [{ type: 'input', prop: 'name', placeholder: '请输入用户姓名' }],
remote: {
httpRequest: getMemberList,
params: { name: '', id: '', mobile: '', status: '' }
},
filters: [
{ type: 'input', prop: 'name', placeholder: '请输入用户姓名' },
{ type: 'input', prop: 'id', placeholder: '请输入用户ID' },
{ type: 'input', prop: 'mobile', placeholder: '请输入用户手机号' },
{
type: 'select',
prop: 'status',
placeholder: '请选择生效状态',
options: [
{ label: '有效', value: '1' },
{ label: '失效', value: '0' }
]
}
],
columns: [
{ type: 'selection' },
{ label: '序号', type: 'index', width: 60 },
{ label: '用户ID', prop: 'id' },
{ label: '姓名', prop: 'name' },
{ label: '性别', prop: 'name' },
{ label: '手机号码', prop: 'name' },
{ label: '来源连接', prop: 'name' },
{ label: '状态', prop: 'name' },
{ label: '更新人', prop: 'name' },
{ label: '更新时间', prop: 'name' },
{ label: '性别', prop: 'gender_name' },
{ label: '手机号码', prop: 'mobile' },
{ label: '来源连接', prop: 'connection_name' },
{ label: '状态', prop: 'status_name' },
{ label: '更新人', prop: 'updated_operator_name' },
{ label: '更新时间', prop: 'updated_time' },
{ label: '操作', slots: 'table-x', width: 380 }
],
data: [{}, {}]
]
}
})
......@@ -40,21 +63,99 @@ const eventsVisible = $ref(false)
const userVisible = $ref(false)
// 新建、更新、查看
const updateVisible = $ref(false)
let updateVisible = $ref(false)
let multipleSelection = $ref<MemberProp[]>([])
function handleSelectionChange(selection: MemberProp[]) {
multipleSelection = selection
}
// 删除
const handleRemove = function (row: { id: string }) {
deleteMembers(row.id)
}
const handleRemoves = function () {
const ids = multipleSelection
.reduce((a: any, b: any) => {
a.push(b.id)
return a
}, [])
.toString()
deleteMembers(ids)
}
const deleteMembers = function (ids: string) {
deleteMember({ ids: ids }).then(res => {
ElMessage({ message: '删除成功', type: 'success' })
handleRefresh()
})
}
// 编辑
let currentRow = ref<MemberProp>()
const handleEdit = function (row: MemberProp) {
currentRow.value = row
row.isView = false
updateVisible = true
}
// 查看
const handleView = function (row: MemberProp) {
row.isView = true
currentRow.value = row
updateVisible = true
}
// 新建
const handleAdd = function () {
updateVisible = true
currentRow.value = undefined
}
// 事件详情页
const goPage = function (row: MemberProp) {
router.push({
path: '/user/eventDetails',
query: { user_id: row.id }
})
}
// 画像
const handleImage = function (row: MemberProp) {
router.push({
path: '/user/image',
query: { user_id: row.id }
})
}
// 导出用户
const downloadMember = function (isAll?: boolean) {
const ids = multipleSelection
.reduce((a: any, b: any) => {
a.push(b.id)
return a
}, [])
.toString()
if (isAll) {
window.open(`/api/experiment/v1/experiment/member/download?experiment_id=${route.query.experiment_id}`)
} else {
window.open(`/api/experiment/v1/experiment/member/download?experiment_id=${route.query.experiment_id}&ids=${ids}`)
}
}
</script>
<template>
<AppCard>
<AppList v-bind="listOptions" ref="appList">
<AppList v-bind="listOptions" ref="appList" @selection-change="handleSelectionChange">
<template #header-buttons>
<el-space>
<el-button type="primary" :icon="Plus">新建</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button>
<el-dropdown>
<el-button type="primary" :icon="Download">导出</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>全部用户数据</el-dropdown-item>
<el-dropdown-item>勾选用户数据</el-dropdown-item>
<el-dropdown-item @click="downloadMember(true)">全部用户数据</el-dropdown-item>
<el-dropdown-item @click="downloadMember(false)">勾选用户数据</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
......@@ -67,22 +168,24 @@ const updateVisible = $ref(false)
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button type="danger" plain :icon="Delete">删除</el-button>
<el-button type="danger" plain :icon="Delete" :disabled="!multipleSelection.length" @click="handleRemoves()"
>删除</el-button
>
</el-space>
</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>
<el-button type="primary" plain>删除</el-button>
<el-button type="primary" plain>事件</el-button>
<template #table-x="{ row }">
<el-button type="primary" plain @click="handleImage(row)">画像</el-button>
<el-button type="primary" plain @click="handleView(row)">查看</el-button>
<el-button type="primary" plain @click="handleEdit(row)">编辑</el-button>
<el-button type="primary" plain @click="handleRemove(row)">删除</el-button>
<el-button type="primary" plain @click="goPage(row)">事件</el-button>
</template>
</AppList>
</AppCard>
<!-- 导入事件弹窗 -->
<UploadEventsDialog v-model="eventsVisible"></UploadEventsDialog>
<UploadEventsDialog @update="handleRefresh" v-if="eventsVisible" v-model="eventsVisible"></UploadEventsDialog>
<!-- 导入用户弹窗 -->
<UploadUserDialog v-model="userVisible"></UploadUserDialog>
<UploadUserDialog @update="handleRefresh" v-if="userVisible" v-model="userVisible"></UploadUserDialog>
<!-- 新建、更新、查看 -->
<UpdateDialog v-model="updateVisible"></UpdateDialog>
<UpdateDialog v-if="updateVisible" :data="currentRow" v-model="updateVisible" @update="handleRefresh"></UpdateDialog>
</template>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论