feat(首页): 添加神策数据埋点
- 在 Header 组件中添加 Banner 点击埋点 - 在 ModelCard 组件中添加 模型介绍点击 埋点 - 在 Operating 组件中添加 操作指引 埋点 - 在 Scene 组件中添加 创建问卷 埋点 - 优化了埋点数据的结构和命名
This commit is contained in:
22
src/App.vue
22
src/App.vue
@@ -5,16 +5,8 @@
|
||||
<div class="link-action-wrapper" @click="clickAction">
|
||||
<router-view />
|
||||
</div>
|
||||
<a-modal
|
||||
centered
|
||||
:width="700"
|
||||
:visible="show"
|
||||
:title="title"
|
||||
:maskClosable="true"
|
||||
:closable="true"
|
||||
wrapClassName="custom-modal"
|
||||
:footer="null"
|
||||
>
|
||||
<a-modal centered :width="700" :visible="show" :title="title" :maskClosable="true" :closable="true"
|
||||
wrapClassName="custom-modal" :footer="null">
|
||||
<template #closeIcon>
|
||||
<i class="iconfont model-close" @click="show = false"></i>
|
||||
</template>
|
||||
@@ -26,7 +18,7 @@
|
||||
<script>
|
||||
import locale from 'ant-design-vue/es/locale/zh_CN';
|
||||
import 'moment/locale/zh-cn';
|
||||
import { watch, onMounted,onUnmounted, ref } from 'vue';
|
||||
import { watch, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
import Loading from '@/components/layout/loading/Loading.vue';
|
||||
@@ -56,7 +48,7 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
console.log(route);
|
||||
// console.log(route);
|
||||
const setToken = () => {
|
||||
if (!!route.query.token) {
|
||||
localStorage.setItem('plantToken', route.query.token);
|
||||
@@ -117,6 +109,7 @@ export default {
|
||||
* {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -139,12 +132,15 @@ div {
|
||||
.vxe-table--body-wrapper {
|
||||
@extend .scroller;
|
||||
}
|
||||
|
||||
.ant-table-header,
|
||||
.ant-table-hide-scrollbar {
|
||||
padding-right: 6px !important;
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
|
||||
html,
|
||||
body {
|
||||
& *:not(svg, p, strong, em, p span, label) {
|
||||
@@ -161,6 +157,7 @@ div {
|
||||
// }
|
||||
/*<=600的设备*/
|
||||
@media (max-width: 600px) {
|
||||
|
||||
html,
|
||||
body {
|
||||
& *:not(p, strong, em, p span, label) {
|
||||
@@ -168,6 +165,7 @@ div {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
// font-family: "Noto Sans CJK SC Medium", "Source Han Sans CN Medium" !important;
|
||||
font-weight: bolder !important;
|
||||
|
||||
31
src/main.js
31
src/main.js
@@ -78,34 +78,5 @@ installAntDesign(app);
|
||||
app.config.globalProperties.emitter = emitter;
|
||||
|
||||
// 神策数据插件
|
||||
app.use(sensorsData(), {
|
||||
// 单页面配置,默认关闭。开启后自动监听 URL 有变化就会触发 $pageview 事件
|
||||
is_track_single_page: function () {
|
||||
return false;
|
||||
},
|
||||
scrollmap: {
|
||||
// Web 视区停留
|
||||
collect_url: function () {
|
||||
function isCollectUrl(urls) {
|
||||
return urls.some((url) => location.href.includes(url));
|
||||
}
|
||||
|
||||
// 需要采集的页面
|
||||
const urls = ['/ad/', '/share/'];
|
||||
console.log(`collect_url`, isCollectUrl(urls));
|
||||
|
||||
// return isCollectUrl(urls);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
heatmap: {
|
||||
//是否开启触达图,default 表示开启,自动采集 $WebStay 事件,可以设置 'not_collect' 表示关闭。
|
||||
//需要 Web JS SDK 版本号大于 1.9.1
|
||||
scroll_notice_map: 'default',
|
||||
scroll_delay_time: 4000,
|
||||
//单位秒,预置属性停留时长 event_duration 的最大值。默认5个小时,也就是300分钟,18000秒。
|
||||
scroll_event_duration: 18000,
|
||||
get_vtrack_config: true
|
||||
}
|
||||
});
|
||||
app.use(sensorsData(), {});
|
||||
app.use(store).use(router).mount('#app');
|
||||
|
||||
@@ -12,7 +12,11 @@ import { jsonpUrl } from '../config.js';
|
||||
import { useStore } from 'vuex';
|
||||
import Creative from './route.creative'; // 创作中心路由
|
||||
import MarketList from '@/views/TempMarket/components/TempMarketLayout';
|
||||
import { sensors } from '@/utils/plugins/sa';
|
||||
|
||||
const sa = {
|
||||
register: false,
|
||||
instance: window.sa || null
|
||||
};
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -617,33 +621,23 @@ const router = createRouter({
|
||||
routes: constantRoutes
|
||||
});
|
||||
|
||||
let pageStayTime = 0;
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
// 离开页面的时候结束记录时间
|
||||
const duration = Date.now() - pageStayTime;
|
||||
pageStayTime = 0;
|
||||
|
||||
const collectUrl = ['/ad/', '/share/'];
|
||||
console.log(
|
||||
`is collect page`,
|
||||
collectUrl.some((url) => from.path.startsWith(url))
|
||||
);
|
||||
|
||||
// 判断是否离开需要采集的页面
|
||||
if (true) {
|
||||
// if (collectUrl.some((url) => from.path.startsWith(url))) {
|
||||
// alert(`duration: ${duration}`);
|
||||
sensors.track('pageStayTime', {
|
||||
duration
|
||||
});
|
||||
}
|
||||
|
||||
if (to.meta?.title) document.title = to.meta.title;
|
||||
|
||||
// token
|
||||
if (!to.meta.shared && !router.options.history.state.back) {
|
||||
await getToken();
|
||||
}
|
||||
|
||||
// 神策数据埋点
|
||||
if (!sa.register && localStorage.getItem('plantUserInfo')) {
|
||||
sa.instance = window.sa;
|
||||
// 检测是否使用神策的登陆
|
||||
const userInfo = JSON.parse(localStorage.getItem('plantUserInfo'));
|
||||
const loginID = `id-${userInfo.id}.login_team_id-${userInfo.login_team_id}`;
|
||||
|
||||
sa.instance.login(globalThis.btoa(loginID));
|
||||
sa.register = true;
|
||||
}
|
||||
|
||||
if (!to.meta.noRedirectLogin) {
|
||||
if (window.self === window.top) {
|
||||
// window.parent.location.href = 'https://yip-uat.dctest.digitalyili.com/login';
|
||||
@@ -662,10 +656,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
router.afterEach((to, from) => {
|
||||
// 页面导航结束的时候开始记录时间
|
||||
pageStayTime = Date.now();
|
||||
});
|
||||
// router.afterEach((to, from) => {
|
||||
// // 页面导航结束的时候开始记录时间
|
||||
// pageStayTime = Date.now();
|
||||
// });
|
||||
|
||||
const getToken = async () => {
|
||||
try {
|
||||
|
||||
@@ -21,13 +21,17 @@ export function sensorsData() {
|
||||
|
||||
// 注册页面公共属性
|
||||
sensors.registerPage({
|
||||
platform: 'h5',
|
||||
platform: 'pc',
|
||||
// 产品名称
|
||||
production_name: 'ylst',
|
||||
current_url: location.href,
|
||||
referrer: document.referrer
|
||||
});
|
||||
|
||||
// 提供全局注入的 sensors 实例
|
||||
app.provide('sensors', sensors);
|
||||
// 注册到window中
|
||||
globalThis.sa = sensors;
|
||||
|
||||
// 注册 saTrack 自定义指令
|
||||
registerDirective(app);
|
||||
@@ -40,17 +44,26 @@ export function sensorsData() {
|
||||
* @param {App} app - Vue 应用实例
|
||||
*/
|
||||
function registerDirective(app) {
|
||||
function bindTrackListener(binding) {
|
||||
return () => {
|
||||
const { arg: eventName, value: properties } = binding;
|
||||
|
||||
if (eventName) {
|
||||
sensors.track(eventName, properties);
|
||||
console.warn(properties);
|
||||
} else {
|
||||
console.warn('[sensorsData] 事件名未提供');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
app.directive('saTrack', {
|
||||
mounted(el, binding) {
|
||||
el.addEventListener('click', () => {
|
||||
const { arg: eventName, value: properties } = binding;
|
||||
|
||||
if (eventName) {
|
||||
sensors.track(eventName, properties);
|
||||
} else {
|
||||
console.warn('[sensorsData] 事件名未提供');
|
||||
}
|
||||
});
|
||||
el.addEventListener('click', bindTrackListener(binding));
|
||||
},
|
||||
unmounted(el, binding) {
|
||||
// 清除绑定的事件
|
||||
el.removeEventListener('click', bindTrackListener(binding));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<layout>
|
||||
<template v-slot:top>
|
||||
<div class="left" >
|
||||
<div class="left">
|
||||
<i class="iconfont icon-xiangzuo-moren" @click="back"></i>
|
||||
{{ bannerInfo.title }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<div class="detail">
|
||||
<p class="fw-900">{{bannerInfo.title}}</p>
|
||||
<p class="fs-14 time">伊调研 | {{bannerInfo.publish_time}}</p>
|
||||
<p class="fw-900">{{ bannerInfo.title }}</p>
|
||||
<p class="fs-14 time">伊调研 | {{ bannerInfo.publish_time }}</p>
|
||||
<!--文字-->
|
||||
<p v-if="bannerInfo.type === 0">
|
||||
<p v-html="bannerInfo.characters"></p>
|
||||
<p v-html="bannerInfo.characters"></p>
|
||||
</p>
|
||||
<!--图片-->
|
||||
<img v-if="bannerInfo.type === 1" :src="bannerInfo.file_address" alt="" style="width: 100%;">
|
||||
@@ -25,14 +25,11 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- <video v-if="bannerInfo.type === 2" :src="bannerInfo.file_address" style="width: 100%;"></video>-->
|
||||
<!-- <video v-if="bannerInfo.type === 2" :src="bannerInfo.file_address" style="width: 100%;"></video>-->
|
||||
|
||||
<div v-if="bannerInfo.is_display_button" class="jump">
|
||||
<a-button
|
||||
type="primary"
|
||||
class="custom-button mr-12"
|
||||
@click="toJump">
|
||||
<span>{{ bannerInfo.button_name }}</span>
|
||||
<div class="jump">
|
||||
<a-button type="primary" class="custom-button mr-12" @click="toJump">
|
||||
<span>{{ bannerInfo.button_name }}12312312</span>
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,10 +40,9 @@
|
||||
|
||||
<script setup>
|
||||
import Layout from '@/views/ProjectManage/components/Layout.vue';
|
||||
import {onMounted,ref} from 'vue';
|
||||
import { useRouter,useRoute } from 'vue-router';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { queryBanner } from '@/api/home';
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const bannerInfo = ref({});
|
||||
@@ -56,12 +52,12 @@ onMounted(() => {
|
||||
});
|
||||
const getBannerDetail = () => {
|
||||
console.log(route.query);
|
||||
queryBanner({ code: route.query.code}).then(res=>{
|
||||
queryBanner({ code: route.query.code }).then(res => {
|
||||
console.log(res.data);
|
||||
bannerInfo.value = res.data
|
||||
})
|
||||
};
|
||||
const toJump = ()=>{
|
||||
const toJump = () => {
|
||||
// router.push({
|
||||
// path: bannerInfo.value.url
|
||||
// })
|
||||
@@ -73,12 +69,14 @@ const back = () => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail{
|
||||
.detail {
|
||||
padding: 10px 20%;
|
||||
.time{
|
||||
|
||||
.time {
|
||||
color: #7F7F7F;
|
||||
}
|
||||
.jump{
|
||||
|
||||
.jump {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { onBeforeUnmount, onMounted, ref, inject } from 'vue';
|
||||
import Swiper, { Autoplay } from 'swiper';
|
||||
import 'swiper/swiper-bundle.css';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -85,6 +85,7 @@ const surveyData = ref({
|
||||
})
|
||||
const bannerList = ref([])
|
||||
|
||||
const sensors = inject('sensors')
|
||||
// 获取数据
|
||||
const getBannerData = async () => {
|
||||
const res = await getBannerList()
|
||||
@@ -168,6 +169,9 @@ const goToSlide = (index) => {
|
||||
}
|
||||
// 方法
|
||||
const toBannerDetail = (item) => {
|
||||
// 神策埋点
|
||||
saTrack(item)
|
||||
|
||||
router.push({
|
||||
path: '/home/bannerDetail',
|
||||
query: {
|
||||
@@ -189,6 +193,21 @@ onBeforeUnmount(() => {
|
||||
bannerSwiper = null
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function saTrack(record) {
|
||||
const config = {
|
||||
eventName: "ClickBanner",
|
||||
properties: {
|
||||
page: "首页",
|
||||
module: "Banner",
|
||||
position: "查看详情",
|
||||
title: record.code,
|
||||
clickTime: new Date().toLocaleString().toString()
|
||||
}
|
||||
}
|
||||
sensors.track(config.eventName, config.properties);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<template>
|
||||
<div class="model-item"
|
||||
@mouseover="hoverIndex = index"
|
||||
@mouseleave="hoverIndex = -1"
|
||||
:style="{ backgroundImage: `url(${model.backgroundImage})` }">
|
||||
<div class="model-item" @mouseover="hoverIndex = index" @mouseleave="hoverIndex = -1"
|
||||
:style="{ backgroundImage: `url(${model.backgroundImage})` }">
|
||||
<div class="flex align-items-center">
|
||||
<img :src="model.image" alt="" style="height: 23px; margin-right: 8px" />
|
||||
<p class="model-item-title">{{ model.title }}</p>
|
||||
</div>
|
||||
<p class="model-item-desc">{{ model.description }}</p>
|
||||
<div
|
||||
class="view-link"
|
||||
@click="$emit('open')">
|
||||
<span>{{ getText(model,index) }}</span>
|
||||
<div class="view-link" @click="handleModelClick">
|
||||
<span>{{ getText(model, index) }}</span>
|
||||
<img v-if="hoverIndex === index && index !== 3" src="@/assets/img/home/tob.png" alt="">
|
||||
<img v-else src="@/assets/img/home/tow.png" alt="">
|
||||
</div>
|
||||
@@ -19,9 +15,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, inject } from 'vue'
|
||||
const hoverIndex = ref(-1);
|
||||
defineProps({
|
||||
const { model,index } = defineProps({
|
||||
model: {
|
||||
type: Object,
|
||||
required: true
|
||||
@@ -30,12 +26,35 @@ defineProps({
|
||||
type: Number,
|
||||
}
|
||||
})
|
||||
const getText = (model,index) => {
|
||||
|
||||
const emit = defineEmits(['open'])
|
||||
const sensors = inject('sensors')
|
||||
const getText = (model, index) => {
|
||||
if (hoverIndex.value === index) {
|
||||
return model.sort === 103 ? "敬请期待" : "去查看";
|
||||
}
|
||||
return "去查看";
|
||||
}
|
||||
|
||||
function handleModelClick() {
|
||||
emit('open')
|
||||
console.log(model);
|
||||
|
||||
saTrack(model)
|
||||
function saTrack(record) {
|
||||
const config = {
|
||||
eventName: "IntroduceModel",
|
||||
properties: {
|
||||
page: "首页",
|
||||
module: "模型介绍",
|
||||
position: record.title,
|
||||
buttonName: "去查看",
|
||||
clickTime: new Date().toLocaleString().toString()
|
||||
}
|
||||
}
|
||||
sensors.track(config.eventName, config.properties);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -99,6 +118,7 @@ p {
|
||||
// color: #3976D7;
|
||||
//}
|
||||
}
|
||||
|
||||
.model-item:hover {
|
||||
.view-link {
|
||||
background: #fff;
|
||||
@@ -113,13 +133,14 @@ p {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
& span {
|
||||
color: #3976D7;
|
||||
}
|
||||
}
|
||||
|
||||
.icon{
|
||||
fill:#fff;
|
||||
color:#fff;
|
||||
.icon {
|
||||
fill: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,58 +2,46 @@
|
||||
<div class="operating-container">
|
||||
<div class="top">
|
||||
<p class="fw-bold fs-24 title">简单4步,轻松完成你的调研</p>
|
||||
<!-- <p class="desc">创建、编辑、投放、分析,让洞察更简单</p>-->
|
||||
<!-- <p class="desc">创建、编辑、投放、分析,让洞察更简单</p>-->
|
||||
</div>
|
||||
<div style="height: 80%">
|
||||
<div class="swiper-container" ref="swiperContainer">
|
||||
<div class="swiper-wrapper">
|
||||
<div
|
||||
v-for="(item, index) in operatingList"
|
||||
:key="index"
|
||||
class="swiper-slide"
|
||||
>
|
||||
<div v-for="(item, index) in operatingList" :key="index" class="swiper-slide">
|
||||
<div class="flex" style="justify-content: center">
|
||||
<div style="margin-right: 9%">
|
||||
<div class="flex-start operating-item" >
|
||||
<p class="progress" :style="{'color':item.btnColor}">
|
||||
<span class="fs-36">
|
||||
{{index+1}}
|
||||
</span>
|
||||
<div class="flex-start operating-item">
|
||||
<p class="progress" :style="{ 'color': item.btnColor }">
|
||||
<span class="fs-36">
|
||||
{{ index + 1 }}
|
||||
</span>
|
||||
<img src="@/assets/img/home/xiegang.png" alt="">
|
||||
<span>
|
||||
{{operatingList.length}}
|
||||
</span>
|
||||
{{ operatingList.length }}
|
||||
</span>
|
||||
</p>
|
||||
<div class="info">
|
||||
<p>{{item.title}}</p>
|
||||
<p>{{item.desc}}</p>
|
||||
<p>{{ item.title }}</p>
|
||||
<p>{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="desc-item">
|
||||
<li class="flex" v-for="(tips,index) in item.descList" :key="index">
|
||||
<li class="flex" v-for="(tips, index) in item.descList" :key="index">
|
||||
<p class="block"></p>
|
||||
{{tips}}
|
||||
{{ tips }}
|
||||
<span class="fs-12 tag" v-if="index === 0 && item.isShowTag">
|
||||
新功能
|
||||
</span>
|
||||
新功能
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<a-button type="primary" @click="toSurveyInfo(item,index)">
|
||||
<a-button type="primary" @click="toSurveyInfo(item, index)">
|
||||
立即体验
|
||||
<img src="@/assets/img/home/tow.png" alt=""
|
||||
style="margin-left: 5px;margin-bottom: 2px">
|
||||
<img src="@/assets/img/home/tow.png" alt="" style="margin-left: 5px;margin-bottom: 2px">
|
||||
</a-button>
|
||||
</div>
|
||||
<div>
|
||||
<video
|
||||
ref="videoPlayer"
|
||||
class="video-player"
|
||||
width="820"
|
||||
height="420"
|
||||
autoplay
|
||||
muted
|
||||
playsinline
|
||||
style="width: 100%;">
|
||||
<video ref="videoPlayer" class="video-player" width="820" height="420" autoplay muted playsinline
|
||||
style="width: 100%;">
|
||||
|
||||
<source :src="getVideo(index)" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
@@ -79,7 +67,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {ref, onMounted, onBeforeUnmount} from 'vue'
|
||||
import { ref, onMounted, onBeforeUnmount, inject } from 'vue'
|
||||
import Swiper from 'swiper';
|
||||
import 'swiper/swiper-bundle.css';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -100,42 +88,44 @@ const nextImg = ref(null);
|
||||
let mySwiper = null;
|
||||
|
||||
const operatingList = [
|
||||
{
|
||||
title: '多种方式',
|
||||
desc:'快速创建问卷',
|
||||
descList:[
|
||||
'一句话AI生成问卷,高效智能','20+专业场景模板,快速创建','WORD模板上传,一键导入','空白创建编辑,灵活简单'
|
||||
],
|
||||
btnColor:'green',
|
||||
isShowTag:true
|
||||
},
|
||||
{
|
||||
title: '多种方式',
|
||||
desc: '快速创建问卷',
|
||||
descList: [
|
||||
'一句话AI生成问卷,高效智能', '20+专业场景模板,快速创建', 'WORD模板上传,一键导入', '空白创建编辑,灵活简单'
|
||||
],
|
||||
btnColor: 'green',
|
||||
isShowTag: true
|
||||
},
|
||||
{
|
||||
title: '编辑质检',
|
||||
desc:'设计快速搞定',
|
||||
descList:[
|
||||
'30+专业题型及模型题组,多种逻辑适配各类场景','AI多维度问卷质检,快速识别问题提供建议',
|
||||
desc: '设计快速搞定',
|
||||
descList: [
|
||||
'30+专业题型及模型题组,多种逻辑适配各类场景', 'AI多维度问卷质检,快速识别问题提供建议',
|
||||
'多种主题、九宫格抽奖, 自定义问卷风格', '多人协作编辑,便捷协同快捷高效'
|
||||
],
|
||||
btnColor:'green',
|
||||
key:'design'
|
||||
},{
|
||||
btnColor: 'green',
|
||||
key: 'design'
|
||||
}, {
|
||||
title: '精准触达',
|
||||
desc:'投放轻松高效',
|
||||
descList:[
|
||||
'多元样本资源精准圈选,在线一站式投放','标准链接及二维码,问卷快捷私发群发','自定义链接参数,记录多渠道样本来源','回收进度、配额进度在线实时追踪'
|
||||
desc: '投放轻松高效',
|
||||
descList: [
|
||||
'多元样本资源精准圈选,在线一站式投放', '标准链接及二维码,问卷快捷私发群发', '自定义链接参数,记录多渠道样本来源', '回收进度、配额进度在线实时追踪'
|
||||
],
|
||||
btnColor:'green',
|
||||
key:'accurate'
|
||||
},{
|
||||
btnColor: 'green',
|
||||
key: 'accurate'
|
||||
}, {
|
||||
title: '数据分析',
|
||||
desc:'多种维度洞察',
|
||||
descList:[
|
||||
'AI数据清洗,无效数据在线剔除','AI智能总结,调研结论一键洞察','专业模型看板,直达分析结论','个性化交叉分析,多维数据挖掘'
|
||||
desc: '多种维度洞察',
|
||||
descList: [
|
||||
'AI数据清洗,无效数据在线剔除', 'AI智能总结,调研结论一键洞察', '专业模型看板,直达分析结论', '个性化交叉分析,多维数据挖掘'
|
||||
],
|
||||
btnColor:'green',
|
||||
key:'particulars'
|
||||
btnColor: 'green',
|
||||
key: 'particulars'
|
||||
}]
|
||||
|
||||
const sensors = inject('sensors')
|
||||
|
||||
const goPre = () => {
|
||||
pauseCurrentVideo();
|
||||
if (mySwiper) {
|
||||
@@ -151,7 +141,7 @@ const goNext = () => {
|
||||
};
|
||||
|
||||
const pauseCurrentVideo = () => {
|
||||
if (mySwiper.realIndex === 0 || mySwiper.realIndex === 3){
|
||||
if (mySwiper.realIndex === 0 || mySwiper.realIndex === 3) {
|
||||
return
|
||||
}
|
||||
const activeIndex = mySwiper.realIndex;
|
||||
@@ -165,15 +155,18 @@ const pauseCurrentVideo = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const toSurveyInfo = async (item,index) => {
|
||||
const toSurveyInfo = async (item, index) => {
|
||||
// 调用神策埋点
|
||||
saTrack(item, index)
|
||||
|
||||
let res = await getQueryUserSurvey()
|
||||
const {sn} = res.data
|
||||
const { sn } = res.data
|
||||
const urlJson = {
|
||||
design: `/survey/planet/design?sn=${sn}`,
|
||||
accurate: `/survey/publish/accurate?sn=${sn}`,
|
||||
particulars: `/survey/analyse/diagram?sn=${sn}`,
|
||||
};
|
||||
if (index === 0){
|
||||
if (index === 0) {
|
||||
// 调用智能创建
|
||||
const sceneObj = {
|
||||
title: '智能创建',
|
||||
@@ -182,29 +175,45 @@ const toSurveyInfo = async (item,index) => {
|
||||
};
|
||||
// 通过事件向父组件发送信号,让父组件调用 Scene 组件的 createScene 方法
|
||||
emit('create-survey', sceneObj, 0);
|
||||
}else{
|
||||
if (res.data.flag){
|
||||
} else {
|
||||
if (res.data.flag) {
|
||||
await router.push({
|
||||
path: urlJson[item.key],
|
||||
query: {
|
||||
sn,
|
||||
}
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
message.warning('您还没有问卷,快去创建一个吧~');
|
||||
}
|
||||
}
|
||||
|
||||
function saTrack(record, index) {
|
||||
const operates = ["创建", "设计","投放","分析"]
|
||||
// 操作引导埋点
|
||||
const config = {
|
||||
eventName: "OperatingGuide",
|
||||
properties: {
|
||||
page: "首页",
|
||||
module: "操作指引",
|
||||
position: operates[index]+"问卷",
|
||||
buttonName: "立即体验",
|
||||
clickTime: new Date().toLocaleString().toString()
|
||||
}
|
||||
}
|
||||
sensors.track(config.eventName, config.properties);
|
||||
}
|
||||
}
|
||||
|
||||
const getVideo = (index) => {
|
||||
return require(`@/assets/img/home/video${index+1}.mp4`)
|
||||
return require(`@/assets/img/home/video${index + 1}.mp4`)
|
||||
}
|
||||
const addVideoEndedListener =()=> {
|
||||
const addVideoEndedListener = () => {
|
||||
const videos = document.querySelectorAll('.video-player');
|
||||
|
||||
videos.forEach((video, index) => {
|
||||
video.addEventListener('ended', () => {
|
||||
console.log('video已播完'+index);
|
||||
console.log('video已播完' + index);
|
||||
if (index < operatingList.length - 1) {
|
||||
setTimeout(() => {
|
||||
mySwiper.slideTo(index + 1); // 自动滑动到下一页
|
||||
@@ -233,7 +242,7 @@ const updateButtonImages = (currentIndex) => {
|
||||
} else if (currentIndex === 3) {
|
||||
nextImg.value.src = require('@/assets/img/home/arrow-dis.png');
|
||||
nextImgElement.style.transform = 'rotate(180deg)';
|
||||
}else{
|
||||
} else {
|
||||
// 其他情况恢复默认图片
|
||||
prevImg.value.src = require('@/assets/img/home/arrow-act.png');
|
||||
nextImg.value.src = require('@/assets/img/home/arrow-act.png');
|
||||
@@ -305,79 +314,96 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
p{
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.fs-36{
|
||||
|
||||
.fs-36 {
|
||||
font-size: 36px;
|
||||
}
|
||||
.fs-34{
|
||||
|
||||
.fs-34 {
|
||||
font-size: 34px;
|
||||
}
|
||||
li{
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
.operating-container{
|
||||
|
||||
.operating-container {
|
||||
margin-top: 20px;
|
||||
min-height: 600px;
|
||||
height: 600px;
|
||||
.top{
|
||||
|
||||
.top {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
&>div:first-child {
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
.title{
|
||||
|
||||
.title {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.desc{
|
||||
|
||||
.desc {
|
||||
color: #7F7F81;
|
||||
}
|
||||
.operating-item{
|
||||
.progress{
|
||||
|
||||
.operating-item {
|
||||
.progress {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
letter-spacing: 1px;
|
||||
& :nth-child(1){
|
||||
|
||||
& :nth-child(1) {
|
||||
color: #70B937;
|
||||
font-size: 45px;
|
||||
font-weight: 400;
|
||||
}
|
||||
& :nth-child(2){
|
||||
height: 33px;
|
||||
|
||||
& :nth-child(2) {
|
||||
height: 33px;
|
||||
}
|
||||
& :nth-child(3){
|
||||
|
||||
& :nth-child(3) {
|
||||
color: #000;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.info{
|
||||
|
||||
.info {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-left: 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.desc-item{
|
||||
|
||||
.desc-item {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
margin-left: 5%;
|
||||
margin-bottom: 40px;
|
||||
width: max-content;
|
||||
li{
|
||||
|
||||
li {
|
||||
margin: 20px 0;
|
||||
justify-content: flex-start;
|
||||
.block{
|
||||
|
||||
.block {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #000;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.tag{
|
||||
|
||||
.tag {
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: #2F5EF2;
|
||||
@@ -390,16 +416,19 @@ li{
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-carousel__arrow--right){
|
||||
|
||||
:deep(.el-carousel__arrow--right) {
|
||||
border: 1px solid #C1C1C2;
|
||||
background: transparent;
|
||||
color: #C1C1C2;
|
||||
}
|
||||
:deep(.el-carousel__arrow--left){
|
||||
|
||||
:deep(.el-carousel__arrow--left) {
|
||||
border: 1px solid #C1C1C2;
|
||||
background: transparent;
|
||||
color: #C1C1C2;
|
||||
}
|
||||
|
||||
:deep(.el-carousel__container) {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -448,15 +477,15 @@ li{
|
||||
right: 0;
|
||||
}
|
||||
|
||||
video{
|
||||
video {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
object-fit: fill;
|
||||
}
|
||||
|
||||
//.video-player {
|
||||
// //width: 100%;
|
||||
// //height: auto; /* 自动计算高度 */
|
||||
// //max-height: 100%; /* 防止视频超出容器 */
|
||||
// border-radius: 8px;
|
||||
//}
|
||||
</style>
|
||||
//}</style>
|
||||
|
||||
@@ -2,47 +2,39 @@
|
||||
<div class="scene-container ">
|
||||
<div class="flex">
|
||||
<p></p>
|
||||
<p class="fw-bold fs-24 align--center scene-title" >从场景出发,满足你的各类调研需求</p>
|
||||
<p class="fw-bold fs-24 align--center scene-title">从场景出发,满足你的各类调研需求</p>
|
||||
<p class="more" @click="toModels">更多模板></p>
|
||||
</div>
|
||||
|
||||
<div class="flex mt20 sceneList">
|
||||
<div v-for="(scene,index) in sceneList"
|
||||
:key="index"
|
||||
class="sceneItem"
|
||||
:class="{'fix-scene':[0,1,2].includes(index)}"
|
||||
@click="createScene(scene,index)">
|
||||
<div v-for="(scene, index) in sceneList" :key="index" class="sceneItem"
|
||||
:class="{ 'fix-scene': [0, 1, 2].includes(index) }" @click="createScene(scene, index)">
|
||||
<div class="flex-start">
|
||||
<img :src="scene.image" alt="" style="width: 28px;">
|
||||
<p class="sceneItem-title" :class="{'sceneItem-title-color':index === 0}">{{scene.title}}</p>
|
||||
<p class="sceneItem-title" :class="{ 'sceneItem-title-color': index === 0 }">{{ scene.title }}</p>
|
||||
</div>
|
||||
<p class="sceneItem-desc" :style="{'minHeight':index === 0?'auto':'30px'}">{{scene.description}}</p>
|
||||
<p class="sceneItem-desc" :style="{ 'minHeight': index === 0 ? 'auto' : '30px' }">{{ scene.description }}</p>
|
||||
<div style="text-align: left">
|
||||
<a-button
|
||||
v-if="index === 0 "
|
||||
class="createBtn"
|
||||
type="primary"
|
||||
>
|
||||
<a-button v-if="index === 0" class="createBtn" type="primary">
|
||||
立即创建
|
||||
</a-button>
|
||||
<div v-else>
|
||||
<a-button class="custom-button toCreate"
|
||||
:class="{'createG':[0,1,2].includes(index),
|
||||
'create-normal':[11,13,15,16,17].includes(scene.code)}" type="text">
|
||||
<a-button class="custom-button toCreate" :class="{
|
||||
'createG': [0, 1, 2].includes(index),
|
||||
'create-normal': [11, 13, 15, 16, 17].includes(scene.code)
|
||||
}" type="text">
|
||||
<span>去创建</span>
|
||||
<!-- 'normal':[11,13,15,16,17].includes(scene.code)-->
|
||||
<!-- 'normal':[11,13,15,16,17].includes(scene.code)-->
|
||||
<img src="@/assets/img/home/tob.png" alt=""
|
||||
v-if="[0,1,2].includes(index) || [11,13,15,16,17].includes(scene.code)"/>
|
||||
<img src="@/assets/img/home/tog.png" alt="" v-else/>
|
||||
v-if="[0, 1, 2].includes(index) || [11, 13, 15, 16, 17].includes(scene.code)" />
|
||||
<img src="@/assets/img/home/tog.png" alt="" v-else />
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<create ref="createRef"
|
||||
style="width: 1px;height: 0"
|
||||
@update:ai-assistant-visible="getValue">
|
||||
</create>
|
||||
<create ref="createRef" style="width: 1px;height: 0" @update:ai-assistant-visible="getValue">
|
||||
</create>
|
||||
|
||||
<!-- 概念测试 -->
|
||||
<ConceptTest ref="conceptTestRef" />
|
||||
@@ -52,9 +44,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { onMounted, ref, inject } from 'vue';
|
||||
import create from '@/views/ProjectManage/create/Index.vue'
|
||||
import {useRouter} from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getSceneListHome } from '@/api/home';
|
||||
import deep from '@/assets/img/home/deep.png'
|
||||
import quickImport from '@/assets/img/home/quickImport.png'
|
||||
@@ -73,19 +65,19 @@ const packageTestRef = ref(null)
|
||||
const fixedSceneList = [
|
||||
{
|
||||
title: '智能创建',
|
||||
description:'AI随行,调研随心',
|
||||
image:deep,
|
||||
description: 'AI随行,调研随心',
|
||||
image: deep,
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
title: '快捷导入',
|
||||
description:'点击上传Word文档,批量导入题目一键生成问卷',
|
||||
image:quickImport,
|
||||
description: '点击上传Word文档,批量导入题目一键生成问卷',
|
||||
image: quickImport,
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
title: '空白创建',
|
||||
description:'点击创建新的空白问卷,自定义编辑内容',
|
||||
description: '点击创建新的空白问卷,自定义编辑内容',
|
||||
image: whiteCreate,
|
||||
value: 3
|
||||
},
|
||||
@@ -93,16 +85,18 @@ const fixedSceneList = [
|
||||
const sceneList = ref([])
|
||||
// ref声明(需与组件ref属性值一致)
|
||||
const createRef = ref()
|
||||
const sensors = inject('sensors')
|
||||
|
||||
onMounted(() => {
|
||||
getSceneList()
|
||||
})
|
||||
const toModels = ()=>{
|
||||
const toModels = () => {
|
||||
router.push({
|
||||
path: '/market'
|
||||
});
|
||||
}
|
||||
const getSceneList=()=>{
|
||||
getSceneListHome().then(res=>{
|
||||
const getSceneList = () => {
|
||||
getSceneListHome().then(res => {
|
||||
sceneList.value = []
|
||||
sceneList.value = fixedSceneList.concat(res.data.items)
|
||||
})
|
||||
@@ -112,14 +106,17 @@ const getSceneList=()=>{
|
||||
* @param record
|
||||
* @param index
|
||||
*/
|
||||
const createScene = (record,index)=>{
|
||||
if ([0, 1, 2].includes(index)){
|
||||
const createScene = (record, index) => {
|
||||
// 调用神策埋点
|
||||
saTrack(record, index)
|
||||
|
||||
if ([0, 1, 2].includes(index)) {
|
||||
if (createRef.value) {
|
||||
// 检查 record 是否有 value 属性,如果没有则直接使用 record
|
||||
const sceneData = record.value !== undefined ? record.value : record;
|
||||
createRef.value.createCustom(sceneData)
|
||||
}
|
||||
}else if ([22, 36, 37, 38].includes(record.code)) {
|
||||
} else if ([22, 36, 37, 38].includes(record.code)) {
|
||||
return conceptTestRef.value.openModal({
|
||||
sn: record.sn,
|
||||
snList: record.other?.split(',') || [],
|
||||
@@ -137,20 +134,20 @@ const createScene = (record,index)=>{
|
||||
snList: record.other?.split(',') || [],
|
||||
sceneCode: '24'
|
||||
});
|
||||
}else if([11, 13, 15, 16, 17, 27, 45, 46].includes(record.code)){
|
||||
} else if ([11, 13, 15, 16, 17, 27, 45, 46].includes(record.code)) {
|
||||
if (createRef.value) {
|
||||
createRef.value.createNormalSurvey(record)
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
Modal.confirm({
|
||||
title: () => '创建问卷',
|
||||
content: () =>
|
||||
'需要在敏捷共创模块【共创管理-测试活动】页面选择待测试创意后再创建问卷,点击“确定”将自动跳转。',
|
||||
'需要在敏捷共创模块【共创管理-测试活动】页面选择待测试创意后再创建问卷,点击“确定”将自动跳转。',
|
||||
onOk() {
|
||||
// 判断环境
|
||||
const iframeUrl = currentMode === 'prod'
|
||||
? 'https://yip.digitalyili.com/iframe/test'
|
||||
: 'https://yip-uat.dctest.digitalyili.com/iframe/test';
|
||||
? 'https://yip.digitalyili.com/iframe/test'
|
||||
: 'https://yip-uat.dctest.digitalyili.com/iframe/test';
|
||||
console.log(currentMode, iframeUrl);
|
||||
// 跳转到产品测试模块
|
||||
// top.open(iframeUrl, '_self')
|
||||
@@ -170,6 +167,23 @@ const createScene = (record,index)=>{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function saTrack(record,index) {
|
||||
const config = {
|
||||
eventName: "SurveyCreate",
|
||||
properties: {
|
||||
page: "首页",
|
||||
module: "创建问卷",
|
||||
// 排除智能创建、快捷导入、空白创建,其他都是模板创建
|
||||
position: [0,1,2].includes(index) ? record.title: `模板创建-${record.title}`,
|
||||
// 第一个默认是智能创建
|
||||
buttonName: index === 0 ? "立即创建" : "去创建",
|
||||
clickTime: new Date().toLocaleString().toString()
|
||||
}
|
||||
}
|
||||
sensors.track(config.eventName, config.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮播图设置显隐
|
||||
* @param val
|
||||
@@ -194,22 +208,26 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
p{
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.scene-container{
|
||||
|
||||
.scene-container {
|
||||
text-align: center;
|
||||
}
|
||||
.scene-title{
|
||||
|
||||
.scene-title {
|
||||
margin: 32px 0 26px 4vw;
|
||||
|
||||
}
|
||||
.more{
|
||||
|
||||
.more {
|
||||
color: #70B937;
|
||||
cursor: pointer;
|
||||
}
|
||||
.sceneList{
|
||||
|
||||
.sceneList {
|
||||
overflow-y: hidden;
|
||||
//width: calc(100vw - 40px);
|
||||
overflow-x: auto;
|
||||
@@ -217,7 +235,8 @@ p{
|
||||
padding-bottom: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.sceneItem{
|
||||
|
||||
.sceneItem {
|
||||
padding: 12px 12px 10px 12px;
|
||||
border-radius: 7px;
|
||||
min-width: 190px;
|
||||
@@ -228,18 +247,21 @@ p{
|
||||
background: #fff;
|
||||
border: 1px solid #EBEBEB;
|
||||
}
|
||||
.sceneItem-title{
|
||||
|
||||
.sceneItem-title {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: #000000;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.sceneItem-title-color{
|
||||
|
||||
.sceneItem-title-color {
|
||||
background: linear-gradient(135deg, #C352E7, #3962FF);
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
.sceneItem-desc{
|
||||
|
||||
.sceneItem-desc {
|
||||
font-size: 10px;
|
||||
color: #7F7F7F;
|
||||
text-align: left;
|
||||
@@ -247,16 +269,19 @@ p{
|
||||
text-wrap: wrap;
|
||||
min-height: 30px
|
||||
}
|
||||
.fix-scene{
|
||||
border: 1px solid rgba(98,93,248,0.5);
|
||||
|
||||
.fix-scene {
|
||||
border: 1px solid rgba(98, 93, 248, 0.5);
|
||||
background-image: url("../../../assets/img/home/sceneBg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.normal{
|
||||
color:#ccc;
|
||||
border: 1px solid red!important;
|
||||
|
||||
.normal {
|
||||
color: #ccc;
|
||||
border: 1px solid red !important;
|
||||
}
|
||||
.createBtn{
|
||||
|
||||
.createBtn {
|
||||
background-image: url("../../../assets/img/home/createbtn.png");
|
||||
background-size: 100% 100%;
|
||||
background-color: transparent;
|
||||
@@ -265,38 +290,49 @@ p{
|
||||
text-align: left;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.toCreate{
|
||||
|
||||
.toCreate {
|
||||
padding-left: 0;
|
||||
img{
|
||||
|
||||
img {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
.createG{
|
||||
color: #5562FB!important;
|
||||
|
||||
.createG {
|
||||
color: #5562FB !important;
|
||||
}
|
||||
.create-normal{
|
||||
color: #3171f3!important;
|
||||
|
||||
.create-normal {
|
||||
color: #3171f3 !important;
|
||||
}
|
||||
|
||||
:deep(.ant-btn > span) {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 强制显示滚动条(WebKit 内核浏览器,如 Chrome/Safari) */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px; /* 纵向滚动条宽度 */
|
||||
height: 6px; /* 横向滚动条高度 */
|
||||
width: 8px;
|
||||
/* 纵向滚动条宽度 */
|
||||
height: 6px;
|
||||
/* 横向滚动条高度 */
|
||||
border: 1px solid red;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #DFE1E7; /* 滚动条滑块颜色 */
|
||||
border-radius: 4px; /* 滑块圆角 */
|
||||
background: #DFE1E7;
|
||||
/* 滚动条滑块颜色 */
|
||||
border-radius: 4px;
|
||||
/* 滑块圆角 */
|
||||
}
|
||||
|
||||
/* 滚动条轨道 */
|
||||
::-webkit-scrollbar-track {
|
||||
background: #fff; /* 轨道颜色 */
|
||||
background: #fff;
|
||||
/* 轨道颜色 */
|
||||
//border: 1px solid #D8D8D8;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user