优化问卷分析与界面展示
- 修复了图表数据为空时的渲染问题,添加了数据验证逻辑 - 优化了Analysis组件中的图表展示,增加了条件渲染 - 新增useScreen钩子函数用于响应式布局 - 改进了SurveyItem组件的标题样式,从h1调整为h3 - 优化了表格组件的宽度计算逻辑,提高了不同数据量下的展示效果 - 调整了多个组件的布局和样式,提升用户体验 - 清理了代码中的冗余注释和空白行,提高代码可读性
This commit is contained in:
@@ -36,7 +36,9 @@ const index = ref(0);
|
|||||||
// 当 keyword 变动的时候,标记脏数据
|
// 当 keyword 变动的时候,标记脏数据
|
||||||
watch(
|
watch(
|
||||||
() => analysis.value,
|
() => analysis.value,
|
||||||
async () => {
|
async (value) => {
|
||||||
|
// 排除空数据渲染图标步骤
|
||||||
|
|
||||||
tableData.value = {
|
tableData.value = {
|
||||||
...analysis.value,
|
...analysis.value,
|
||||||
option: getTableData(analysis.value)
|
option: getTableData(analysis.value)
|
||||||
@@ -46,6 +48,9 @@ watch(
|
|||||||
|
|
||||||
series.value = formatData(dimension.value ? tableData.value : analysis.value, index.value);
|
series.value = formatData(dimension.value ? tableData.value : analysis.value, index.value);
|
||||||
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
|
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
|
||||||
|
// console.log(`series value `, series.value);
|
||||||
|
|
||||||
|
if (!series.value?.data?.length) return;
|
||||||
useSetPieChart(pieChart, series, { title: false, legend: false });
|
useSetPieChart(pieChart, series, { title: false, legend: false });
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
@@ -71,6 +76,7 @@ const changeChart = (i: number) => {
|
|||||||
|
|
||||||
<!-- 图表部分 -->
|
<!-- 图表部分 -->
|
||||||
<div
|
<div
|
||||||
|
v-if="series?.data?.length"
|
||||||
class="charts"
|
class="charts"
|
||||||
:style="{
|
:style="{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -79,7 +85,13 @@ const changeChart = (i: number) => {
|
|||||||
margin: '16px 0'
|
margin: '16px 0'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span ref="pieChart" style="width: 100%; height: v-bind(chartHeight + 'px')"></span>
|
<span
|
||||||
|
ref="pieChart"
|
||||||
|
:style="{
|
||||||
|
width: '100%',
|
||||||
|
height: series?.data?.length ? chartHeight + 'px' : ''
|
||||||
|
}"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const survey = defineModel<object>('survey', { required: true });
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ survey.project_name }}</h1>
|
<h3>{{ survey.project_name }}</h3>
|
||||||
<el-space spacer="|" direction="horizontal">
|
<el-space spacer="|" direction="horizontal">
|
||||||
<section class="flex items-center pt-1">
|
<section class="flex items-center pt-1">
|
||||||
<img :src="people" alt="" style="margin-right: 5px" />
|
<img :src="people" alt="" style="margin-right: 5px" />
|
||||||
@@ -25,8 +25,8 @@ const survey = defineModel<object>('survey', { required: true });
|
|||||||
<style lang="scss" scoped module="item">
|
<style lang="scss" scoped module="item">
|
||||||
@use '@/assets/css/theme';
|
@use '@/assets/css/theme';
|
||||||
|
|
||||||
h1 {
|
h3 {
|
||||||
margin: 17px 0 12px 0;
|
margin: 10px 0 12px 0;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const template = defineModel('template', { required: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-cell style="margin-bottom: 10px">
|
<van-cell style="margin-bottom: 10px">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
@@ -18,6 +22,14 @@
|
|||||||
</van-cell>
|
</van-cell>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<style lang="scss" scoped module="item">
|
||||||
const template = defineModel('template', { required: true });
|
@use '@/assets/css/theme';
|
||||||
</script>
|
|
||||||
|
h3 {
|
||||||
|
margin: 10px 0 12px 0;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 15px;
|
||||||
|
text-align: left;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RowAlign, type ColumnStyle } from 'element-plus';
|
import { type ColumnStyle } from 'element-plus';
|
||||||
|
|
||||||
const data = defineModel<unknown[]>('data', { default: [] });
|
const data = defineModel<unknown[]>('data', { default: [] });
|
||||||
const props = defineModel<TablePropsType[]>('props');
|
const props = defineModel<TablePropsType[]>('props');
|
||||||
|
|||||||
2
src/components/YlTable/types/table.d.ts
vendored
2
src/components/YlTable/types/table.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
type TablePropsType = {
|
type TablePropsType = {
|
||||||
prop: string;
|
prop: string;
|
||||||
label: string;
|
label: string;
|
||||||
width?: string;
|
width?: string | number;
|
||||||
};
|
};
|
||||||
|
|
||||||
25
src/hooks/browser/useScreen.ts
Normal file
25
src/hooks/browser/useScreen.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
|
||||||
|
export function screenLayout() {
|
||||||
|
// 当前视口的宽度
|
||||||
|
const width = ref(window.innerWidth);
|
||||||
|
// 当前视口的高度
|
||||||
|
const height = ref(window.innerHeight);
|
||||||
|
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
const { width: _width, height: _height } = entry.contentRect;
|
||||||
|
width.value = _width;
|
||||||
|
height.value = _height;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当页面挂载的时候开始监听元素
|
||||||
|
onMounted(() => observer.observe(document.body));
|
||||||
|
// 当页面卸载的时候停止监听元素
|
||||||
|
onUnmounted(() => observer.disconnect());
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { fetchSurveys } from '@/hooks/request/useSurvey';
|
||||||
import CreateSurvey from './components/CreateSurvey/Index.vue';
|
import CreateSurvey from './components/CreateSurvey/Index.vue';
|
||||||
import NewSurvey from './components/NewSurvey/index.vue';
|
import NewSurvey from './components/NewSurvey/index.vue';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
@@ -14,7 +15,8 @@ import MineTask from '@/views/Home/components/MineTask/Index.vue';
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
|
|
||||||
const contentShow = ref(false);
|
const contentShow = ref(false);
|
||||||
|
// 获取我的问卷数据
|
||||||
|
const { surveys } = fetchSurveys();
|
||||||
const keyword = ref('');
|
const keyword = ref('');
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (appBridge.isInReactNative()) {
|
if (appBridge.isInReactNative()) {
|
||||||
@@ -67,9 +69,8 @@ function handleSearchClick() {
|
|||||||
<!--底部新建问卷-->
|
<!--底部新建问卷-->
|
||||||
<NewSurvey />
|
<NewSurvey />
|
||||||
|
|
||||||
<mine-task v-if="false" />
|
<mine-task :surveys="surveys" v-if="surveys?.length > 0" />
|
||||||
<home-recommend class="home_recommend" v-else />
|
<home-recommend class="home_recommend" v-else />
|
||||||
|
|
||||||
<navigation />
|
<navigation />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const props = ref<TablePropsType[]>([
|
|||||||
<template>
|
<template>
|
||||||
<van-cell class="home_recommend">
|
<van-cell class="home_recommend">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<div style="width: 88vw">
|
<div style="width: 90vw">
|
||||||
<yl-table :data="data?.surveyTrendDataVOS" :props="props" />
|
<yl-table :data="data?.surveyTrendDataVOS" :props="props" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
<template>
|
|
||||||
<el-card shadow="never" :body-style="{ padding: 0 }">
|
|
||||||
<van-swipe :autoplay="5000" indicator-color="white">
|
|
||||||
<van-swipe-item v-for="banner in banners">
|
|
||||||
<el-image :src="banner.banner_address" fit="contain" @click="handleBannerClick(banner)" />
|
|
||||||
</van-swipe-item>
|
|
||||||
</van-swipe>
|
|
||||||
</el-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { banners } from '@/views/Home/components/ImageSlider/hooks/useSlider';
|
import { banners } 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 defineBanners = defineModel('banners');
|
// const defineBanners = defineModel('banners');
|
||||||
// 如果定义了 banner , 那么 banners 就不再初始化
|
// 如果定义了 banner , 那么 banners 就不再初始化
|
||||||
// defineBanners.value && updateBanners(defineBanners.value);
|
// defineBanners.value && updateBanners(defineBanners.value);
|
||||||
|
const borderRadius = defineModel('borderRadius');
|
||||||
|
|
||||||
function handleBannerClick(banner: any) {
|
function handleBannerClick(banner: any) {
|
||||||
|
const router = useRouter();
|
||||||
// 把对应的信息给 AD 的 hooks
|
// 把对应的信息给 AD 的 hooks
|
||||||
bannerInfo.value = banner;
|
bannerInfo.value = banner;
|
||||||
router.push({ name: 'ad' });
|
router.push({ name: 'ad' });
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<van-swipe :autoplay="5000" indicator-color="white">
|
||||||
|
<van-swipe-item v-for="banner in banners">
|
||||||
|
<el-image
|
||||||
|
class="img"
|
||||||
|
:style="{ borderRadius: borderRadius + 'px' }"
|
||||||
|
:src="banner.banner_address"
|
||||||
|
fit="contain"
|
||||||
|
@click="handleBannerClick(banner)"
|
||||||
|
/>
|
||||||
|
</van-swipe-item>
|
||||||
|
</van-swipe>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@use '@/assets/css/theme' as *;
|
||||||
|
|
||||||
|
.img {
|
||||||
|
border-radius: $card-radius;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { fetchSurveys } from '@/hooks/request/useSurvey';
|
|
||||||
import QuestionList from './components/QuestionList.vue';
|
import QuestionList from './components/QuestionList.vue';
|
||||||
import YlSwiper from '@/components/YlSwiper/Index.vue';
|
import YlSwiper from '@/components/YlSwiper/Index.vue';
|
||||||
|
|
||||||
const { surveys } = fetchSurveys();
|
const surveys = defineModel('surveys', { required: true });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import YlSwiper from '@/components/YlSwiper/Index.vue';
|
|
||||||
import { useFetchAnalysis } from '@/hooks/request/useSurvey';
|
import { useFetchAnalysis } from '@/hooks/request/useSurvey';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import SurveyItem from '@/views/Survey/components/SurveyItem.vue';
|
import SurveyItem from '@/views/Survey/components/SurveyItem.vue';
|
||||||
import LogicInfo from '@/views/Survey/views/Analysis/components/LogicInfo/Index.vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
import Wait from '@/views/Survey/views/Analysis/components/Wait/Index.vue';
|
|
||||||
import AnalysisInfo from '@/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue';
|
import AnalysisInfo from '@/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue';
|
||||||
import SearchBar from '@/components/Search/Index.vue';
|
|
||||||
import { fetchSingleSurvey } from '@/hooks/request/useSurvey';
|
import { fetchSingleSurvey } from '@/hooks/request/useSurvey';
|
||||||
|
|
||||||
const survey = defineModel<SurveyItem>('survey');
|
const survey = defineModel<SurveyItem>('survey');
|
||||||
@@ -16,16 +11,6 @@ const { questionAnalysis } = useFetchAnalysis(survey.value?.sn as string);
|
|||||||
const { currentSurvey } = fetchSingleSurvey(survey.value?.sn as string);
|
const { currentSurvey } = fetchSingleSurvey(survey.value?.sn as string);
|
||||||
|
|
||||||
const disableInsight = ref(true);
|
const disableInsight = ref(true);
|
||||||
const aiInsightsConfig = ref({
|
|
||||||
visible: false,
|
|
||||||
message: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const postAnalysis = (sn: string) => {
|
|
||||||
aiInsightsConfig.value.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const height = ref(`200px`);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -80,15 +65,6 @@ const height = ref(`200px`);
|
|||||||
.question-item-container {
|
.question-item-container {
|
||||||
width: 90vw;
|
width: 90vw;
|
||||||
|
|
||||||
// display: flex;
|
|
||||||
// justify-content: center;
|
|
||||||
// flex-flow: column nowrap;
|
|
||||||
// align-items: center;
|
|
||||||
|
|
||||||
.survey-item {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.analysis-info {
|
.analysis-info {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ watch(keyword, async () => {
|
|||||||
// await handleSearch();
|
// await handleSearch();
|
||||||
// 重置状态
|
// 重置状态
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
|
||||||
|
// 清空 banners
|
||||||
|
banners.value = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
// 索引变动之后,立刻进行搜索 (没有进行防抖)
|
// 索引变动之后,立刻进行搜索 (没有进行防抖)
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ onUnmounted(() => {
|
|||||||
@use '@/assets/css/theme';
|
@use '@/assets/css/theme';
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
overflow-wrap: break-word;
|
|
||||||
color: rgba(0, 0, 0, 1);
|
color: rgba(0, 0, 0, 1);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: PingFangSC-Medium;
|
font-family: PingFangSC-Medium;
|
||||||
@@ -76,7 +75,7 @@ onUnmounted(() => {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin: 28px 297px 0 2px;
|
margin: 28px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-container {
|
.search-container {
|
||||||
@@ -88,7 +87,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.banner {
|
.banner {
|
||||||
padding: theme.$gap;
|
padding: 0 theme.$gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索结果外部布局
|
// 搜索结果外部布局
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import { index, surveys as _surveys, keyword } from '@/views/HomeSearch/Hooks/useSurveySearch';
|
||||||
index,
|
|
||||||
surveys as _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';
|
import { useRouter } from 'vue-router';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
@@ -53,5 +48,9 @@ const surveys = computed(() => {
|
|||||||
.list-item {
|
.list-item {
|
||||||
margin-top: theme.$gap;
|
margin-top: theme.$gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-item:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ const { questionAnalysis } = useFetchAnalysis(sn.value);
|
|||||||
:survey="currentSurvey as SurveyItem"
|
:survey="currentSurvey as SurveyItem"
|
||||||
@post-analysis="postAnalysis(sn as string)"
|
@post-analysis="postAnalysis(sn as string)"
|
||||||
/>
|
/>
|
||||||
|
<!-- 弹窗组件 -->
|
||||||
<!-- 弹窗组件 -->
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:show-close="false"
|
:show-close="false"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
v-if="analysis.head"
|
v-if="analysis.head"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
<!-- <section v-else>
|
<!-- <section v-else>
|
||||||
<empty-container />
|
<empty-container />
|
||||||
</section> -->
|
</section> -->
|
||||||
</div>
|
</div>
|
||||||
@@ -38,14 +38,17 @@ import ChartMsg from '@/components/Analysis/Index.vue';
|
|||||||
import { getTableData } from './hooks/pieSeries';
|
import { getTableData } from './hooks/pieSeries';
|
||||||
import YlTable from '@/components/YlTable/Index.vue';
|
import YlTable from '@/components/YlTable/Index.vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { screenLayout } from '@/hooks/browser/useScreen';
|
||||||
// questionTypeMap 自己去对应
|
// questionTypeMap 自己去对应
|
||||||
const showChart = ref([1, 2, 5, 106, 9, 10]);
|
const showChart = ref([1, 2, 5, 106, 9, 10]);
|
||||||
|
|
||||||
// 接受上级传递的 questionAnalysis 数据
|
// 接受上级传递的 questionAnalysis 数据
|
||||||
const questionAnalysis = defineModel<any[]>('questionAnalysis');
|
const questionAnalysis = defineModel<any[]>('questionAnalysis');
|
||||||
|
|
||||||
|
const { width } = screenLayout();
|
||||||
|
|
||||||
// 构建表头
|
// 构建表头
|
||||||
const getTableHeadProps = (values: any[], option: any[]) => {
|
const getTableHeadProps = (values: any[], option: any[]): TablePropsType[] => {
|
||||||
const head = [];
|
const head = [];
|
||||||
|
|
||||||
if (values && values.length > 0) {
|
if (values && values.length > 0) {
|
||||||
@@ -54,12 +57,13 @@ const getTableHeadProps = (values: any[], option: any[]) => {
|
|||||||
head.push({
|
head.push({
|
||||||
label: item.title,
|
label: item.title,
|
||||||
prop: item.key,
|
prop: item.key,
|
||||||
width: 120
|
width: values.length < 3 ? width.value / values.length : 120
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (option && option.length > 0 && option[0].option) {
|
|
||||||
|
if (option.length > 0 && option[0].option) {
|
||||||
head.unshift({
|
head.unshift({
|
||||||
label: '选项',
|
label: '选项',
|
||||||
prop: 'option',
|
prop: 'option',
|
||||||
|
|||||||
Reference in New Issue
Block a user