| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- <!-- 题目配置 -->
- <template>
- <div class="test_question_config">
- <Form
- :v-model:formRef="formRefDom"
- :form-item-list="finalFormItemList"
- :default-form-data="questionFormData"
- @form-item-change="HandleFormItemChange"
- labelWidth="92px"
- >
- <template #questionType>
- <div class="question_type">
- <!-- 题目类型下拉 -->
- <el-select
- v-model="questionFormData.questionType"
- class="type_select"
- @change="(val)=>HandleFormItemChange({key:'question_type',val,formData:questionFormData})"
- placeholder="请选择">
- <el-option
- v-for="selectItem in questionTypeOptions"
- :key="selectItem.value"
- :label="selectItem.label"
- :value="selectItem.value"
- />
- </el-select>
- <!-- 题目额外 展示配置 -->
- <el-checkbox-group
- class="type_cofig_check"
- v-model="questionFormData.extraConfig"
- >
- <el-checkbox
- v-for="checkItem in questionConfig"
- :key="checkItem.value"
- :label="checkItem.label"
- :value="checkItem.value"
- />
- </el-checkbox-group>
- </div>
- </template>
- <template #evaluationType="{formData}">
- <div class="score_reviewType">
- <el-radio-group v-model="questionFormData.evaluationType">
- <el-radio v-for="radioItem in scoreReviewTypeList" :key="radioItem.value" :value="radioItem.value">{{ radioItem.label }}</el-radio>
- </el-radio-group>
- <ul class="num_score" v-if="Number(formData.evaluationType) === 0 && Number(formData.questionScore)">
- <li v-for="value in Number(formData.questionScore)">
- {{ value }}分
- </li>
- </ul>
- <div class="star_score" v-else-if="Number(formData.evaluationType) === 1 && Number(formData.questionScore)">
- 非常不满意
- <el-rate size="large"
- :model-value="0"
- :disabled="true"
- disabled-void-color="#c6d1de"
- disabled-void-icon="Star"
- :max="Number(formData.questionScore)"
- clearable />
- 非常满意
- </div>
- </div>
- </template>
- <template #options="{ formData }">
- <div class="options_list_container">
- <div v-for="(option) in formData.options" :key="option.id" class="option_item">
- <div class="input_option">
- <el-input
- v-model="option.content"
- placeholder="请输入选项内容"
- />
- <template v-if="displayMode === 'statistic'">
- <el-icon
- class="delete_icon"
- @click="removeOption(option.id)"
- >
- <Close/>
- </el-icon>
- <!-- <div class="blank_icon" v-else></div> -->
- </template>
-
- </div>
- <div v-if="displayMode === 'scored'" class="score_option">
- <span class="row_label">选项分值:</span>
- <el-input
- v-model="option.score"
- placeholder="请输入分值"
- />
- <el-icon
- class="delete_icon"
- @click="removeOption(option.id)"
- >
- <Close/>
- </el-icon>
- <!-- <div class="blank_icon" v-else></div> -->
- </div>
-
- </div>
- </div>
-
- <div class="add_option_area">
- <el-button type="primary" link @click="addOption">
- <el-icon><CirclePlus /></el-icon>
- 添加选项
- </el-button>
- </div>
- </template>
- <template #submit="{formRef,formData}">
- <div class="action_bar">
- <el-button class="button_background" @click="HandleAddConfirm({formRef,formData})">确定</el-button>
- <el-button class="button_refresh">取消</el-button>
- </div>
- </template>
- </Form>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, computed, watch } from 'vue'
- import { Close, CirclePlus } from '@element-plus/icons-vue'
- import Form from '@/baseComponents/Form.vue'
- import { questionFormItemList } from './form'
- import {
- statisticQuestionType, scoredQuestionType
- } from './questionTypeList'
- type DisplayMode = 'scored' | 'statistic'
- interface Option {
- content: String
- score?: String
- id?: Number
- }
- interface FormData {
- questionTitleName: String //题目名称
- questionScore?: String //题目分值
- questionType: String //题目类型
- extraConfig: String[] // 是否必答 required, 是否横排 isHorizontal
- options: Option[], //单选/多选 的 选项配置
- evaluationType?:Number, // 评价题 评分的展示形式
- }
- const props = defineProps({
- displayMode: { // 展示形式 带分值 scored 不带分值 statistic
- type: String as () => DisplayMode,
- default: 'statistic',
- required:true,
- },
- defaultFormData:{
- type:Object as ()=> FormData,
- }
- })
- const emit = defineEmits(['confirm', 'cancel', 'formChange'])
- const formRefDom = ref()
- // 试题题目信息
- const questionFormData = ref<FormData>({
- questionTitleName: '',
- questionScore: '',
- questionType: '',
- extraConfig: ['required'], //默认勾选必答题
- options: [],
- evaluationType:0 //默认展示 数字式
- })
- /*
- 监听 props.displayMode 展示 不同的 题型配置 和 试卷配置
- */
- // 题型选项配置 监听 动态切换
- const questionTypeOptions = computed(() => {
- if (props.displayMode === 'scored') {
- return [...scoredQuestionType.value]
- } else {
- return [... statisticQuestionType.value]
- }
- })
- // 表单试题 展示项配置 监听 表单元素 动态显隐
- const finalFormItemList = computed(() => {
- return questionFormItemList.value.map(item => {
- const newItem = { ...item }
- // 题目分值仅在 scored 模式显示
- if (item.key === 'questionScore') {
- newItem.hidden = props.displayMode !== 'scored'
- }else if(item.key == 'options'){
- // 评价题 和 问答题 不展示 题目子选项配置
- newItem.hidden = [2,5].includes(Number(questionFormData.value.questionType))
- }else if(item.key == 'evaluationType'){
- // 评价题 展示评分的格式
- newItem.hidden = Number(questionFormData.value.questionType) !== 5
- }
- return newItem
- })
- })
- // 试题额外配置项 // 评价题 和 问答题 展示不同的配置项
- const questionConfig = computed(()=>{
- // 评价题 和 问答题
- if([2,5].includes(Number(questionFormData.value.questionType)) ){
- return [
- { label: '必答题', value: 'required' },
- ]
- }else{
- return [
- { label: '必答题', value: 'required' },
- { label: '选项横排', value: 'isHorizontal' }
- ]
- }
- })
- // 评价题 评分形式 列表
- const scoreReviewTypeList = ref([
- {label:'数字式',value:0},
- {label:'星星式', value:1},
- ])
- // 表单内部某些变化 触发 的操作
- const HandleFormItemChange = (params: any) => {
- const { key, val, formData: data } = params
- // console.log('表单项目变化了--',formData)
- emit('formChange', params)
- }
- // 添加题目选项配置
- const addOption = () => {
- questionFormData.value.options.push({ content: '', score: '',id:(Number(questionFormData.value.options[questionFormData.value.options.length - 1]?.id || 0) + 1) })
- }
- // 删除题目选项配置
- const removeOption = (id: number) => {
- questionFormData.value.options = questionFormData.value.options.filter((opt)=>{
- return opt.id !== id
- })
- }
- // 题目信息校验 并传递信息给父级
- const HandleAddConfirm = async (params:any)=>{
- const {formRef,formData} = params
- if (!formRef) return
- await formRef.validate(async(valid) => {
- if (valid) {
- emit('confirm', {formData:formData,formRef})
- }
- }).catch(err=>{
- console.log('报错信息',err)
- })
- }
- // 同步监听 1
- watch(()=>props.defaultFormData,(newVal)=>{
- // 赋值除了类型之外的其他值
- console.log('监听到赋值了',newVal)
- if (newVal) {
- // 避免首次赋值选项置空的情况 _ 待完善 _ 可能发生
- questionFormData.value = newVal
- }
- },{deep:true, immediate:true})
- </script>
- <style lang="scss" scoped>
- .test_question_config {
- padding: 20px;
- background-color: #F8FAFE;
- }
- .question_type{
- display: flex;
- gap:32px;
- align-items: center;
- width: 100%;
- .type_select{
- width: 200px;
- }
- }
- .score_reviewType{
- display: flex;
- flex-direction: column;
- .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;
- }
- }
- }
- // 选项列表样式
- .options_list_container {
- width:100% ;
- display: flex;
- flex-direction: column;
- gap: 16px;
- margin-bottom: 16px;
- .option_item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 16px;
- .input_option{
- width:60% ;
- display: flex;
- align-items: center;
- padding-left: 92px;
- }
- .score_option{
- width: 35%;
- display: flex;
- align-items: center;
- .row_label {
- color: #999999;
- font-size: 14px;
- flex-shrink: 0;
- }
- }
- .input_option,
- .score_option{
- .delete_icon {
- font-size: 20px;
- color: #c0c4cc;
- cursor: pointer;
- margin-left: 20px;
- width: 20px !important;
- height: 20px;
- &:hover {
- color: #f56c6c;
- }
- }
- .blank_icon{
- margin-left: 20px;
- width: 20px !important;
- height: 20px;
- }
- }
- }
- }
- // 添加选项按钮
- .add_option_area {
- margin-left: 92px;
- }
- // 底部操作栏
- .action_bar {
- margin-left: 75px;
- display: flex;
- gap:20px;
- .el-button {
- margin:0;
- padding:10px 36px;
- height: 40px;
- }
- }
- // 表单项样式
- :deep(.el-form) {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- gap: 16px 0;
- .el-form-item {
- margin: 0px;
- &.custom_itm {
- width: 100%;
- .el-form-item__content{
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- }
- }
- &.percent_70 {
- width: 60%;
- }
- &.percent_30 {
- width: 35%;
- }
- }
- }
- </style>
|