feat(survey): 优化问卷列表和分析页面

- 更新了多个图片资源
- 优化了问卷分析页面的图表展示逻辑
- 调整了导航栏和重定向页面的样式
- 统一了空容器组件的样式
- 优化了问卷列表页面的布局
This commit is contained in:
Huangzhe
2025-05-27 14:40:00 +08:00
parent 2b297d5e80
commit 0dd4600d35
11 changed files with 141 additions and 71 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -6,29 +6,32 @@ import {
getTableData, getTableData,
setDimensionData setDimensionData
} from '@/views/Survey/views/Analysis/components/AnalysisInfo/hooks/pieSeries'; } from '@/views/Survey/views/Analysis/components/AnalysisInfo/hooks/pieSeries';
import EmptyContainer from '@/views/Survey/components/EmptyContainer.vue';
// series 信息
const tableData = ref([]); const tableData = ref([]);
const analysis = defineModel<any>('analysis'); const analysis = defineModel<any>('analysis');
// console.log('analysis', analysis.value); // series 信息
const series = ref([]); const series = ref([]);
const dimension = defineModel('dimension'); const dimension = defineModel('dimension');
// 图标高度 // 图标高度
const chartHeight = computed(() => { const chartHeight = computed(() => {
// 需要增加的高度, 由于字多了他就会高度异常,所有要指定一个动态高度 // 需要增加的高度, 由于字多了他就会高度异常,所有要指定一个动态高度
let addHeight = 0; let addHeight = 0;
const optionLength = analysis.value?.option?.length; // const optionLength = analysis.value?.option?.length;
// 做一些额外的检测, 如果 option 下面的title 字段超过 8 个,就把 addHeight 增加 // 做一些额外的检测, 如果 option 下面的title 字段超过 8 个,就把 addHeight 增加
analysis.value?.option?.forEach((item: any) => { analysis.value?.option?.forEach((item: any) => {
console.log(item);
if (item.title?.length > 8) { if (item.title?.length > 8) {
addHeight += 9; addHeight += 2;
} }
}); });
console.log(`addHeight`, addHeight);
// 每三个选项高度增加 20px 默认 300px // 每三个选项高度增加 20px 默认 300px
return dimension.value ? 280 : 280 + (optionLength - 1) * addHeight; return dimension.value ? 280 : 280 + addHeight;
}); });
const index = ref(0); const index = ref(0);
@@ -37,18 +40,17 @@ const index = ref(0);
watch( watch(
() => analysis.value, () => analysis.value,
async (value) => { async (value) => {
// 排除空数据渲染图标步骤
tableData.value = { tableData.value = {
...analysis.value, ...analysis.value,
option: getTableData(analysis.value) option: getTableData(analysis.value)
}; };
// console.log(`图标的高度是`, chartHeight.value); // console.log(`tableData.value`, tableData.value);
series.value = formatData(dimension.value ? tableData.value : analysis.value, index.value); series.value = formatData(dimension.value ? tableData.value : analysis.value, index.value);
// console.log(`series value`, series.value);
const pieChart = useTemplateRef<HTMLSpanElement>('pieChart'); const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
// console.log(`series value `, series.value);
if (!series.value?.data?.length) return; if (!series.value?.data?.length) return;
useSetPieChart(pieChart, series, { title: false, legend: false }); useSetPieChart(pieChart, series, { title: false, legend: false });
@@ -60,12 +62,42 @@ const changeChart = (i: number) => {
index.value = i; index.value = i;
series.value = formatData(tableData.value, index.value); series.value = formatData(tableData.value, index.value);
// console.log(`series value. by changeChart`, series.value);
if (series.value.data.length <= 0) { if (series.value.data.length <= 0) {
series.value.data = [{ value: 0, name: 0 }]; series.value.data = [{ value: 0, name: 0 }];
} }
// const pieChart = useTemplateRef<HTMLSpanElement>('pieChart'); // const pieChart = useTemplateRef<HTMLSpanElement>('pieChart');
// useSetPieChart(pieChart, series, { title: false, legend: false }); // useSetPieChart(pieChart, series, { title: false, legend: false });
}; };
const chartVisible = computed(() => {
/**
* 针对特殊题型做处理,
* 首先就是矩阵的题目 question_type 为 8 9 10
*
* */
if (
analysis.value.question_type === 8 ||
analysis.value.question_type === 9 ||
analysis.value.question_type === 10
) {
// console.log(`series.value on matrix`, series.value?.data);
const data = series.value?.data as { name: any; value: any }[];
// 过滤后的 data 数据,
const filterData = data.filter((item) => item.value != 0 && item.name != 0);
return filterData.length;
// series.value?.data.forEach((item: any`1[]) => {
// if (item.value > 0) {
// return true;
// }
// });
}
return series.value?.data?.length;
});
</script> </script>
<template> <template>
@@ -85,7 +117,7 @@ const changeChart = (i: number) => {
<!-- 图表部分 --> <!-- 图表部分 -->
<div <div
v-if="series?.data?.length" v-if="chartVisible"
class="charts" class="charts"
:style="{ :style="{
display: 'flex', display: 'flex',
@@ -98,10 +130,14 @@ const changeChart = (i: number) => {
ref="pieChart" ref="pieChart"
:style="{ :style="{
width: '100%', width: '100%',
height: series?.data?.length ? chartHeight + 'px' : '' height: chartVisible ? chartHeight + 'px' : ''
}" }"
></span> ></span>
</div> </div>
<!-- 图标没有实例就开始展示空图标 -->
<div v-else>
<empty-container :error-msg="'本题暂无有效答题数据'" />
</div>
</section> </section>
</template> </template>

View File

@@ -17,14 +17,14 @@ const navigation = ref([
icon: 'home-o', icon: 'home-o',
inactive: '' inactive: ''
}, },
{ // {
title: '伊调研', // title: '伊调研',
// link: { // // link: {
// name: 'home', // // name: 'home',
// path: '/home' // // path: '/home'
// }, // // },
icon: yl // icon: yl
}, // },
{ {
title: '我的', title: '我的',
link: { link: {
@@ -66,7 +66,7 @@ watch(activeTab, (value) => {
<template> <template>
<van-tabbar v-model="activeTab" class="navigation"> <van-tabbar v-model="activeTab" class="navigation">
<template v-for="(item, index) in navigation" :key="item.title"> <template v-for="(item, index) in navigation" :key="item.title">
<span <!-- <span
v-if="index === 1" v-if="index === 1"
style=" style="
display: flex; display: flex;
@@ -77,8 +77,8 @@ watch(activeTab, (value) => {
> >
<img :src="item.icon" alt="" style="width: 30px; height: 30px" /> <img :src="item.icon" alt="" style="width: 30px; height: 30px" />
{{ item.title }} {{ item.title }}
</span> </span> -->
<van-tabbar-item v-else :icon="item.icon" :name="item.title"> <van-tabbar-item :icon="item.icon" :name="item.title">
{{ item.title }} {{ item.title }}
</van-tabbar-item> </van-tabbar-item>
</template> </template>
@@ -87,7 +87,7 @@ watch(activeTab, (value) => {
<style scoped lang="scss"> <style scoped lang="scss">
.navigation { .navigation {
padding: 3px 0; padding: 10px 0;
// width: 100vw; // width: 100vw;
// background-color: white; // background-color: white;
// display: flex; // display: flex;

View File

@@ -3,7 +3,7 @@
<!-- title 标题和搜索栏 --> <!-- title 标题和搜索栏 -->
<header class="header"> <header class="header">
<van-nav-bar <van-nav-bar
:class="[$route.meta.pureBGC ? '' : 'navbar-header']" :class="redirectHeaderStyle"
:title="$route.meta.title" :title="$route.meta.title"
left-arrow left-arrow
safe-area-inset-top safe-area-inset-top
@@ -31,27 +31,40 @@
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
import { RiShareForwardBoxFill } from 'vue-icons-plus/ri'; import { RiShareForwardBoxFill } from 'vue-icons-plus/ri';
import { RouterView, useRoute } from 'vue-router'; import { RouterView, useRoute } from 'vue-router';
import appBridge from '@/assets/js/appBridge'; import appBridge from '@/assets/js/appBridge';
import { computed } from 'vue'; import { computed } from 'vue';
import type { CSSProperties } from 'vue';
const route = useRoute(); const route = useRoute();
// console.log(route.meta.pureBGC); // console.log(route.meta.pureBGC);
/**
* 控制 body 的 style
*/
const redirectBodyStyle = computed(() => { const redirectBodyStyle = computed(() => {
// 背景色控制
const bgc = route.meta.bgc as string;
// 是否纯色背景
const pureBGC = route.meta.pureBGC; const pureBGC = route.meta.pureBGC;
const bgc = route.meta.bgc; // style 样式
const style = {} as CSSProperties;
// 如果存在 bgc 优先选取 bgc, 如果没有则使用 pureBGC if (bgc) style.background = bgc;
// pureBGC 为兼容处理 else if (pureBGC) style.background = '#fff';
if (bgc) return { background: bgc }; return style;
});
return { /**
background: pureBGC ? '#fff' : '' * 控制 header 的 style
}; */
const redirectHeaderStyle = computed(() => {
const css = [];
if (route.meta.header?.bgc === 'green') css.push('green-header');
else css.push('navbar-header');
return css;
}); });
function goBack() { function goBack() {
@@ -97,8 +110,13 @@ const handlePopState = () => {
} }
} }
.green-header {
background-color: theme.$theme-color;
}
.redirect-body { .redirect-body {
overflow: scroll; overflow: scroll;
width: 100vw;
height: calc(100vh - var(--sticky-top-height) - 1px); height: calc(100vh - var(--sticky-top-height) - 1px);
background: transparent; background: transparent;
} }

View File

@@ -53,7 +53,15 @@ const router = createRouter({
{ {
path: '/create', path: '/create',
name: 'create', name: 'create',
meta: { title: '问卷编辑' }, meta: {
title: '问卷编辑',
pureBGC: true,
bgc: '#71b73c',
header: {
bgc: 'green',
pureBGC: false
}
},
component: () => import('../views/Survey/views/Create/Index.vue') component: () => import('../views/Survey/views/Create/Index.vue')
}, },
{ {

View File

@@ -1,43 +1,45 @@
<template> <template>
<!-- survey container --> <section>
<div class="survey-search"> <!-- survey container -->
<nav-search <div class="survey-search">
v-model:value="searchValue" <nav-search
@search="handleSearchClick" v-model:value="searchValue"
@cancel="handleCancelClick" @search="handleSearchClick"
/> @cancel="handleCancelClick"
<!-- <nav-search />
<!-- <nav-search
placeholder="请输入关键词" placeholder="请输入关键词"
v-model:value="searchValue" v-model:value="searchValue"
@click="() => $router.push({ name: 'search' })" @click="() => $router.push({ name: 'search' })"
/> --> /> -->
</div>
<div v-loading="requestLoading" class="new-survey-container">
<div style="margin-bottom: 80px">
<van-list v-model:loading="loading" :finished="finished" @load="handleLoadSurveys">
<template #finished>
<!-- 如果存在搜索文字的话显示没有更多了 -->
<span v-if="searchValue">
<el-text>无符合要求的结果</el-text>
</span>
</template>
<template v-if="survey.length > 0">
<div v-for="item in survey" :key="item" class="new-survey_item">
<survey-item :survey="item" :is-analysis="true" :disable-action-button="false" />
</div>
</template>
<!-- 如果问卷等于0的话显示空容器 -->
<empty-container
v-if="survey.length === 0 && !searchValue"
:img-src="emptyImg"
:show-button="true"
@handle-click="handleEmptyClick"
/>
<NewSurvey v-model:show="showModel" />
</van-list>
</div> </div>
</div> <div v-loading="requestLoading" class="new-survey-container">
<div style="margin-bottom: 80px">
<van-list v-model:loading="loading" :finished="finished" @load="handleLoadSurveys">
<template #finished>
<!-- 如果存在搜索文字的话显示没有更多了 -->
<span v-if="searchValue">
<el-text>无符合要求的结果</el-text>
</span>
</template>
<template v-if="survey.length > 0">
<div v-for="item in survey" :key="item" class="new-survey_item">
<survey-item :survey="item" :is-analysis="true" :disable-action-button="false" />
</div>
</template>
<!-- 如果问卷等于0的话显示空容器 -->
<empty-container
v-if="survey.length === 0 && !searchValue"
:img-src="emptyImg"
:show-button="true"
@handle-click="handleEmptyClick"
/>
<NewSurvey v-model:show="showModel" />
</van-list>
</div>
</div>
</section>
</template> </template>
<script setup> <script setup>

View File

@@ -1,9 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCssModule } from 'vue'; import { useCssModule } from 'vue';
import emptyImg from '@/assets/img/emptyImg.png';
const errorMsg = defineModel<string>('errorMsg', { default: ' - 更多任务期待您的创建 - ' }); const errorMsg = defineModel<string>('errorMsg', { default: ' - 更多任务期待您的创建 - ' });
const showButton = defineModel<boolean>('showButton', { default: false }); const showButton = defineModel<boolean>('showButton', { default: false });
const imgSrc = defineModel<string>('imgSrc'); const imgSrc = defineModel<string>('imgSrc', { default: emptyImg });
const emit = defineEmits(['handle-click']); const emit = defineEmits(['handle-click']);
const style = useCssModule(); const style = useCssModule();

View File

@@ -59,7 +59,7 @@ function setImg(code: number) {
const isShortTitle = ref(false); const isShortTitle = ref(false);
onMounted(() => { onMounted(() => {
console.log(titleRef.value); // console.log(titleRef.value);
if (titleRef.value) { if (titleRef.value) {
const offsetWidth = titleRef.value.$el.offsetWidth; const offsetWidth = titleRef.value.$el.offsetWidth;
isShortTitle.value = 130 <= offsetWidth; isShortTitle.value = 130 <= offsetWidth;
@@ -302,6 +302,11 @@ function copyItem(item: SurveyItem) {
position: absolute; position: absolute;
top: -25px; top: -25px;
right: -25px; right: -25px;
img {
transform: translate(50%, 50%);
width: 98px;
}
} }
.survey_item_info_title { .survey_item_info_title {