优化搜索和模板市场功能
- 修复饼图无法显示的问题,调整了图表初始化逻辑和容器尺寸 - 添加模板市场组件,实现模板点击和使用功能 - 优化首页布局,调整轮播图和创建问卷组件的顺序 - 添加搜索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']
|
||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanCard: typeof import('vant/es')['Card']
|
||||
VanCell: typeof import('vant/es')['Cell']
|
||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||
VanCheckbox: typeof import('vant/es')['Checkbox']
|
||||
@@ -49,7 +50,6 @@ declare module 'vue' {
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanRow: typeof import('vant/es')['Row']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanSpace: typeof import('vant/es')['Space']
|
||||
VanStepper: typeof import('vant/es')['Stepper']
|
||||
VanSwipe: typeof import('vant/es')['Swipe']
|
||||
VanSwipeItem: typeof import('vant/es')['SwipeItem']
|
||||
@@ -58,7 +58,6 @@ declare module 'vue' {
|
||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||
VanTabs: typeof import('vant/es')['Tabs']
|
||||
VanTag: typeof import('vant/es')['Tag']
|
||||
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
|
||||
YLInput: typeof import('./src/components/YLInput.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) {
|
||||
return request({
|
||||
url: `/console/surveys/${sn}/analysis_insights_h5`,
|
||||
params
|
||||
data: {},
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ai 洞察检查分析是否完成
|
||||
* @param sn 循环题组sn
|
||||
* @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({
|
||||
url: `/console/surveys/${sn}/status`,
|
||||
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 { questionTypeMap } from '@/utils/question/typeMapping';
|
||||
|
||||
// const info = defineModel<any>('info', { required: true });
|
||||
// series 信息
|
||||
const series = defineModel<any>('series', { required: true });
|
||||
// 饼图 dom 结构
|
||||
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
|
||||
|
||||
useSetPieChart(pieChart, series.value, { title: false, ledge: false });
|
||||
useSetPieChart(pieChart, series, { title: false, legend: false });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<!-- 图表部分 -->
|
||||
<div style="display: flex; justify-content: center; margin: 16px 0">
|
||||
<span ref="pieChart" style="width: 100%; height: 300px"></span>
|
||||
<div
|
||||
style="display: flex; height: 300px; width: 300px; justify-content: center; margin: 16px 0"
|
||||
>
|
||||
<!-- <span ref="pieChart" style="width: 100%; height: 300px"></span> -->
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -1,72 +1,25 @@
|
||||
<template>
|
||||
<section class="w-full">
|
||||
<van-list :finished="finished" @load="onLoad">
|
||||
<van-card
|
||||
v-for="template in templates"
|
||||
:key="template.id"
|
||||
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>
|
||||
|
||||
<el-space spacer="|" direction="horizontal" class="mb-3 text-sm text-gray-600">
|
||||
<section class="flex items-center">
|
||||
<el-text class="ml-1">创作者 {{ template.author }}</el-text>
|
||||
</section>
|
||||
<section class="flex items-center">
|
||||
<el-text class="ml-1">引用次数 {{ template.views }}</el-text>
|
||||
</section>
|
||||
</el-space>
|
||||
</div>
|
||||
</template>
|
||||
</van-card>
|
||||
</van-list>
|
||||
</section>
|
||||
<van-cell style="margin-bottom: 10px">
|
||||
<template #extra>
|
||||
<section>
|
||||
<div class="">
|
||||
<h3 class="">{{ template.title }}</h3>
|
||||
</div>
|
||||
<el-space spacer="|" direction="horizontal">
|
||||
<section>
|
||||
<el-text>创作者 {{ template.creater_user }}</el-text>
|
||||
</section>
|
||||
<section>
|
||||
<el-text>引用次数 {{ template.quote_nums }}</el-text>
|
||||
</section>
|
||||
</el-space>
|
||||
</section>
|
||||
</template>
|
||||
</van-cell>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { User, View } from '@element-plus/icons-vue';
|
||||
const template = defineModel('template', { required: true });
|
||||
|
||||
// 模拟模板数据
|
||||
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;
|
||||
};
|
||||
console.log(template.value);
|
||||
</script>
|
||||
|
||||
@@ -1,61 +1,58 @@
|
||||
import { onMounted, ref, type ShallowRef, watch } from 'vue';
|
||||
import type { ECOption } 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']>;
|
||||
|
||||
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
|
||||
*/
|
||||
const option = ref(pieOption);
|
||||
// const option = ref(pieOption);
|
||||
|
||||
function useSetPieChart(
|
||||
dom: Readonly<ShallowRef<HTMLSpanElement | null>>,
|
||||
series: any,
|
||||
opts: optsType = {}
|
||||
): void {
|
||||
if (!series) return;
|
||||
for (const item in opts) {
|
||||
if (item === 'legend') !opts[item] && deleteLegend();
|
||||
else if (item === 'title') !opts[item] && deleteTitle();
|
||||
}
|
||||
// 图表实例
|
||||
let pieChart: any;
|
||||
|
||||
// 检测边界范围 dom 和 data 是否存在
|
||||
onMounted(() => {
|
||||
if (!dom || series.data.length === 0) return;
|
||||
if (!dom.value) {
|
||||
console.error('饼图DOM元素不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 在 dom 挂载之后,显示饼图
|
||||
pieChart.value = chart.init(dom.value);
|
||||
pieChart.value.setOption(option.value, opts);
|
||||
pieChart = chart.init(dom.value);
|
||||
|
||||
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) => {
|
||||
pieChart.value.setOption(value, opts);
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ const router = createRouter({
|
||||
component: () => import('../views/Survey/views/Publish/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'intelligentGeneration',
|
||||
path: '/intelligentGeneration',
|
||||
name: 'intelligentGeneration',
|
||||
meta: {
|
||||
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>
|
||||
<div v-if="contentShow" class="container-home">
|
||||
<div class="container-body">
|
||||
<create-survey :createdNewPage="false" />
|
||||
<!-- 首页轮播图 -->
|
||||
<image-slider />
|
||||
<create-survey :createdNewPage="false" />
|
||||
<!-- 最新问卷 -->
|
||||
<!--<last-survey/>-->
|
||||
<!-- 模板市场 -->
|
||||
@@ -55,7 +55,7 @@ onMounted(async () => {
|
||||
<!--底部新建问卷-->
|
||||
<NewSurvey />
|
||||
|
||||
<mine-task />
|
||||
<!-- <mine-task /> -->
|
||||
|
||||
<navigation />
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,11 @@ const createdNewPage = defineModel('createdNewPage', {
|
||||
default: false
|
||||
});
|
||||
const createdQuestion = (item) => {
|
||||
// 为 智能创建建立链接
|
||||
if (item.h5Title === '智能创建') {
|
||||
return router.push({ name: 'intelligentGeneration' });
|
||||
}
|
||||
|
||||
const query = {
|
||||
group_id: 0,
|
||||
source: 1,
|
||||
@@ -112,7 +117,7 @@ onMounted(() => {
|
||||
<img :src="homePen" alt="" />
|
||||
</div>
|
||||
<div class="surveys">
|
||||
<div @click="$router.push({ name: 'intelligentGeneration' })">AI 智能创建</div>
|
||||
<!-- <div @click="$router.push({ name: 'intelligentGeneration' })">AI 智能创建</div> -->
|
||||
<div
|
||||
v-for="survey in surveys"
|
||||
:key="survey.title"
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
const url =
|
||||
'https://yiligpt.x.digitalyili.com/aiagent/assistant/78907182-cc42-4072-abae-86ef67c1ecd3/share?token=123123&source=app';
|
||||
import { escapeHTML } from '@/utils/stringTranslate';
|
||||
|
||||
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>
|
||||
|
||||
<template>
|
||||
<iframe style="height: 100%; width: 100%" :src="url" frameborder="0"></iframe>
|
||||
<iframe style="height: 100%; width: 100%" :src="escapeHTML(url)" frameborder="0" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<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)" />
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
@@ -9,12 +9,16 @@
|
||||
</template>
|
||||
|
||||
<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 { bannerInfo } from '@/views/AD/hooks/useAD';
|
||||
|
||||
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) {
|
||||
// 把对应的信息给 AD 的 hooks
|
||||
bannerInfo.value = banner;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { queryBannerList } from '@/api/ad';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const banners = ref();
|
||||
// 初始化 data 数据
|
||||
initBannerData();
|
||||
// 初始化 data 数据, 如果不存在 banner 数据,那么重新获取
|
||||
!banners.value&& initBannerData();
|
||||
|
||||
async function initBannerData() {
|
||||
const { data } = await queryBannerList();
|
||||
@@ -11,4 +11,8 @@ async function initBannerData() {
|
||||
// console.log(`banner data`,banners.value);
|
||||
}
|
||||
|
||||
export function updateBanners(defineBanners:unknown){
|
||||
banners.value = defineBanners
|
||||
}
|
||||
|
||||
export { initBannerData, banners };
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<div class="new_survey">
|
||||
<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> 新建问卷
|
||||
</van-button>
|
||||
</van-button> -->
|
||||
<van-popup v-model:show="show" round closeable position="bottom" teleport="#app">
|
||||
<create-question :createdNewPage="false"></create-question>
|
||||
</van-popup>
|
||||
</div>
|
||||
<navigation/>
|
||||
<navigation />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import CreateQuestion from '@/views/Home/components/CreateSurvey/CreateQuestion.vue';
|
||||
import Navigation from "@/components/Navigation/Index.vue"
|
||||
import {useRoute } from "vue-router"
|
||||
import Navigation from '@/components/Navigation/Index.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
const route = useRoute();
|
||||
|
||||
console.log(route.name)
|
||||
console.log(route.name);
|
||||
import { ref } from 'vue';
|
||||
function create() {
|
||||
show.value = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { nextTick, ref, watch } from 'vue';
|
||||
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([]);
|
||||
@@ -17,8 +18,12 @@ const pageCount = ref<number>(5);
|
||||
const dirty = ref(true);
|
||||
// loading 状态
|
||||
const loading = ref(false);
|
||||
// 模板列表
|
||||
const templates = ref();
|
||||
// banners
|
||||
const banners = ref();
|
||||
|
||||
async function handleSearch () {
|
||||
async function handleSearch() {
|
||||
// loading 状态开启
|
||||
// loading.value = true;
|
||||
const params = {
|
||||
@@ -31,6 +36,11 @@ async function handleSearch () {
|
||||
// 排除返回出错的异常
|
||||
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 = surveys.value.concat(res.data.data);
|
||||
@@ -44,7 +54,7 @@ async function handleSearch () {
|
||||
/**
|
||||
* 更新 搜索关键字信息
|
||||
*/
|
||||
async function updateKeyword () {
|
||||
async function updateKeyword() {
|
||||
// 排除边界条件
|
||||
if (!keyword.value) return;
|
||||
|
||||
@@ -53,16 +63,16 @@ async function updateKeyword () {
|
||||
// 处理后置条件,点击搜索之后,索引更新,
|
||||
index.value = 1;
|
||||
// 把关键词添加到 localStorage 中
|
||||
saveSearchHistory(keyword.value)
|
||||
saveSearchHistory(keyword.value);
|
||||
// 打开页面展示状态
|
||||
loading.value = true
|
||||
loading.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
function updatePageCount (value: number) {
|
||||
function updatePageCount(value: number) {
|
||||
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 RecommendTag from '@/views/HomeSearch/components/Recommend/Index.vue';
|
||||
import { onMounted } from 'vue';
|
||||
import ImageSlider from '../Home/components/ImageSlider/Index.vue';
|
||||
import { banners } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||
|
||||
onMounted(() => {
|
||||
// 当页面取消挂载时,重置页面展示的状态
|
||||
loading.value = false
|
||||
})
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<search v-model:value="keyword" :search="handleSearch" />
|
||||
<!-- 广告区域 -->
|
||||
<image-slider :banners="banners" v-if="banners?.length" />
|
||||
|
||||
<section v-if="loading">
|
||||
<!-- 我的问卷区域 -->
|
||||
@@ -35,7 +38,7 @@ onMounted(() => {
|
||||
</section>
|
||||
|
||||
<section v-else>
|
||||
<recommend-tag></recommend-tag>
|
||||
<recommend-tag />
|
||||
</section>
|
||||
<!-- <div class="search-result">-->
|
||||
<!-- <div class="search-result-item" v-for="item in searchResult" :key="item.id">-->
|
||||
@@ -43,7 +46,6 @@ onMounted(() => {
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</section>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { index, surveys, lastIndex, keyword } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||
import SurveyItem from '@/components/SurveyItem/Index.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter();
|
||||
/**
|
||||
* van-list 触发 loading 状态函数
|
||||
*/
|
||||
@@ -10,6 +12,15 @@ function handleLoadStatus() {
|
||||
if (!keyword.value) return;
|
||||
index.value += 1;
|
||||
}
|
||||
|
||||
function handleSurveyClick(survey: { sn: any }) {
|
||||
router.push({
|
||||
path: '/create',
|
||||
query: {
|
||||
sn: survey.sn
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -17,7 +28,7 @@ function handleLoadStatus() {
|
||||
<van-list :offset="10" :finished="lastIndex" @load="handleLoadStatus">
|
||||
<van-card v-for="survey in surveys" :key="survey" class="rounded-xs">
|
||||
<template #tags>
|
||||
<survey-item :survey="survey" />
|
||||
<survey-item :survey="survey" @click="handleSurveyClick(survey)" />
|
||||
</template>
|
||||
</van-card>
|
||||
</van-list>
|
||||
|
||||
@@ -1,12 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
// import MarketItem from '@/components/MarketItem/MarketItem.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>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<market-item></market-item>
|
||||
<section class="template-container">
|
||||
<market-item
|
||||
v-for="template in templates"
|
||||
:key="template"
|
||||
:template="template"
|
||||
@click="handleTemplateClick(template)"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -45,10 +45,10 @@ useFetchAnalysis(route.query.sn as string);
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<van-cell v-if="false" class="ai-insight">
|
||||
<van-cell v-if="aiInsightsConfig.message.length > 0" class="ai-insight">
|
||||
<template #extra>
|
||||
<!-- ai 洞察部分内容 -->
|
||||
<AiInsightResults />
|
||||
<div v-html="aiInsightsConfig.message" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
|
||||
@@ -23,17 +23,18 @@ export const series = ref({
|
||||
});
|
||||
|
||||
export function formatData(data: any) {
|
||||
console.log(data);
|
||||
const { option } = data;
|
||||
const _series = ref(JSON.parse(JSON.stringify(series.value)));
|
||||
|
||||
series.value.data = option.map((item) => {
|
||||
return {
|
||||
value: item.number,
|
||||
name: item.title
|
||||
};
|
||||
});
|
||||
// 当内容为单选的时候处理方式
|
||||
if (data.question_index === 2) {
|
||||
const { option } = data;
|
||||
_series.value.data = option.map((item: any) => {
|
||||
return {
|
||||
value: item.number,
|
||||
name: item.title
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`series data`, series.value);
|
||||
|
||||
return series.value;
|
||||
return _series;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
<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>
|
||||
|
||||
<template>
|
||||
<section class="wait-container">
|
||||
<el-image :src="waitImg"></el-image>
|
||||
<el-text>AI 小助手加速工作中</el-text>
|
||||
<el-text>我正在为您分析问卷内容,这个过程可能会多花一点点时间,不过马上就好,稍等哦</el-text>
|
||||
</section>
|
||||
<section class="wait-container">
|
||||
<el-image :src="waitImg"></el-image>
|
||||
<el-text>AI 小助手加速工作中</el-text>
|
||||
<el-text>
|
||||
{{
|
||||
aiInsightsConfig.info.length !== 0
|
||||
? aiInsightsConfig.info
|
||||
: '我正在为您分析问卷内容,这个过程可能会多花一点点时间,不过马上就好,稍等哦'
|
||||
}}</el-text
|
||||
>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wait-container {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { surveyAnalysis } from '@/api/survey';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { analysisInsights, checkAnalysisSatus } from '@/api/anslysis/aiInsight';
|
||||
import { analysisInsights, checkAnalysisStatus, getAnalysis } from '@/api/anslysis/aiInsight';
|
||||
|
||||
type AiInsightType = {
|
||||
visible: boolean;
|
||||
timer: NodeJS.Timeout | undefined;
|
||||
message: string;
|
||||
info: string;
|
||||
};
|
||||
// ai 智能洞察
|
||||
export const aiInsightsConfig = ref<AiInsightType>({
|
||||
visible: false,
|
||||
timer: undefined
|
||||
timer: undefined,
|
||||
message: '',
|
||||
info: ''
|
||||
});
|
||||
|
||||
const questionAnalysis = ref();
|
||||
@@ -19,31 +23,52 @@ const params: AnalysisParam = {
|
||||
source: 1
|
||||
};
|
||||
|
||||
export function postAnalysis(sn: string) {
|
||||
export async function postAnalysis(sn: string) {
|
||||
let code;
|
||||
let message;
|
||||
|
||||
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) {
|
||||
// 每 1 s 检查一次是否分析完成
|
||||
aiInsightsConfig.value.timer = setInterval(() => {
|
||||
checkAnalysis(sn);
|
||||
aiInsightsConfig.value.timer = setInterval(async () => {
|
||||
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);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 当组件取消挂载时, 取消 interval 定时
|
||||
clearInterval(aiInsightsConfig.value.timer);
|
||||
});
|
||||
}
|
||||
|
||||
export async function checkAnalysis(sn: string) {
|
||||
const res = checkAnalysisSatus(sn, 2);
|
||||
console.log(res);
|
||||
const { data } = await checkAnalysisStatus(sn, 2);
|
||||
return data;
|
||||
}
|
||||
|
||||
async function useFetchAnalysis(sn: string) {
|
||||
const res = await surveyAnalysis(sn);
|
||||
questionAnalysis.value = res.data.data;
|
||||
console.log(`question analysis`, questionAnalysis.value);
|
||||
// console.log(`question analysis`, questionAnalysis.value);
|
||||
}
|
||||
|
||||
export { useFetchAnalysis, questionAnalysis };
|
||||
|
||||
@@ -1,59 +1,61 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<div class="question-title flex space-between">
|
||||
<div class="title-left">
|
||||
<div class="flex" :class="titleActive ? 'line-border' : ''">
|
||||
<!--问卷标题-->
|
||||
<contenteditable
|
||||
v-model="questionInfo.survey.title"
|
||||
className="content-title"
|
||||
:active="titleActive"
|
||||
id="content-title"
|
||||
placeholder="请输入问卷标题"
|
||||
ref="contentTitle"
|
||||
@blur="saveTitle"
|
||||
>
|
||||
</contenteditable>
|
||||
<div class="right-action">
|
||||
<van-icon
|
||||
class-prefix="mobilefont"
|
||||
name="Edit"
|
||||
v-if="!titleActive"
|
||||
@click="titleActive = true"
|
||||
></van-icon>
|
||||
<van-icon
|
||||
class-prefix="mobilefont"
|
||||
name="del1"
|
||||
v-else
|
||||
@click.stop="closeActive"
|
||||
></van-icon>
|
||||
<div class="container">
|
||||
<van-cell class="question-title">
|
||||
<template #extra>
|
||||
<div class="title-left">
|
||||
<div class="flex" :class="titleActive ? 'line-border' : ''">
|
||||
<!--问卷标题-->
|
||||
<contenteditable
|
||||
v-model="questionInfo.survey.title"
|
||||
className="content-title"
|
||||
:active="titleActive"
|
||||
id="content-title"
|
||||
placeholder="请输入问卷标题"
|
||||
ref="contentTitle"
|
||||
@blur="saveTitle"
|
||||
>
|
||||
</contenteditable>
|
||||
<div class="right-action">
|
||||
<van-icon
|
||||
class-prefix="mobilefont"
|
||||
name="Edit"
|
||||
v-if="!titleActive"
|
||||
@click="titleActive = true"
|
||||
></van-icon>
|
||||
<van-icon
|
||||
class-prefix="mobilefont"
|
||||
name="del1"
|
||||
v-else
|
||||
@click.stop="closeActive"
|
||||
></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 问卷标注-->
|
||||
<contenteditable
|
||||
v-model="questionInfo.survey.introduction"
|
||||
className="introduction"
|
||||
:active="true"
|
||||
placeholder="请输入问卷标注"
|
||||
@blur="saveTitle"
|
||||
></contenteditable>
|
||||
</div>
|
||||
<!-- <van-cell-group inset class="result-cell">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div>-->
|
||||
<!-- -->
|
||||
<!-- </div>-->
|
||||
<!-- <div>-->
|
||||
<!-- -->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- 问卷标注-->
|
||||
<contenteditable
|
||||
v-model="questionInfo.survey.introduction"
|
||||
className="introduction"
|
||||
:active="true"
|
||||
placeholder="请输入问卷标注"
|
||||
@blur="saveTitle"
|
||||
></contenteditable>
|
||||
</div>
|
||||
<!-- <van-cell-group inset class="result-cell">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div>-->
|
||||
<!-- -->
|
||||
<!-- </div>-->
|
||||
<!-- <div>-->
|
||||
<!-- -->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </van-cell-group>-->
|
||||
<div class="title-right">
|
||||
<div class="right-icon"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
<!-- </van-cell-group>-->
|
||||
<div class="title-right">
|
||||
<div class="right-icon"></div>
|
||||
</div>
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<div class="ques">
|
||||
<!-- 题目-->
|
||||
@@ -866,10 +868,12 @@ onBeforeMount(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use '@/assets/css/theme';
|
||||
@import '@/assets/css/theme';
|
||||
|
||||
.container {
|
||||
& .question-title {
|
||||
border-radius: theme.$card-radius;
|
||||
padding: 0 20px;
|
||||
background-color: transparent !important;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user