优化搜索和模板市场功能
- 修复饼图无法显示的问题,调整了图表初始化逻辑和容器尺寸 - 添加模板市场组件,实现模板点击和使用功能 - 优化首页布局,调整轮播图和创建问卷组件的顺序 - 添加搜索API接口,支持模板和banner搜索 - 修复问卷创建页面样式,使用van-cell组件优化布局 - 实现智能创建入口的跳转逻辑 - 优化代码格式,修正拼写错误和分号问题
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -32,6 +32,7 @@ declare module 'vue' {
|
|||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||||
VanButton: typeof import('vant/es')['Button']
|
VanButton: typeof import('vant/es')['Button']
|
||||||
|
VanCard: typeof import('vant/es')['Card']
|
||||||
VanCell: typeof import('vant/es')['Cell']
|
VanCell: typeof import('vant/es')['Cell']
|
||||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||||
@@ -49,7 +50,6 @@ declare module 'vue' {
|
|||||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||||
VanRow: typeof import('vant/es')['Row']
|
VanRow: typeof import('vant/es')['Row']
|
||||||
VanSearch: typeof import('vant/es')['Search']
|
VanSearch: typeof import('vant/es')['Search']
|
||||||
VanSpace: typeof import('vant/es')['Space']
|
|
||||||
VanStepper: typeof import('vant/es')['Stepper']
|
VanStepper: typeof import('vant/es')['Stepper']
|
||||||
VanSwipe: typeof import('vant/es')['Swipe']
|
VanSwipe: typeof import('vant/es')['Swipe']
|
||||||
VanSwipeItem: typeof import('vant/es')['SwipeItem']
|
VanSwipeItem: typeof import('vant/es')['SwipeItem']
|
||||||
@@ -58,7 +58,6 @@ declare module 'vue' {
|
|||||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||||
VanTabs: typeof import('vant/es')['Tabs']
|
VanTabs: typeof import('vant/es')['Tabs']
|
||||||
VanTag: typeof import('vant/es')['Tag']
|
|
||||||
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
|
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
|
||||||
YLInput: typeof import('./src/components/YLInput.vue')['default']
|
YLInput: typeof import('./src/components/YLInput.vue')['default']
|
||||||
YLPicker: typeof import('./src/components/YLPicker.vue')['default']
|
YLPicker: typeof import('./src/components/YLPicker.vue')['default']
|
||||||
|
|||||||
@@ -8,18 +8,36 @@ import request from '@/utils/request';
|
|||||||
export function analysisInsights(sn: string, params?: ParticalParams) {
|
export function analysisInsights(sn: string, params?: ParticalParams) {
|
||||||
return request({
|
return request({
|
||||||
url: `/console/surveys/${sn}/analysis_insights_h5`,
|
url: `/console/surveys/${sn}/analysis_insights_h5`,
|
||||||
params
|
data: {},
|
||||||
|
method: 'post'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ai 洞察检查分析是否完成
|
* ai 洞察检查分析是否完成
|
||||||
* @param sn 循环题组sn
|
* @param sn 循环题组sn
|
||||||
* @param data {1|2} 1=AI样本标记;2=AI洞察
|
* @param data {1|2} 1=AI样本标记;2=AI洞察
|
||||||
*/
|
*/
|
||||||
export function checkAnalysisSatus(sn: string, data?: 1 | 2) {
|
export function checkAnalysisStatus(sn: string, data?: 1 | 2) {
|
||||||
return request({
|
return request({
|
||||||
url: `/console/surveys/${sn}/status`,
|
url: `/console/surveys/${sn}/status`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data: {
|
||||||
|
type: data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 问题分析接口
|
||||||
|
* @param sn
|
||||||
|
* @param data {import('@/api/types/analysis.js').AnalysisParam}
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>> | *}
|
||||||
|
*/
|
||||||
|
export function getAnalysis(sn: string) {
|
||||||
|
return request({
|
||||||
|
url: `/console/surveys/${sn}/chart_analysis`,
|
||||||
|
method: 'post',
|
||||||
|
data: {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/api/home/search.ts
Normal file
11
src/api/home/search.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
export function getSearchInfo(keyword: string) {
|
||||||
|
return request({
|
||||||
|
url: '/console/surveys/search',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
keyWord: keyword
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -5,20 +5,21 @@ import { useSetPieChart } from '@/hooks/chart/usePieChart';
|
|||||||
import { surveys } from '@/components/Analysis/hooks/useSurvey';
|
import { surveys } from '@/components/Analysis/hooks/useSurvey';
|
||||||
import { questionTypeMap } from '@/utils/question/typeMapping';
|
import { questionTypeMap } from '@/utils/question/typeMapping';
|
||||||
|
|
||||||
// const info = defineModel<any>('info', { required: true });
|
|
||||||
// series 信息
|
// series 信息
|
||||||
const series = defineModel<any>('series', { required: true });
|
const series = defineModel<any>('series', { required: true });
|
||||||
// 饼图 dom 结构
|
// 饼图 dom 结构
|
||||||
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
|
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
|
||||||
|
|
||||||
useSetPieChart(pieChart, series.value, { title: false, ledge: false });
|
useSetPieChart(pieChart, series, { title: false, legend: false });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<!-- 图表部分 -->
|
<!-- 图表部分 -->
|
||||||
<div style="display: flex; justify-content: center; margin: 16px 0">
|
<div
|
||||||
<span ref="pieChart" style="width: 100%; height: 300px"></span>
|
style="display: flex; height: 300px; width: 300px; justify-content: center; margin: 16px 0"
|
||||||
|
>
|
||||||
|
<!-- <span ref="pieChart" style="width: 100%; height: 300px"></span> -->
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,72 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="w-full">
|
<van-cell style="margin-bottom: 10px">
|
||||||
<van-list :finished="finished" @load="onLoad">
|
<template #extra>
|
||||||
<van-card
|
<section>
|
||||||
v-for="template in templates"
|
<div class="">
|
||||||
:key="template.id"
|
<h3 class="">{{ template.title }}</h3>
|
||||||
class="h-7 mb-3 rounded-sm overflow-hidden shadow-md"
|
|
||||||
>
|
|
||||||
<template #tags>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="flex justify-between items-center mb-2">
|
|
||||||
<h3 class="m-0 font-bold pb-1 text-gray-800">{{ template.title }}</h3>
|
|
||||||
<el-tag size="small" type="success">{{ template.type }}</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
|
<el-space spacer="|" direction="horizontal">
|
||||||
<el-space spacer="|" direction="horizontal" class="mb-3 text-sm text-gray-600">
|
<section>
|
||||||
<section class="flex items-center">
|
<el-text>创作者 {{ template.creater_user }}</el-text>
|
||||||
<el-text class="ml-1">创作者 {{ template.author }}</el-text>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="flex items-center">
|
<section>
|
||||||
<el-text class="ml-1">引用次数 {{ template.views }}</el-text>
|
<el-text>引用次数 {{ template.quote_nums }}</el-text>
|
||||||
</section>
|
</section>
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-card>
|
|
||||||
</van-list>
|
|
||||||
</section>
|
</section>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
const template = defineModel('template', { required: true });
|
||||||
import { User, View } from '@element-plus/icons-vue';
|
|
||||||
|
|
||||||
// 模拟模板数据
|
console.log(template.value);
|
||||||
const templates = ref([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: '报名登到模板A',
|
|
||||||
type: '报名表',
|
|
||||||
author: '张强',
|
|
||||||
views: 4,
|
|
||||||
created_at: '2025-05-01'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: '客户满意度调查',
|
|
||||||
type: '满意度',
|
|
||||||
author: '李明',
|
|
||||||
views: 12,
|
|
||||||
created_at: '2025-04-28'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: '产品反馈收集',
|
|
||||||
type: '反馈',
|
|
||||||
author: '王华',
|
|
||||||
views: 8,
|
|
||||||
created_at: '2025-04-25'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 列表加载状态
|
|
||||||
const loading = ref(false);
|
|
||||||
const finished = ref(true);
|
|
||||||
|
|
||||||
// 加载更多数据
|
|
||||||
const onLoad = () => {
|
|
||||||
loading.value = false;
|
|
||||||
finished.value = true;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,61 +1,58 @@
|
|||||||
import { onMounted, ref, type ShallowRef, watch } from 'vue';
|
import { onMounted, ref, type ShallowRef, watch } from 'vue';
|
||||||
import type { ECOption } from '@/utils/echarts';
|
import type { ECOption } from '@/utils/echarts';
|
||||||
import { chart } from '@/utils/echarts';
|
import { chart } from '@/utils/echarts';
|
||||||
import { deleteLegend, deleteTitle, pieOption } from './data/pie';
|
import { deleteLegend, deleteTitle } from './data/pie';
|
||||||
|
|
||||||
type dataOption = Partial<ECOption['data']>;
|
type dataOption = Partial<ECOption['data']>;
|
||||||
|
|
||||||
const pieChart = ref();
|
|
||||||
/**
|
|
||||||
* 定义数据集
|
|
||||||
*/
|
|
||||||
// const series = ref<dataOption[]>([
|
|
||||||
// {
|
|
||||||
// name: 'Access From',
|
|
||||||
// type: 'pie',
|
|
||||||
// radius: '50%',
|
|
||||||
// data: [
|
|
||||||
// { value: 1048, name: 'Search Engine' },
|
|
||||||
// { value: 735, name: 'Direct' },
|
|
||||||
// { value: 580, name: 'Email' },
|
|
||||||
// { value: 484, name: 'Union Ads' },
|
|
||||||
// { value: 300, name: 'Video Ads' }
|
|
||||||
// ],
|
|
||||||
// emphasis: {
|
|
||||||
// itemStyle: {
|
|
||||||
// shadowBlur: 10,
|
|
||||||
// shadowOffsetX: 0,
|
|
||||||
// shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 饼图的 option
|
* 饼图的 option
|
||||||
*/
|
*/
|
||||||
const option = ref(pieOption);
|
// const option = ref(pieOption);
|
||||||
|
|
||||||
function useSetPieChart(
|
function useSetPieChart(
|
||||||
dom: Readonly<ShallowRef<HTMLSpanElement | null>>,
|
dom: Readonly<ShallowRef<HTMLSpanElement | null>>,
|
||||||
series: any,
|
series: any,
|
||||||
opts: optsType = {}
|
opts: optsType = {}
|
||||||
): void {
|
): void {
|
||||||
if (!series) return;
|
// 图表实例
|
||||||
for (const item in opts) {
|
let pieChart: any;
|
||||||
if (item === 'legend') !opts[item] && deleteLegend();
|
|
||||||
else if (item === 'title') !opts[item] && deleteTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检测边界范围 dom 和 data 是否存在
|
// 检测边界范围 dom 和 data 是否存在
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!dom || series.data.length === 0) return;
|
if (!dom.value) {
|
||||||
|
console.error('饼图DOM元素不存在');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 在 dom 挂载之后,显示饼图
|
// 在 dom 挂载之后,显示饼图
|
||||||
pieChart.value = chart.init(dom.value);
|
pieChart = chart.init(dom.value);
|
||||||
pieChart.value.setOption(option.value, opts);
|
|
||||||
|
if (series.value) {
|
||||||
|
// 创建完整的配置对象
|
||||||
|
const fullOption = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
radius: '50%',
|
||||||
|
data: series.value.data || []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置图表选项
|
||||||
|
pieChart.setOption(fullOption, opts);
|
||||||
|
|
||||||
|
// 强制重绘以确保显示
|
||||||
|
setTimeout(() => {
|
||||||
|
pieChart.resize();
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
console.error('饼图数据不存在');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 如果 data 变动,重新生成图表
|
// 如果 data 变动,重新生成图表w
|
||||||
watch(series, (value) => {
|
watch(series, (value) => {
|
||||||
pieChart.value.setOption(value, opts);
|
pieChart.value.setOption(value, opts);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const router = createRouter({
|
|||||||
component: () => import('../views/Survey/views/Publish/Index.vue')
|
component: () => import('../views/Survey/views/Publish/Index.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'intelligentGeneration',
|
path: '/intelligentGeneration',
|
||||||
name: 'intelligentGeneration',
|
name: 'intelligentGeneration',
|
||||||
meta: {
|
meta: {
|
||||||
title: '智能创建'
|
title: '智能创建'
|
||||||
|
|||||||
18
src/utils/stringTranslate.ts
Normal file
18
src/utils/stringTranslate.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export function escapeHTML (str: string, type = 'dom') {
|
||||||
|
if (type !== 'dom') {
|
||||||
|
const dom = document.createElement("div")
|
||||||
|
dom.textContent = str
|
||||||
|
|
||||||
|
return dom.innerHTML
|
||||||
|
} else {
|
||||||
|
return str.replace(/[&<>"']/g, (match) => ({
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": '''
|
||||||
|
}[match]));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -45,9 +45,9 @@ onMounted(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="contentShow" class="container-home">
|
<div v-if="contentShow" class="container-home">
|
||||||
<div class="container-body">
|
<div class="container-body">
|
||||||
<create-survey :createdNewPage="false" />
|
|
||||||
<!-- 首页轮播图 -->
|
<!-- 首页轮播图 -->
|
||||||
<image-slider />
|
<image-slider />
|
||||||
|
<create-survey :createdNewPage="false" />
|
||||||
<!-- 最新问卷 -->
|
<!-- 最新问卷 -->
|
||||||
<!--<last-survey/>-->
|
<!--<last-survey/>-->
|
||||||
<!-- 模板市场 -->
|
<!-- 模板市场 -->
|
||||||
@@ -55,7 +55,7 @@ onMounted(async () => {
|
|||||||
<!--底部新建问卷-->
|
<!--底部新建问卷-->
|
||||||
<NewSurvey />
|
<NewSurvey />
|
||||||
|
|
||||||
<mine-task />
|
<!-- <mine-task /> -->
|
||||||
|
|
||||||
<navigation />
|
<navigation />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ const createdNewPage = defineModel('createdNewPage', {
|
|||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
const createdQuestion = (item) => {
|
const createdQuestion = (item) => {
|
||||||
|
// 为 智能创建建立链接
|
||||||
|
if (item.h5Title === '智能创建') {
|
||||||
|
return router.push({ name: 'intelligentGeneration' });
|
||||||
|
}
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
group_id: 0,
|
group_id: 0,
|
||||||
source: 1,
|
source: 1,
|
||||||
@@ -112,7 +117,7 @@ onMounted(() => {
|
|||||||
<img :src="homePen" alt="" />
|
<img :src="homePen" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="surveys">
|
<div class="surveys">
|
||||||
<div @click="$router.push({ name: 'intelligentGeneration' })">AI 智能创建</div>
|
<!-- <div @click="$router.push({ name: 'intelligentGeneration' })">AI 智能创建</div> -->
|
||||||
<div
|
<div
|
||||||
v-for="survey in surveys"
|
v-for="survey in surveys"
|
||||||
:key="survey.title"
|
:key="survey.title"
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const url =
|
import { escapeHTML } from '@/utils/stringTranslate';
|
||||||
'https://yiligpt.x.digitalyili.com/aiagent/assistant/78907182-cc42-4072-abae-86ef67c1ecd3/share?token=123123&source=app';
|
|
||||||
|
const host = `https://yiligpt.x.digitalyili.com`;
|
||||||
|
const path = '/aiagent/assistant/78907182-cc42-4072-abae-86ef67c1ecd3/share';
|
||||||
|
const param = `?token=${localStorage.getItem('plantToken')}&source=app`;
|
||||||
|
const url = host + path + param;
|
||||||
|
|
||||||
|
// 字符串转义
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<iframe style="height: 100%; width: 100%" :src="url" frameborder="0"></iframe>
|
<iframe style="height: 100%; width: 100%" :src="escapeHTML(url)" frameborder="0" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<van-swipe :autoplay="2000" indicator-color="white">
|
<van-swipe :autoplay="2000" indicator-color="white">
|
||||||
<van-swipe-item v-for="banner in banners">
|
<van-swipe-item v-for="banner in banners ?? defineBanners">
|
||||||
<el-image :src="banner.banner_address" fit="contain" @click="handleBannerClick(banner)" />
|
<el-image :src="banner.banner_address" fit="contain" @click="handleBannerClick(banner)" />
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
</van-swipe>
|
</van-swipe>
|
||||||
@@ -9,12 +9,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { banners } from '@/views/Home/components/ImageSlider/hooks/useSlider';
|
import { banners, updateBanners } from '@/views/Home/components/ImageSlider/hooks/useSlider';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { bannerInfo } from '@/views/AD/hooks/useAD';
|
import { bannerInfo } from '@/views/AD/hooks/useAD';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
// const defineBanners = defineModel('banners');
|
||||||
|
// 如果定义了 banner , 那么 banners 就不再初始化
|
||||||
|
// defineBanners.value && updateBanners(defineBanners.value);
|
||||||
|
|
||||||
|
setTimeout('console.log(`banner `, banners.value);', 2000);
|
||||||
function handleBannerClick(banner: any) {
|
function handleBannerClick(banner: any) {
|
||||||
// 把对应的信息给 AD 的 hooks
|
// 把对应的信息给 AD 的 hooks
|
||||||
bannerInfo.value = banner;
|
bannerInfo.value = banner;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { queryBannerList } from '@/api/ad';
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const banners = ref();
|
const banners = ref();
|
||||||
// 初始化 data 数据
|
// 初始化 data 数据, 如果不存在 banner 数据,那么重新获取
|
||||||
initBannerData();
|
!banners.value&& initBannerData();
|
||||||
|
|
||||||
async function initBannerData() {
|
async function initBannerData() {
|
||||||
const { data } = await queryBannerList();
|
const { data } = await queryBannerList();
|
||||||
@@ -11,4 +11,8 @@ async function initBannerData() {
|
|||||||
// console.log(`banner data`,banners.value);
|
// console.log(`banner data`,banners.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateBanners(defineBanners:unknown){
|
||||||
|
banners.value = defineBanners
|
||||||
|
}
|
||||||
|
|
||||||
export { initBannerData, banners };
|
export { initBannerData, banners };
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="new_survey">
|
<div class="new_survey">
|
||||||
<div v-if="$route.name !== 'home'">
|
<div v-if="$route.name !== 'home'">
|
||||||
<van-button type="primary" block color="#70B937" @click="create">
|
<!-- <van-button type="primary" block color="#70B937" @click="create">
|
||||||
<span class="fw-bold">+</span> 新建问卷
|
<span class="fw-bold">+</span> 新建问卷
|
||||||
</van-button>
|
</van-button> -->
|
||||||
<van-popup v-model:show="show" round closeable position="bottom" teleport="#app">
|
<van-popup v-model:show="show" round closeable position="bottom" teleport="#app">
|
||||||
<create-question :createdNewPage="false"></create-question>
|
<create-question :createdNewPage="false"></create-question>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
</div>
|
</div>
|
||||||
<navigation/>
|
<navigation />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import CreateQuestion from '@/views/Home/components/CreateSurvey/CreateQuestion.vue';
|
import CreateQuestion from '@/views/Home/components/CreateSurvey/CreateQuestion.vue';
|
||||||
import Navigation from "@/components/Navigation/Index.vue"
|
import Navigation from '@/components/Navigation/Index.vue';
|
||||||
import {useRoute } from "vue-router"
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
|
|
||||||
console.log(route.name)
|
console.log(route.name);
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
function create() {
|
function create() {
|
||||||
show.value = true;
|
show.value = true;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { nextTick, ref, watch } from 'vue';
|
import { nextTick, ref, watch } from 'vue';
|
||||||
import { getSurveysPage } from '@/api/home';
|
import { getSurveysPage } from '@/api/home';
|
||||||
import { saveSearchHistory } from "@/views/HomeSearch/components/Recommend/hooks/useRecommend"
|
import { saveSearchHistory } from '@/views/HomeSearch/components/Recommend/hooks/useRecommend';
|
||||||
|
import { getSearchInfo } from '@/api/home/search';
|
||||||
|
|
||||||
// 问卷
|
// 问卷
|
||||||
const surveys = ref([]);
|
const surveys = ref([]);
|
||||||
@@ -17,8 +18,12 @@ const pageCount = ref<number>(5);
|
|||||||
const dirty = ref(true);
|
const dirty = ref(true);
|
||||||
// loading 状态
|
// loading 状态
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
// 模板列表
|
||||||
|
const templates = ref();
|
||||||
|
// banners
|
||||||
|
const banners = ref();
|
||||||
|
|
||||||
async function handleSearch () {
|
async function handleSearch() {
|
||||||
// loading 状态开启
|
// loading 状态开启
|
||||||
// loading.value = true;
|
// loading.value = true;
|
||||||
const params = {
|
const params = {
|
||||||
@@ -31,6 +36,11 @@ async function handleSearch () {
|
|||||||
// 排除返回出错的异常
|
// 排除返回出错的异常
|
||||||
if (res.data.code !== 0) return;
|
if (res.data.code !== 0) return;
|
||||||
|
|
||||||
|
// 处理模板搜索和banner的信息
|
||||||
|
const info = await getSearchInfo(keyword.value as string);
|
||||||
|
templates.value = info.data.data.templates;
|
||||||
|
banners.value = info.data.data.banners;
|
||||||
|
|
||||||
// 更新问卷信息
|
// 更新问卷信息
|
||||||
// surveys.value = dirty ? res.data.data : surveys.value.concat(res.data.data);
|
// surveys.value = dirty ? res.data.data : surveys.value.concat(res.data.data);
|
||||||
surveys.value = surveys.value.concat(res.data.data);
|
surveys.value = surveys.value.concat(res.data.data);
|
||||||
@@ -44,7 +54,7 @@ async function handleSearch () {
|
|||||||
/**
|
/**
|
||||||
* 更新 搜索关键字信息
|
* 更新 搜索关键字信息
|
||||||
*/
|
*/
|
||||||
async function updateKeyword () {
|
async function updateKeyword() {
|
||||||
// 排除边界条件
|
// 排除边界条件
|
||||||
if (!keyword.value) return;
|
if (!keyword.value) return;
|
||||||
|
|
||||||
@@ -53,16 +63,16 @@ async function updateKeyword () {
|
|||||||
// 处理后置条件,点击搜索之后,索引更新,
|
// 处理后置条件,点击搜索之后,索引更新,
|
||||||
index.value = 1;
|
index.value = 1;
|
||||||
// 把关键词添加到 localStorage 中
|
// 把关键词添加到 localStorage 中
|
||||||
saveSearchHistory(keyword.value)
|
saveSearchHistory(keyword.value);
|
||||||
// 打开页面展示状态
|
// 打开页面展示状态
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
function updatePageCount (value: number) {
|
function updatePageCount(value: number) {
|
||||||
pageCount.value = value;
|
pageCount.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,5 +92,13 @@ watch(index, async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export { keyword, updateKeyword as handleSearch, lastIndex, loading, surveys, index };
|
export {
|
||||||
|
keyword,
|
||||||
|
updateKeyword as handleSearch,
|
||||||
|
lastIndex,
|
||||||
|
loading,
|
||||||
|
surveys,
|
||||||
|
index,
|
||||||
|
templates,
|
||||||
|
banners
|
||||||
|
};
|
||||||
|
|||||||
@@ -7,17 +7,20 @@ import Layout from '@/components/Layout/CommonLayout.vue';
|
|||||||
import { visible } from '@/views/HomeSearch/Hooks/useHomeSearch';
|
import { visible } from '@/views/HomeSearch/Hooks/useHomeSearch';
|
||||||
import RecommendTag from '@/views/HomeSearch/components/Recommend/Index.vue';
|
import RecommendTag from '@/views/HomeSearch/components/Recommend/Index.vue';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
import ImageSlider from '../Home/components/ImageSlider/Index.vue';
|
||||||
|
import { banners } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 当页面取消挂载时,重置页面展示的状态
|
// 当页面取消挂载时,重置页面展示的状态
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<search v-model:value="keyword" :search="handleSearch" />
|
<search v-model:value="keyword" :search="handleSearch" />
|
||||||
<!-- 广告区域 -->
|
<!-- 广告区域 -->
|
||||||
|
<image-slider :banners="banners" v-if="banners?.length" />
|
||||||
|
|
||||||
<section v-if="loading">
|
<section v-if="loading">
|
||||||
<!-- 我的问卷区域 -->
|
<!-- 我的问卷区域 -->
|
||||||
@@ -35,7 +38,7 @@ onMounted(() => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section v-else>
|
<section v-else>
|
||||||
<recommend-tag></recommend-tag>
|
<recommend-tag />
|
||||||
</section>
|
</section>
|
||||||
<!-- <div class="search-result">-->
|
<!-- <div class="search-result">-->
|
||||||
<!-- <div class="search-result-item" v-for="item in searchResult" :key="item.id">-->
|
<!-- <div class="search-result-item" v-for="item in searchResult" :key="item.id">-->
|
||||||
@@ -43,7 +46,6 @@ onMounted(() => {
|
|||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { index, surveys, lastIndex, keyword } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
import { index, surveys, lastIndex, keyword } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||||
import SurveyItem from '@/components/SurveyItem/Index.vue';
|
import SurveyItem from '@/components/SurveyItem/Index.vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
/**
|
/**
|
||||||
* van-list 触发 loading 状态函数
|
* van-list 触发 loading 状态函数
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +12,15 @@ function handleLoadStatus() {
|
|||||||
if (!keyword.value) return;
|
if (!keyword.value) return;
|
||||||
index.value += 1;
|
index.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSurveyClick(survey: { sn: any }) {
|
||||||
|
router.push({
|
||||||
|
path: '/create',
|
||||||
|
query: {
|
||||||
|
sn: survey.sn
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -17,7 +28,7 @@ function handleLoadStatus() {
|
|||||||
<van-list :offset="10" :finished="lastIndex" @load="handleLoadStatus">
|
<van-list :offset="10" :finished="lastIndex" @load="handleLoadStatus">
|
||||||
<van-card v-for="survey in surveys" :key="survey" class="rounded-xs">
|
<van-card v-for="survey in surveys" :key="survey" class="rounded-xs">
|
||||||
<template #tags>
|
<template #tags>
|
||||||
<survey-item :survey="survey" />
|
<survey-item :survey="survey" @click="handleSurveyClick(survey)" />
|
||||||
</template>
|
</template>
|
||||||
</van-card>
|
</van-card>
|
||||||
</van-list>
|
</van-list>
|
||||||
|
|||||||
@@ -1,12 +1,79 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import MarketItem from '@/components/MarketItem/MarketItem.vue';
|
|
||||||
import MarketItem from '@/components/TemplateMarketItem/Index.vue';
|
import MarketItem from '@/components/TemplateMarketItem/Index.vue';
|
||||||
|
import { templates } from '../../Hooks/useSurveySearch';
|
||||||
|
import { consoleSurveys, useTemplate } from '@/api/home';
|
||||||
|
import { saveQuestions, snQuestions } from '@/api/design';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useCounterStore } from '@/stores/counter';
|
||||||
|
import { type Store, type PiniaCustomStateProperties, storeToRefs } from 'pinia';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// 获取 Store 实例
|
||||||
|
const counterStore = useCounterStore();
|
||||||
|
const store = storeToRefs(counterStore as any);
|
||||||
|
|
||||||
|
function handleTemplateClick(template: any) {
|
||||||
|
const query = {
|
||||||
|
group_id: 0,
|
||||||
|
source: 1,
|
||||||
|
project_name: `${template.title}问卷 `,
|
||||||
|
remarks: '为优化活动服务品质,烦请完成问卷,感谢配合',
|
||||||
|
scene_code: template.scene_code,
|
||||||
|
scene_code_info: template.scene_code_info,
|
||||||
|
tags: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
if (template.sn) {
|
||||||
|
query.scene_code = null;
|
||||||
|
query.tags = [] as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果放在了底部 当作新增组件
|
||||||
|
if (template.sn) {
|
||||||
|
useTemplate(template.sn, query).then((temp) => {
|
||||||
|
if (temp.data) {
|
||||||
|
createdApx(temp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
consoleSurveys(query).then((res) => {
|
||||||
|
if (res.data) {
|
||||||
|
createdApx(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createdApx(res: any) {
|
||||||
|
snQuestions({ sn: res.data.data.sn }).then((ques) => {
|
||||||
|
if (ques.data) {
|
||||||
|
ques.data.data.survey.introduction = `<p>为优化活动服务品质,烦请完成问卷,感谢配合!您的反馈至关重要!</p>`;
|
||||||
|
store.questionsInfo.value = ques.data.data;
|
||||||
|
saveQuestions({
|
||||||
|
sn: res.data.data.sn,
|
||||||
|
introduction: ques.data.data.survey.introduction,
|
||||||
|
title: ques.data.data.survey.title
|
||||||
|
}).then(() => {
|
||||||
|
router.push({
|
||||||
|
path: '/create',
|
||||||
|
query: {
|
||||||
|
sn: res.data.data.sn
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section class="template-container">
|
||||||
<market-item></market-item>
|
<market-item
|
||||||
|
v-for="template in templates"
|
||||||
|
:key="template"
|
||||||
|
:template="template"
|
||||||
|
@click="handleTemplateClick(template)"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ useFetchAnalysis(route.query.sn as string);
|
|||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-cell v-if="false" class="ai-insight">
|
<van-cell v-if="aiInsightsConfig.message.length > 0" class="ai-insight">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<!-- ai 洞察部分内容 -->
|
<!-- ai 洞察部分内容 -->
|
||||||
<AiInsightResults />
|
<div v-html="aiInsightsConfig.message" />
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,18 @@ export const series = ref({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function formatData(data: any) {
|
export function formatData(data: any) {
|
||||||
console.log(data);
|
const _series = ref(JSON.parse(JSON.stringify(series.value)));
|
||||||
const { option } = data;
|
|
||||||
|
|
||||||
series.value.data = option.map((item) => {
|
// 当内容为单选的时候处理方式
|
||||||
|
if (data.question_index === 2) {
|
||||||
|
const { option } = data;
|
||||||
|
_series.value.data = option.map((item: any) => {
|
||||||
return {
|
return {
|
||||||
value: item.number,
|
value: item.number,
|
||||||
name: item.title
|
name: item.title
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`series data`, series.value);
|
return _series;
|
||||||
|
|
||||||
return series.value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import waitImg from "@/assets/img/analysis/wait.png"
|
import waitImg from '@/assets/img/analysis/wait.png';
|
||||||
|
import { aiInsightsConfig } from '@/views/Survey/views/Analysis/hooks/useAnalysis';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="wait-container">
|
<section class="wait-container">
|
||||||
<el-image :src="waitImg"></el-image>
|
<el-image :src="waitImg"></el-image>
|
||||||
<el-text>AI 小助手加速工作中</el-text>
|
<el-text>AI 小助手加速工作中</el-text>
|
||||||
<el-text>我正在为您分析问卷内容,这个过程可能会多花一点点时间,不过马上就好,稍等哦</el-text>
|
<el-text>
|
||||||
|
{{
|
||||||
|
aiInsightsConfig.info.length !== 0
|
||||||
|
? aiInsightsConfig.info
|
||||||
|
: '我正在为您分析问卷内容,这个过程可能会多花一点点时间,不过马上就好,稍等哦'
|
||||||
|
}}</el-text
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
import { surveyAnalysis } from '@/api/survey';
|
import { surveyAnalysis } from '@/api/survey';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { analysisInsights, checkAnalysisSatus } from '@/api/anslysis/aiInsight';
|
import { analysisInsights, checkAnalysisStatus, getAnalysis } from '@/api/anslysis/aiInsight';
|
||||||
|
|
||||||
type AiInsightType = {
|
type AiInsightType = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
timer: NodeJS.Timeout | undefined;
|
timer: NodeJS.Timeout | undefined;
|
||||||
|
message: string;
|
||||||
|
info: string;
|
||||||
};
|
};
|
||||||
// ai 智能洞察
|
// ai 智能洞察
|
||||||
export const aiInsightsConfig = ref<AiInsightType>({
|
export const aiInsightsConfig = ref<AiInsightType>({
|
||||||
visible: false,
|
visible: false,
|
||||||
timer: undefined
|
timer: undefined,
|
||||||
|
message: '',
|
||||||
|
info: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const questionAnalysis = ref();
|
const questionAnalysis = ref();
|
||||||
@@ -19,31 +23,52 @@ const params: AnalysisParam = {
|
|||||||
source: 1
|
source: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
export function postAnalysis(sn: string) {
|
export async function postAnalysis(sn: string) {
|
||||||
|
let code;
|
||||||
|
let message;
|
||||||
|
|
||||||
aiInsightsConfig.value.visible = true;
|
aiInsightsConfig.value.visible = true;
|
||||||
analysisInsights(sn);
|
analysisInsights(sn)
|
||||||
|
.then((res) => {
|
||||||
|
code = res.code;
|
||||||
|
message = res.message;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
aiInsightsConfig.value.info = e.data.message;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 此时正在进行 ai 洞察
|
||||||
|
if (code === 10015) aiInsightsConfig.value.message = message;
|
||||||
|
|
||||||
if (!aiInsightsConfig.value.timer) {
|
if (!aiInsightsConfig.value.timer) {
|
||||||
// 每 1 s 检查一次是否分析完成
|
// 每 1 s 检查一次是否分析完成
|
||||||
aiInsightsConfig.value.timer = setInterval(() => {
|
aiInsightsConfig.value.timer = setInterval(async () => {
|
||||||
checkAnalysis(sn);
|
const { code, data } = await checkAnalysis(sn);
|
||||||
|
|
||||||
|
// 如果状态正常且标记成功,清除 timer 内容
|
||||||
|
if (code === 0 && data.status === 1) {
|
||||||
|
clearInterval(aiInsightsConfig.value.timer);
|
||||||
|
// 获取洞察结果
|
||||||
|
const { data } = await getAnalysis(sn);
|
||||||
|
console.log(data.other.overall_conclusion);
|
||||||
|
aiInsightsConfig.value.message = data.other.overall_conclusion;
|
||||||
|
aiInsightsConfig.value.visible = false;
|
||||||
|
} else if (data.status === 2) {
|
||||||
|
// 标记失败, 后续增加处理
|
||||||
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 当组件取消挂载时, 取消 interval 定时
|
|
||||||
clearInterval(aiInsightsConfig.value.timer);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkAnalysis(sn: string) {
|
export async function checkAnalysis(sn: string) {
|
||||||
const res = checkAnalysisSatus(sn, 2);
|
const { data } = await checkAnalysisStatus(sn, 2);
|
||||||
console.log(res);
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function useFetchAnalysis(sn: string) {
|
async function useFetchAnalysis(sn: string) {
|
||||||
const res = await surveyAnalysis(sn);
|
const res = await surveyAnalysis(sn);
|
||||||
questionAnalysis.value = res.data.data;
|
questionAnalysis.value = res.data.data;
|
||||||
console.log(`question analysis`, questionAnalysis.value);
|
// console.log(`question analysis`, questionAnalysis.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { useFetchAnalysis, questionAnalysis };
|
export { useFetchAnalysis, questionAnalysis };
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="">
|
<div class="container">
|
||||||
<div class="question-title flex space-between">
|
<van-cell class="question-title">
|
||||||
|
<template #extra>
|
||||||
<div class="title-left">
|
<div class="title-left">
|
||||||
<div class="flex" :class="titleActive ? 'line-border' : ''">
|
<div class="flex" :class="titleActive ? 'line-border' : ''">
|
||||||
<!--问卷标题-->
|
<!--问卷标题-->
|
||||||
@@ -53,7 +54,8 @@
|
|||||||
<div class="title-right">
|
<div class="title-right">
|
||||||
<div class="right-icon"></div>
|
<div class="right-icon"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
|
||||||
<div class="ques">
|
<div class="ques">
|
||||||
<!-- 题目-->
|
<!-- 题目-->
|
||||||
@@ -866,10 +868,12 @@ onBeforeMount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@use '@/assets/css/theme';
|
||||||
@import '@/assets/css/theme';
|
@import '@/assets/css/theme';
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
& .question-title {
|
& .question-title {
|
||||||
|
border-radius: theme.$card-radius;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user