lm 1 месяц назад
Родитель
Сommit
b669bfa51c

+ 128 - 0
src/components/QuestionTypeShow.vue

@@ -0,0 +1,128 @@
+<template>
+    <!-- 单选  -->
+    <el-radio-group 
+        v-if="[0,3].includes(Number(questionType))" 
+        :class="{vertical:!isHorizontal}"> 
+        <el-radio v-for="radioItem in questionSubOptions" 
+            :key="radioItem.value" 
+            :value="radioItem.value"
+        >{{ radioItem.label }}</el-radio>
+    </el-radio-group>
+        
+    <!-- 多选 -->
+    <el-checkbox-group 
+        v-else-if="Number(questionType) === 1" 
+        :class="{vertical:!isHorizontal}">
+
+        <el-checkbox 
+            v-for="checkItem in questionSubOptions" 
+            :key="checkItem.value"
+            :label="checkItem.label"
+            :value="checkItem.value"
+        />
+    </el-checkbox-group>
+
+    <!-- 问答题 -->
+    <el-input  
+        v-else-if="Number(questionType) === 2"
+        :autosize="{ minRows:5, maxRows: 5 }" 
+        type="textarea" 
+        :rows="5"  
+        placeholder="不超过2000字"
+    />
+
+    <!-- 评价(分)题 4 -->
+    <template v-else-if="Number(questionType) === 4 ">
+        <ul class="num_score" v-if="Number(scoreReviewType) === 0 && Number(titleScore)">
+            <li v-for="value in Number(titleScore)">
+                {{ value }}分
+            </li>
+        </ul>
+        <div class="star_score" v-else-if="Number(scoreReviewType) === 1 && Number(titleScore)">
+            非常不满意
+            <el-rate size="large" 
+                :max="Number(titleScore)" 
+                clearable />
+            非常满意
+        </div>
+    </template>
+</template>
+
+
+<script setup lang="ts">
+
+interface Option {
+    label: String
+    score?: String
+    value?: Number
+}
+const props = defineProps({
+    questionType:{  //题目展示类型  单选0/多选1/问答2/评分单选3 / 评分题4
+        type:[Number,String],
+        required:true
+    },
+    isHorizontal:{    //单选/多选 选项 水平/垂直 排列
+        type:Boolean,
+        default:true,
+        required:true
+    },
+    questionSubOptions:{   // 单选/多选 选项列表
+        type:[Array<Option>,null],
+    },
+    scoreReviewType:{    //评分题 分值的展示形式  0 数字  1 星星
+        type:[Number,String,null],
+    },
+    titleScore:{   // 评分题 题目的分值
+        type:[Number,null]
+    }
+
+})
+
+</script>
+
+
+<style lang="scss" scoped>
+
+.el-checkbox-group.vertical,
+.el-radio-group.vertical{
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: flex-start;
+}
+
+
+.num_score,
+.star_score
+{
+    display: flex;
+    align-items: center;
+    gap:16px;
+    color: #CCCCCC;
+    line-height: 1;
+}
+.num_score{
+    flex-wrap: wrap;
+    li{
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        border-radius: 4px ;
+        border: 1px solid #CCCCCC;
+        width: 44px;
+        height: 32px;
+        font-size: 14px;
+        background-color: white;
+    }
+}
+
+.star_score{
+    word-break: keep-all;
+    .el-rate{
+        display: flex;
+        flex-wrap: wrap;
+        gap:10px 20px;
+        height: auto;
+    }
+} 
+</style>

+ 5 - 0
src/router/index.ts

@@ -31,6 +31,11 @@ const routes: Array<RouteRecordRaw> = [
         name: 'createQuestionnaire',
         component: () => import('@/views/surveyManagement/createQuestionnaire/CreateQuestionnaire.vue')
       },
+      {
+        path: 'previewQuestionnaire',
+        name: 'previewQuestionnaire',
+        component: () => import('@/views/surveyManagement/PreviewQuestionnaire.vue')
+      },
       
       {
         path: 'reviewManagement',

+ 165 - 0
src/views/surveyManagement/PreviewQuestionnaire.vue

@@ -0,0 +1,165 @@
+<template>
+    <div  class="main_container">
+          <TopBackNav>
+            <template #topRight>
+                <el-button class="button_refresh" @click="$router.go(-1)">关闭预览</el-button>
+            </template>
+        </TopBackNav>
+
+        <div class="page_jg_20" style="flex-shrink: 0;"></div>
+
+
+        <div class="page_item questionnaire">
+            <!-- 问卷头部 -->
+            <div class="questionnaire_head">
+                <h1 class="head_title">{{ questionaireMsg?.questionnaireTitle }}</h1>
+                <p class="head_desc">{{ questionaireMsg?.questionnaireDesc }}</p>
+            </div>
+
+            <!-- 预览内容列表 -->
+            <ul class="question_list">
+                <li
+                    v-for="(item, index) in questionaireMsg?.quetionList"
+                    :key="item.id"
+                    class="question_card">
+                    
+                    <!-- 题目行 -->
+                    <div class="question_header">
+                        <span class="q_title" :class="{required_mark:isRequired(item)}">{{ index + 1 }}.{{ item.title }}</span>
+                        <span class="q_type_tag">[{{ qustionTypeToName(item.questionType) }}]</span>
+
+                        <div class="operation table_row_option">
+                            <span class="el_button_editor" @click="EditQuestion">编辑</span>
+                            <span class="el_button_delete" @click="DeleteQuestion(item)">删除</span>
+                        </div>
+                    </div>
+
+                    <!-- 题目内容区域 -->
+                    <div class="question_body">
+                        <QuestionTypeShow 
+                            :isHorizontal="item.extraConfig.includes('isHorizontal')"
+                            :questionType="Number(item.questionType)"
+                            :questionSubOptions="item.options"
+                            :scoreReviewType="Number(item.scoreReviewType)"
+                            :titleScore="Number(item.titleScore)"
+                        ></QuestionTypeShow>
+                    </div>
+                </li>
+            </ul>
+        </div>
+    </div>
+
+</template>
+
+<script setup lang="ts">
+import { onMounted,ref } from 'vue';
+import TopBackNav from '@/components/TopBackNav.vue';
+import {qustionTypeToName} from '@/components/questionConfig/questionTypeList'
+import QuestionTypeShow from '@/components/QuestionTypeShow.vue';
+
+// 问卷信息
+const questionaireMsg = ref()
+// 辅助函数:判断是否必填
+const isRequired = (item) => {
+  return item.extraConfig && item.extraConfig.includes('required');
+};
+
+const DeleteQuestion = (row)=>{
+
+}
+const EditQuestion = ()=>{
+    
+}
+
+onMounted(()=>{
+    questionaireMsg.value = JSON.parse(sessionStorage.getItem('questionnaire') || '{}')
+})
+
+</script>
+
+
+
+<style lang="scss" scoped>
+.questionnaire {
+    max-width: 800px;
+    margin: 0 auto;
+    padding:20px 0;
+    
+    /* --- 头部样式 --- */
+    .questionnaire_head {
+        text-align: center;
+        margin-bottom: 40px;
+
+        .head_title {
+            font-size: 24px;
+            font-weight: bold;
+            color: #000;
+            margin-bottom: 16px;
+        }
+
+        .head_desc {
+            font-size: 14px;
+            color: #999999;
+            line-height: 1.6;
+            margin: 0;
+        }
+    }
+
+    .question_list{
+        display: flex;
+        flex-direction: column;
+        gap:20px;
+
+        /* --- 题目卡片样式 --- */
+        .question_card {
+            padding: 10px 20px;
+            .question_header {
+                display: flex;
+                align-items: baseline;
+                margin-bottom: 15px;
+                font-size: 14px;
+                color: #000;
+
+                .q_title {
+                    &.required_mark {
+                        padding-right: 6px;
+                        position: relative;
+                        &::after{
+                            position: absolute;
+                            right: 0;
+                            content:'*';
+                            width: 5px;
+                            color: #f56c6c;
+                            margin-left: 2px;
+                            font-size: 18px;
+                        }
+                    }
+                }
+                .q_type_tag {
+                    color: #2E64FA;
+                    font-size: 14px;
+                    margin-left: 8px;
+                    font-weight: normal;
+                }
+
+                .operation{
+                    flex: 1 1;
+                    display: none;
+                    justify-content: flex-end;
+                    gap:20px;
+
+                }
+            }
+
+            &:hover{
+                box-shadow: 0px 10px 20px 0px rgba(46,100,250,0.1), 
+                            0px -10px 20px 0px rgba(46,100,250,0.1);
+                .question_header .operation{
+                    display: flex;
+                }
+            }
+        }
+    }
+}
+
+</style>

+ 32 - 106
src/views/surveyManagement/createQuestionnaire/CreateQuestionnaire.vue

@@ -3,8 +3,8 @@
         <TopBackNav>
             <template #topRight>
                 <span class="paper_score">阅卷总分:<span class="score">{{questionTotalScore}}分</span></span>
-                <el-button class="button_refresh">预览问卷</el-button>
-                <el-button class="button_background" @click="HandleQuestionnaireSave">保存问卷</el-button>
+                <el-button class="button_refresh" @click="PreviewQuestionnaire">预览问卷</el-button>
+                <el-button class="button_background" @click="SaveQuestionnaire">保存问卷</el-button>
             </template>
         </TopBackNav>
 
@@ -59,57 +59,17 @@
                             {{index + 1}}.{{ question.title }}
                             <span class="question_type">[{{ qustionTypeToName(question.questionType) }}]</span>
                         </div>
-
-                        <!-- 单选  -->
-                        <el-radio-group 
-                            v-if="[0,3].includes(Number(question.questionType))" 
-                            :class="{vertical:!question.extraConfig.includes('isHorizontal')}"> 
-
-                            <el-radio v-for="radioItem in question.options" :key="radioItem.value" :value="radioItem.value">{{ radioItem.label }}</el-radio>
-                        </el-radio-group>
-                            
-                        <!-- 多选 -->
-                        <el-checkbox-group 
-                            v-else-if="Number(question.questionType) === 1" 
-                            :class="{vertical:!question.extraConfig.includes('isHorizontal')}">
-
-                            <el-checkbox 
-                            v-for="checkItem in question.options" 
-                            :key="checkItem.value"
-                            :label="checkItem.label"
-                            :value="checkItem.value"
-                            />
-                        </el-checkbox-group>
-
-                        <!-- 问答题 -->
-                        <el-input  
-                            v-else-if="Number(question.questionType) === 2"
-                            :autosize="{ minRows:5, maxRows: 5 }" 
-                            type="textarea" 
-                            :rows="5"  
-                            placeholder="不超过2000字"
-                        />
-
-                        <!-- 评价(分)题 4 -->
-                        <template v-else-if="Number(question.questionType) === 4 ">
-                            <ul class="num_score" v-if="Number(question.scoreReviewType) === 0 && Number(question.titleScore)">
-                                <li v-for="value in Number(question.titleScore)">
-                                    {{ value }}分
-                                </li>
-                            </ul>
-                            <div class="star_score" v-else-if="Number(question.scoreReviewType) === 1 && Number(question.titleScore)">
-                                非常不满意
-                                <el-rate size="large" 
-                                    :max="Number(question.titleScore)" 
-                                    clearable />
-                                非常满意
-                            </div>
-                        </template>
+                        <QuestionTypeShow 
+                            :isHorizontal="question.extraConfig.includes('isHorizontal')"
+                            :questionType="Number(question.questionType)"
+                            :questionSubOptions="question.options"
+                            :scoreReviewType="Number(question.scoreReviewType)"
+                            :titleScore="Number(question.titleScore)"
+                        ></QuestionTypeShow>
                     </li>
                 </ul>
 
 
-
                 <!-- 题目添加区域 -->
                  <div class=" add_question_area">
                     <div v-if="!selectedQuestionType" class="add_question">
@@ -119,7 +79,7 @@
                         <QuestionConfig  
                             :displayMode="selectedQuestionGetScore ? 'scored' : 'statistic'"
                             :questionType="selectedQuestionType"
-                            @confirm="HandleAddQuesiton"
+                            @confirm="AddQuesiton"
                         ></QuestionConfig>
                     </div>
                  </div>
@@ -159,6 +119,8 @@ import { ElMessage } from 'element-plus';
 import { unioformDateTransform } from '@/utils/dateTransform';
 import { useHandleMoveUpAndDown } from '@/baseComponents/useHandleMoveUpAndDown';
 
+import QuestionTypeShow from '@/components/QuestionTypeShow.vue';
+
 import moveUpDownIcon from '@/assets/icon/move_up_down.png'
 
 
@@ -189,6 +151,9 @@ const router = useRouter()
 
 // 试卷头表单
 const questionnaireBaseFormRef = ref()
+// 已存储的试卷整体信息
+const questionnaireMsg = ref()  
+
 // 试卷头基本信息
 const questionnaireInfo = ref<QuestionnaireInfo>({
     questionnaireTitle:'',
@@ -206,6 +171,8 @@ const addedQuestionList = ref<QuestionItm[]>([
         scoreReviewType:''
     }
 ])
+
+
 // 当前选中的题型
 const selectedQuestionType = ref('')
 // 选中题型 是否得分 // 得分题  true  非得分题 false 
@@ -249,7 +216,7 @@ const { HandleDragStart, HandleDragEnd } = useHandleMoveUpAndDown(addedQuestionL
 
 const addedIndex = ref(1)
 // 添加试题信息
-const HandleAddQuesiton = (params)=>{
+const AddQuesiton = (params)=>{
     const {formRef,formData} = params
     console.log('获取到试题信息了',formData)
 
@@ -272,7 +239,7 @@ const HandleAddQuesiton = (params)=>{
 
 
 // 保存试卷
-const HandleQuestionnaireSave = async ()=>{
+const SaveQuestionnaire = async ()=>{
     // 试卷总表单
     let formRef = questionnaireBaseFormRef.value
 
@@ -280,27 +247,23 @@ const HandleQuestionnaireSave = async ()=>{
     await formRef.validate(async(valid) => {
         if (valid) {
             if(addedQuestionList.value.length > 0){
-                let finalQuestionMsg = {
-                    ...(questionnaireInfo.value),
-                    quetionList:addedQuestionList.value
-                }
-                console.log('最终提交的表单信息',finalQuestionMsg)
-
                 /**
                  * 模拟数据
                  */
                 // 模拟保存数据 和页面跳转
                 let questionnaireList = JSON.parse(localStorage.getItem('questionnaireList') || '[]')
-                questionnaireList.push({
-                    ...finalQuestionMsg,
+                
+                questionnaireMsg.value = {
+                    ...(questionnaireInfo.value),
+                    quetionList:addedQuestionList.value,
                     id:Number(questionnaireList[questionnaireList.length - 1]?.id || 0) + 1,
                     createTime:unioformDateTransform(new Date()),
                     createBy:'管理员',
                     totalScore:questionTotalScore.value,
                     useStatus:1
-                })
-                localStorage.setItem('questionnaireList',JSON.stringify(questionnaireList))
-                router.push('/main')
+                }
+                questionnaireList.push(questionnaireMsg.value)
+                localStorage.setItem('questionnaireList',JSON.stringify(questionnaireList.value || []))
             }else{
                 ElMessage.warning('请添加问卷题目')
             }
@@ -308,9 +271,15 @@ const HandleQuestionnaireSave = async ()=>{
     }).catch(err=>{
         console.log('报错信息',err)
     })
+}
 
 
+// 预览试卷
+const PreviewQuestionnaire =()=>{
+    sessionStorage.setItem('questionnaire',JSON.stringify(questionnaireMsg.value || '{}'))
+    router.push(`/main/previewQuestionnaire`)
 }
+
 </script>
 
 <style lang="scss" scoped>
@@ -428,49 +397,6 @@ const HandleQuestionnaireSave = async ()=>{
                         }
                     }
                 }
-
-                .el-checkbox-group.vertical,
-                .el-radio-group.vertical{
-                    display: flex;
-                    flex-direction: column;
-                    justify-content: flex-start;
-                    align-items: flex-start;
-                }
-
-
-                .num_score,
-                .star_score
-                {
-                    display: flex;
-                    align-items: center;
-                    gap:16px;
-                    color: #CCCCCC;
-                    line-height: 1;
-                }
-                .num_score{
-                    flex-wrap: wrap;
-                    li{
-                        display: flex;
-                        justify-content: center;
-                        align-items: center;
-                        border-radius: 4px ;
-                        border: 1px solid #CCCCCC;
-                        width: 44px;
-                        height: 32px;
-                        font-size: 14px;
-                        background-color: white;
-                    }
-                }
-
-                .star_score{
-                    word-break: keep-all;
-                    .el-rate{
-                        display: flex;
-                        flex-wrap: wrap;
-                        gap:10px 20px;
-                        height: auto;
-                    }
-                } 
             }
         }