feat: 优化组件和页面功能
- 新增 YlSwiper 轮播组件,基于 swiper 库实现,支持自定义渲染和多种配置项 - 优化 YlTable 组件,提升表格渲染性能和使用体验 - 优化 LogicInfo 组件,修复数据为空时的显示问题,使用 currentTabs 替代重复的计算属性 - 优化 AnalysisInfo 组件,移除冗余类型转换 - 新增问卷列表组件 QuestionList,用于展示任务相关问卷 - 更新 vite 配置,支持 swiper 自定义元素 - 添加 swiper 依赖包
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"shrinkpng": "^1.2.0-beta.1",
|
||||
"sortablejs": "^1.15.6",
|
||||
"swiper": "^11.2.7",
|
||||
"tailwindcss": "^4.1.6",
|
||||
"uuid": "^11.1.0",
|
||||
"vant": "^4.9.17",
|
||||
|
||||
286
src/components/YlSwiper/Index.vue
Normal file
286
src/components/YlSwiper/Index.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<script setup lang="ts">
|
||||
import { register } from 'swiper/element/bundle';
|
||||
import { ref, computed, defineEmits, onMounted, defineModel, useSlots } from 'vue';
|
||||
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
|
||||
|
||||
// 定义 Swiper 元素类型
|
||||
interface SwiperEvent {
|
||||
detail: [any, any?];
|
||||
}
|
||||
|
||||
interface SwiperElement extends HTMLElement {
|
||||
swiper: any;
|
||||
}
|
||||
|
||||
// 注册 Swiper 元素
|
||||
register();
|
||||
|
||||
// Swiper 实例引用
|
||||
const swiperRef = ref<SwiperElement | null>(null);
|
||||
const swiperInstance = ref<any>(null);
|
||||
|
||||
// 使用 defineModel 定义可双向绑定的属性
|
||||
// 轮播图数据
|
||||
const slides = defineModel<any[]>('slides', { default: () => [] });
|
||||
// 每个幻灯片的渲染函数
|
||||
const renderSlide = defineModel<Function | null>('renderSlide', { default: null });
|
||||
// 每页显示的幻灯片数
|
||||
const slidesPerView = defineModel<number | string>('slidesPerView', { default: 1 });
|
||||
// 幻灯片之间的间距
|
||||
const spaceBetween = defineModel<number | string>('spaceBetween', { default: 10 });
|
||||
// 是否居中显示
|
||||
const centeredSlides = defineModel<boolean>('centeredSlides', { default: false });
|
||||
// 是否循环播放
|
||||
const loop = defineModel<boolean>('loop', { default: false });
|
||||
// 是否自动播放
|
||||
const autoplay = defineModel<boolean | object>('autoplay', { default: false });
|
||||
// 是否显示分页器
|
||||
const pagination = defineModel<boolean | object>('pagination', { default: false });
|
||||
// 是否显示导航按钮
|
||||
const navigation = defineModel<boolean | object>('navigation', { default: false });
|
||||
// 断点配置
|
||||
const breakpoints = defineModel<object>('breakpoints', { default: () => ({}) });
|
||||
// 初始幻灯片索引
|
||||
const initialSlide = defineModel<number>('initialSlide', { default: 0 });
|
||||
// 高度
|
||||
const height = defineModel<string>('height', { default: '' });
|
||||
// 宽度
|
||||
const width = defineModel<string>('width', { default: '100%' });
|
||||
// 是否允许触摸滑动(设置为 false 则禁用滑动)
|
||||
const allowTouchMove = defineModel<boolean>('allowTouchMove', { default: true });
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits([
|
||||
'progress',
|
||||
'slideChange',
|
||||
'slideChangeTransitionStart',
|
||||
'slideChangeTransitionEnd',
|
||||
'update'
|
||||
]);
|
||||
|
||||
// 计算属性:自动播放配置
|
||||
const autoplayConfig = computed(() => {
|
||||
if (autoplay.value === true) {
|
||||
return { delay: 3000, disableOnInteraction: false };
|
||||
}
|
||||
return autoplay.value || false;
|
||||
});
|
||||
|
||||
// 计算属性:分页器配置
|
||||
const paginationConfig = computed(() => {
|
||||
// 始终返回 false,禁用原生分页指示器
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取插槽
|
||||
const slots = useSlots();
|
||||
|
||||
// 计算属性:是否有自定义导航按钮
|
||||
const hasCustomNavButtons = computed(() => {
|
||||
return !!(slots.prevButton || slots.nextButton);
|
||||
});
|
||||
|
||||
// 计算属性:导航按钮配置
|
||||
const navigationConfig = computed(() => {
|
||||
// 如果有自定义导航按钮,则禁用原生导航按钮
|
||||
if (hasCustomNavButtons.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 否则使用配置的导航按钮设置
|
||||
if (navigation.value === true) {
|
||||
return {};
|
||||
}
|
||||
return navigation.value || false;
|
||||
});
|
||||
|
||||
// 事件处理函数
|
||||
const onProgress = (e: SwiperEvent) => {
|
||||
const [swiper, progress] = e.detail;
|
||||
emit('progress', { swiper, progress });
|
||||
};
|
||||
|
||||
const onSlideChange = (e: SwiperEvent) => {
|
||||
const [swiper] = e.detail;
|
||||
emit('slideChange', { swiper, activeIndex: swiper.activeIndex });
|
||||
};
|
||||
|
||||
const onSlideChangeTransitionStart = (e: SwiperEvent) => {
|
||||
const [swiper] = e.detail;
|
||||
emit('slideChangeTransitionStart', { swiper });
|
||||
};
|
||||
|
||||
const onSlideChangeTransitionEnd = (e: SwiperEvent) => {
|
||||
const [swiper] = e.detail;
|
||||
emit('slideChangeTransitionEnd', { swiper });
|
||||
};
|
||||
|
||||
// 初始化 Swiper
|
||||
onMounted(() => {
|
||||
// 使用 setTimeout 确保 DOM 已完全渲染
|
||||
setTimeout(() => {
|
||||
if (swiperRef.value && swiperRef.value.swiper) {
|
||||
swiperInstance.value = swiperRef.value.swiper;
|
||||
emit('update', swiperInstance.value);
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// 提供方法:切换到下一张幻灯片
|
||||
const slideNext = () => {
|
||||
if (swiperInstance.value && typeof swiperInstance.value.slideNext === 'function') {
|
||||
swiperInstance.value.slideNext();
|
||||
}
|
||||
};
|
||||
|
||||
// 提供方法:切换到上一张幻灯片
|
||||
const slidePrev = () => {
|
||||
if (swiperInstance.value && typeof swiperInstance.value.slidePrev === 'function') {
|
||||
swiperInstance.value.slidePrev();
|
||||
}
|
||||
};
|
||||
|
||||
// 提供方法:切换到指定幻灯片
|
||||
const slideTo = (index: number) => {
|
||||
if (swiperInstance.value && typeof swiperInstance.value.slideTo === 'function') {
|
||||
swiperInstance.value.slideTo(index);
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
slideNext,
|
||||
slidePrev,
|
||||
slideTo,
|
||||
swiper: swiperInstance
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="yl-swiper" :style="{ width, height }">
|
||||
<!-- 导航按钮(左) -->
|
||||
<div v-if="navigation" class="yl-swiper-button-prev" @click="slidePrev">
|
||||
<slot name="prevButton">
|
||||
<el-icon :size="24"><arrow-left /></el-icon>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<swiper-container
|
||||
ref="swiperRef"
|
||||
:slides-per-view="slidesPerView"
|
||||
:space-between="spaceBetween"
|
||||
:centered-slides="centeredSlides"
|
||||
:initial-slide="initialSlide"
|
||||
:loop="loop"
|
||||
:autoplay="autoplayConfig"
|
||||
:pagination="paginationConfig"
|
||||
:navigation="navigationConfig"
|
||||
:breakpoints="breakpoints"
|
||||
:allow-touch-move="allowTouchMove"
|
||||
@swiperprogress="onProgress"
|
||||
@swiperslidechange="onSlideChange"
|
||||
@sliderslidetransitionstart="onSlideChangeTransitionStart"
|
||||
@sliderslidetransitionend="onSlideChangeTransitionEnd"
|
||||
>
|
||||
<!-- 使用传入的渲染函数渲染幻灯片 -->
|
||||
<template v-if="renderSlide && slides && slides.length">
|
||||
<swiper-slide v-for="(item, index) in slides" :key="index">
|
||||
<component :is="renderSlide(item, index)" />
|
||||
</swiper-slide>
|
||||
</template>
|
||||
|
||||
<!-- 使用默认插槽 -->
|
||||
<template v-else>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</swiper-container>
|
||||
|
||||
<!-- 导航按钮(右) -->
|
||||
<div v-if="navigation" class="yl-swiper-button-next" @click="slideNext">
|
||||
<slot name="nextButton">
|
||||
<el-icon :size="24"><arrow-right /></el-icon>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<!-- 自定义分页指示器 -->
|
||||
<div v-if="pagination" class="yl-swiper-pagination">
|
||||
<slot name="pagination">
|
||||
<div
|
||||
v-for="(_, index) in slides && slides.length ? slides : (swiperInstance?.value?.slides || [])"
|
||||
:key="index"
|
||||
class="yl-swiper-pagination-bullet"
|
||||
:class="{ 'is-active': swiperInstance?.value?.activeIndex === index }"
|
||||
@click="slideTo(index)"
|
||||
></div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.yl-swiper {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.yl-swiper-button-prev,
|
||||
.yl-swiper-button-next {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 10;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.yl-swiper-button-prev {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.yl-swiper-button-next {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.yl-swiper-button-prev,
|
||||
.yl-swiper-button-next {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.yl-swiper-pagination {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
z-index: 10;
|
||||
|
||||
.yl-swiper-pagination-bullet {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.is-active {
|
||||
background-color: #409EFF;
|
||||
width: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { RowAlign, type ColumnStyle } from 'element-plus';
|
||||
import type { CSSProperties } from 'vue';
|
||||
|
||||
const data = defineModel<unknown[]>('data', { default: [] });
|
||||
const props = defineModel<
|
||||
@@ -16,6 +15,9 @@ const singleLine = defineModel<boolean>('singleLine', { default: false });
|
||||
const rowStyle = defineModel<ColumnStyle<any>>('rowStyle', {
|
||||
default: {}
|
||||
});
|
||||
// 显示表格的高度, 默认的高度是 200px
|
||||
const tableHeight = defineModel<string | number>('height', { default: '300px' });
|
||||
|
||||
const headerStyle = defineModel<ColumnStyle<any>>('headerStyle', {
|
||||
default: {
|
||||
background: 'red'
|
||||
@@ -34,6 +36,7 @@ function setStripeColor(rowData: { row: any; rowIndex: number }): string {
|
||||
<template>
|
||||
<div :style="{ borderRadius: rounded ? '10px' : '0', overflow: 'hidden' }">
|
||||
<el-table
|
||||
:max-height="tableHeight"
|
||||
:header-cell-style="{ background: '#f2f8ee' }"
|
||||
:row-class-name="setStripeColor"
|
||||
:data="data"
|
||||
@@ -49,7 +52,7 @@ function setStripeColor(rowData: { row: any; rowIndex: number }): string {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss" scoped module="table">
|
||||
:deep(.even-row) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ import '@/style/utils.scss';
|
||||
import appBridge from '@/assets/js/appBridge';
|
||||
import VConsole from 'vconsole';
|
||||
import './assets/css/main.scss';
|
||||
// 引入 swiper 样式
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import 'swiper/css/pagination';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
if (import.meta.env.VITE_APP_ENV !== 'production') {
|
||||
|
||||
@@ -28,7 +28,8 @@ service.interceptors.request.use(
|
||||
let plantToken = localStorage.getItem('plantToken');
|
||||
// 如果 token 不存在, 试图尝试让用户输入 token ,然后放入本地 token 内容中
|
||||
// 仅限开发环境中
|
||||
if (!plantToken && !import.meta.env.PROD) {
|
||||
// if (!plantToken && !import.meta.env.PROD) {
|
||||
if (!plantToken) {
|
||||
plantToken = prompt('token 不存在,请输入 plant token');
|
||||
plantToken && localStorage.setItem('plantToken', plantToken);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ function handleSearchClick() {
|
||||
<div class="container-body">
|
||||
<!-- 搜索栏 -->
|
||||
<section class="search">
|
||||
<search-bar placeholder="请输入关键字" :value="keyword" @click="handleSearchClick" />
|
||||
<search-bar placeholder="请输入关键词" :value="keyword" @click="handleSearchClick" />
|
||||
</section>
|
||||
<!-- 首页轮播图 -->
|
||||
<section class="slider">
|
||||
|
||||
@@ -34,7 +34,6 @@ const createdQuestion = (item) => {
|
||||
remarks: '为优化活动服务品质,烦请完成问卷,感谢配合',
|
||||
scene_code: item.parentCode,
|
||||
scene_code_info: item.code,
|
||||
// 很迷茫 模板新增 tag 空数组 非模板 就是k
|
||||
tags: ''
|
||||
};
|
||||
if (createdNewPage.value) {
|
||||
@@ -116,7 +115,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="create_survey">
|
||||
<div class="create_survey_title" style="color: #000; text-align: left">新建问卷</div>
|
||||
<div class="create_survey_title" style="color: #000; text-align: left">新建任务</div>
|
||||
<div class="home-pen">
|
||||
<img :src="homePen" alt="" />
|
||||
</div>
|
||||
|
||||
@@ -1,35 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
import SurveyAnalysis from '@/views/Survey/views/Analysis/Index.vue';
|
||||
import { fetchSurveys } from '@/hooks/request/useSurvey';
|
||||
import { cellWithoutPadding } from '@/utils/theme/cell';
|
||||
import QuestionList from './components/QuestionList.vue';
|
||||
import YlSwiper from '@/components/YlSwiper/Index.vue';
|
||||
|
||||
const { surveys } = fetchSurveys();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-cell :style="cellWithoutPadding" class="swipe-container">
|
||||
<template #extra>
|
||||
<van-swipe class="my-swipe" indicator-color="white" :loop="false">
|
||||
<van-swipe-item :key="survey.sn" v-for="survey in surveys">
|
||||
<section style="width: 90vw">
|
||||
<h3 style="margin: 10px 0 -10px 10px">我的任务</h3>
|
||||
<survey-analysis :sn="survey.sn" :disable-search="true" :disable-insight="true" />
|
||||
</section>
|
||||
</van-swipe-item>
|
||||
<!-- 指示器 -->
|
||||
<!-- <template #indicator="{ active, total }">
|
||||
<div class="custom-indicator">{{ active + 1 }}/{{ total }}</div>
|
||||
</template> -->
|
||||
</van-swipe>
|
||||
</template>
|
||||
</van-cell>
|
||||
<div class="carousel-container">
|
||||
<!-- 方式一:使用默认插槽,手动添加 swiper-slide 元素 -->
|
||||
<yl-swiper
|
||||
:slides-per-view="1"
|
||||
:centered-slides="true"
|
||||
:pagination="true"
|
||||
:navigation="true"
|
||||
:loop="false"
|
||||
:space-between="0"
|
||||
:allow-touch-move="false"
|
||||
>
|
||||
<swiper-slide v-for="question in surveys" :key="question.sn">
|
||||
<question-list :survey="question" style="max-width: 100vw; overflow: hidden" />
|
||||
</swiper-slide>
|
||||
</yl-swiper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '@/assets/css/theme';
|
||||
|
||||
.swipe-container {
|
||||
.carousel-container {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
margin-top: theme.$gap;
|
||||
border-radius: theme.$card-radius;
|
||||
padding: 10px;
|
||||
|
||||
.carousel-item {
|
||||
.swipe-container {
|
||||
margin-top: theme.$gap;
|
||||
border-radius: theme.$card-radius;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-content {
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
import YlSwiper from '@/components/YlSwiper/Index.vue';
|
||||
import { useFetchAnalysis } from '@/hooks/request/useSurvey';
|
||||
import { ref } from '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 SearchBar from '@/components/Search/Index.vue';
|
||||
import { fetchSingleSurvey } from '@/hooks/request/useSurvey';
|
||||
|
||||
const survey = defineModel<SurveyItem>('survey');
|
||||
// 获取问卷分析数据
|
||||
const { questionAnalysis } = useFetchAnalysis(survey.value?.sn as string);
|
||||
const { currentSurvey } = fetchSingleSurvey(survey.value?.sn as string);
|
||||
|
||||
const disableInsight = ref(true);
|
||||
const aiInsightsConfig = ref({
|
||||
visible: false,
|
||||
message: ''
|
||||
});
|
||||
|
||||
const postAnalysis = (sn: string) => {
|
||||
aiInsightsConfig.value.visible = true;
|
||||
};
|
||||
|
||||
const height = ref(`200px`);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="question-item-container">
|
||||
<section class="survey-item">
|
||||
<!-- 问卷详情部分 -->
|
||||
<survey-item
|
||||
v-if="currentSurvey"
|
||||
:is-analysis="disableInsight"
|
||||
:disable-action-button="true"
|
||||
:survey="currentSurvey as SurveyItem"
|
||||
></survey-item>
|
||||
</section>
|
||||
|
||||
<!-- 问卷分析 -->
|
||||
<section class="analysis-info">
|
||||
<!-- van swiper -->
|
||||
<van-swipe>
|
||||
<van-swipe-item v-for="analysis in questionAnalysis">
|
||||
<analysis-info :sn="survey?.sn" :questionAnalysis="[analysis]" />
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
|
||||
<!-- <swiper navigation :slides-per-view="3" :modules="modules" :space-between="50">
|
||||
<swiper-slide v-for="analysis in questionAnalysis">
|
||||
{{ analysis }}
|
||||
</swiper-slide>
|
||||
</swiper> -->
|
||||
|
||||
<!-- swiper -->
|
||||
<!-- <yl-swiper> -->
|
||||
<!-- <swiper-slide v-for="item in questionAnalysis" :key="item.stem"> -->
|
||||
<!-- 为 item 解决内部数据错误的问题 -->
|
||||
<!-- <analysis-info :sn="survey?.sn" :questionAnalysis="[item]" /> -->
|
||||
<!-- </swiper-slide> -->
|
||||
<!-- </yl-swiper> -->
|
||||
|
||||
<!-- el carousel -->
|
||||
<!-- <el-carousel arrow="always" :loop="false" :autoplay="false"> -->
|
||||
<!-- <el-carousel-item v-for="item in questionAnalysis"> -->
|
||||
<!-- 为 item 解决内部数据错误的问题 -->
|
||||
<!-- <analysis-info :sn="survey?.sn" :questionAnalysis="[item]" /> -->
|
||||
<!-- </el-carousel-item> -->
|
||||
<!-- </el-carousel> -->
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '@/assets/css/theme';
|
||||
|
||||
.question-item-container {
|
||||
width: 90vw;
|
||||
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// flex-flow: column nowrap;
|
||||
// align-items: center;
|
||||
|
||||
.survey-item {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.analysis-info {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<section v-for="analysis in questionAnalysis" :key="analysis.stem" class="mt10">
|
||||
<!-- 优先去上级传递的数值 -->
|
||||
<section v-for="analysis in analysis" :key="analysis.stem" class="mt10">
|
||||
<!-- {{ analysis }} -->
|
||||
<!-- 问题标题 -->
|
||||
<el-tag type="success" size="small">{{
|
||||
@@ -17,16 +18,21 @@
|
||||
|
||||
<!-- 问题表格部分 -->
|
||||
<yl-table
|
||||
class="mt10"
|
||||
class="mt10"
|
||||
:props="getTableHeadProps(analysis.head, analysis.option)"
|
||||
:data="getTableData(analysis)"
|
||||
v-if="analysis.head"
|
||||
/>
|
||||
</section>
|
||||
<!-- <section v-else>
|
||||
<empty-container />
|
||||
</section> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 空白容器
|
||||
import EmptyContainer from '@/views/Survey/components/EmptyContainer.vue';
|
||||
import { useFetchAnalysis } from '../../hooks/useAnalysis';
|
||||
import { questionTypeMap } from '@/utils/question/typeMapping';
|
||||
import ChartMsg from '@/components/Analysis/Index.vue';
|
||||
@@ -35,12 +41,20 @@ import YlTable from '@/components/YlTable/Index.vue';
|
||||
import { ref } from 'vue';
|
||||
// questionTypeMap 自己去对应
|
||||
const showChart = ref([1, 2, 5, 106, 9, 10]);
|
||||
const sn = defineModel('sn');
|
||||
const { questionAnalysis } = useFetchAnalysis(sn.value as string);
|
||||
// const showTable = ref([1,2,4])
|
||||
const sn = defineModel('sn', { required: true });
|
||||
|
||||
// 接受上级传递的 questionAnalysis 数据
|
||||
const analysis = defineModel<any[]>('questionAnalysis');
|
||||
|
||||
// 如果没有接收到数据,那么就去请求
|
||||
if (!analysis.value) {
|
||||
console.log('repeat fetch analysis');
|
||||
const { questionAnalysis } = useFetchAnalysis(sn.value as string);
|
||||
analysis.value = questionAnalysis.value;
|
||||
}
|
||||
|
||||
// 构建表头
|
||||
const getTableHeadProps = (values: any[], option) => {
|
||||
const getTableHeadProps = (values: any[], option: any[]) => {
|
||||
const head = [];
|
||||
|
||||
if (values && values.length > 0) {
|
||||
@@ -63,7 +77,6 @@ const getTableHeadProps = (values: any[], option) => {
|
||||
}
|
||||
return head;
|
||||
};
|
||||
// 构建表格数据
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.mt10 {
|
||||
|
||||
@@ -4,7 +4,7 @@ export const series = ref({
|
||||
name: 'yl form chart',
|
||||
type: 'pie',
|
||||
radius: ['30%', '50%'],
|
||||
center: ['50%', '30%'],
|
||||
center: ['50%', '35%'],
|
||||
data: [
|
||||
{ value: 1048, name: 'Search Engine' },
|
||||
{ value: 735, name: 'Direct' },
|
||||
|
||||
@@ -14,7 +14,8 @@ sn.value = sn.value ?? (route.query.sn as string);
|
||||
const { quota, random, cycle, loading } = fetchLogicInfo(sn.value);
|
||||
|
||||
const activeTab = ref(0);
|
||||
const tabs = ref<LogicInfoTab[]>([
|
||||
|
||||
const tabs = computed(() => [
|
||||
{
|
||||
title: '逻辑配额',
|
||||
props: [
|
||||
@@ -23,7 +24,7 @@ const tabs = ref<LogicInfoTab[]>([
|
||||
{ prop: 'sample_number', label: '样本量', width: 90 },
|
||||
{ prop: 'percent', label: '进度', width: 90 }
|
||||
],
|
||||
data: quota.value as any
|
||||
data: quota.value
|
||||
},
|
||||
{
|
||||
title: '随机题组配额',
|
||||
@@ -33,7 +34,7 @@ const tabs = ref<LogicInfoTab[]>([
|
||||
{ prop: 'sample_num', label: '样本量', width: 120 },
|
||||
{ prop: 'precent', label: '进度', width: 120 }
|
||||
],
|
||||
data: random.value as any
|
||||
data: random.value
|
||||
},
|
||||
{
|
||||
title: '循环题组配额',
|
||||
@@ -43,25 +44,23 @@ const tabs = ref<LogicInfoTab[]>([
|
||||
{ prop: 'sample_num', label: '样本量', width: 80 },
|
||||
{ prop: 'precent', label: '进度', width: 120 }
|
||||
],
|
||||
data: cycle.value as any
|
||||
data: cycle.value
|
||||
}
|
||||
]);
|
||||
|
||||
// 自动计算是否有 card 区域,只显示有数据的标签页
|
||||
const currentTabs = computed(() => {
|
||||
return tabs.value.filter((item) => {
|
||||
return item.data.length > 0;
|
||||
return item.data && item.data.length > 0;
|
||||
});
|
||||
});
|
||||
|
||||
// 自动计算是否有 card 区域
|
||||
const visibleQuestionConfig = computed(() => {
|
||||
return tabs.value.filter((item) => {
|
||||
return item.data.length > 0;
|
||||
});
|
||||
});
|
||||
// 调试信息
|
||||
const debug = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-cell class="logic-info" v-if="visibleQuestionConfig.length > 0">
|
||||
<van-cell class="logic-info" v-if="currentTabs.length > 0">
|
||||
<template #extra>
|
||||
<section style="width: 86vw" v-loading="loading">
|
||||
<!-- tabs 选项列表 -->
|
||||
|
||||
@@ -69,7 +69,14 @@ export default defineConfig(({ mode }) => {
|
||||
cacheDir: '.tmp',
|
||||
plugins: [
|
||||
vueDevTools(),
|
||||
vue(),
|
||||
vue({
|
||||
template: {
|
||||
compilerOptions: {
|
||||
// 将 swiper 相关标签注册为自定义元素
|
||||
isCustomElement: (tag) => tag.startsWith('swiper-')
|
||||
}
|
||||
}
|
||||
}),
|
||||
vueJsx(),
|
||||
AutoImport({ resolvers: [VantResolver(), ElementPlusResolver()] }),
|
||||
Components({ resolvers: [VantResolver(), ElementPlusResolver()] }),
|
||||
|
||||
Reference in New Issue
Block a user