You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
747 lines
19 KiB
747 lines
19 KiB
<!--
|
|
* 警务评议与问题处置 - 可视化问卷设计画布
|
|
*
|
|
* @Author: Antigravity
|
|
* @Date: 2026-06-10
|
|
-->
|
|
<template>
|
|
<div class="page-container flex-layout">
|
|
<!-- 顶部状态导航栏 -->
|
|
<div class="designer-header">
|
|
<div class="left-info">
|
|
<a-button @click="handleBack" class="back-btn">
|
|
<template #icon><ArrowLeftOutlined /></template>
|
|
返回列表
|
|
</a-button>
|
|
<span class="divider">|</span>
|
|
<span class="survey-title">正在设计:<strong>{{ surveyInfo.title || '测评问卷' }}</strong></span>
|
|
<a-tag :color="getBizTypeColor(surveyInfo.sjlyNo)" style="margin-left: 8px">
|
|
<DictLabel :dict-code="DICT_CODE_ENUM.BUSINESS_CLASSIFICATION" :data-value="surveyInfo.sjlyNo" />
|
|
</a-tag>
|
|
</div>
|
|
<div class="right-actions">
|
|
<a-button @click="handlePreview" style="margin-right: 8px">
|
|
<template #icon><EyeOutlined /></template>
|
|
预览问卷
|
|
</a-button>
|
|
<a-button type="primary" @click="handleSave" :loading="saving">
|
|
<template #icon><SaveOutlined /></template>
|
|
保存问卷设计
|
|
</a-button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 主设计区域 (左右分栏布局) -->
|
|
<div class="designer-main">
|
|
<!-- 左侧:题型控件区 -->
|
|
<div class="left-panel">
|
|
<h3 class="panel-title">添加题目控件</h3>
|
|
<div class="widget-list">
|
|
<div class="widget-item" @click="addQuestion('rate')">
|
|
<span class="widget-icon"><StarOutlined /></span>
|
|
<span class="widget-label">星级打分题</span>
|
|
</div>
|
|
<div class="widget-item" @click="addQuestion('radio')">
|
|
<span class="widget-icon"><BorderInnerOutlined /></span>
|
|
<span class="widget-label">单项选择题</span>
|
|
</div>
|
|
<div class="widget-item" @click="addQuestion('checkbox')">
|
|
<span class="widget-icon"><AppstoreOutlined /></span>
|
|
<span class="widget-label">多项选择题</span>
|
|
</div>
|
|
<div class="widget-item" @click="addQuestion('textarea')">
|
|
<span class="widget-icon"><FormOutlined /></span>
|
|
<span class="widget-label">群众意见框 (多行文本)</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="designer-tips-card">
|
|
<div class="tips-title"><InfoCircleOutlined /> 逻辑跳转与满意度规则</div>
|
|
<p class="tips-text">1. 在选择题中,可以为不同的选项配置【跳转逻辑】(如不满意自动跳到特定细化题)。</p>
|
|
<p class="tips-text">2. 可以为每个单选项设置对应的【选项分值】,系统在提交时会自动求平均值和累加。</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右侧:设计画布区 -->
|
|
<div class="canvas-panel">
|
|
<div v-if="questions.length === 0" class="empty-canvas">
|
|
<a-empty description="画布中空空如也,请点击左侧题型控件添加题目" />
|
|
</div>
|
|
|
|
<div v-else class="question-list">
|
|
<div
|
|
v-for="(q, index) in questions"
|
|
:key="q.id"
|
|
class="question-card"
|
|
:class="{ 'is-active': activeQuestionId === q.id }"
|
|
@click="activeQuestionId = q.id"
|
|
>
|
|
<!-- 题目头部工具栏 -->
|
|
<div class="q-card-header">
|
|
<span class="q-number">Q{{ index + 1 }}</span>
|
|
<span class="q-type-badge">{{ getQuestionTypeLabel(q.type) }}</span>
|
|
|
|
<div class="q-actions" @click.stop>
|
|
<a-button type="text" size="small" :disabled="index === 0" @click="moveQuestion(index, -1)">
|
|
<template #icon><UpOutlined /></template>
|
|
</a-button>
|
|
<a-button type="text" size="small" :disabled="index === questions.length - 1" @click="moveQuestion(index, 1)">
|
|
<template #icon><DownOutlined /></template>
|
|
</a-button>
|
|
<a-popconfirm title="确认删除此题目吗?" @confirm="deleteQuestion(q.id)">
|
|
<a-button type="text" size="small" danger>
|
|
<template #icon><DeleteOutlined /></template>
|
|
</a-button>
|
|
</a-popconfirm>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 题目内容编辑 -->
|
|
<div class="q-card-body">
|
|
<div class="q-title-row">
|
|
<a-input v-model:value="q.title" placeholder="请输入题目名称,例如:您对民警的办事效率是否满意?" class="q-title-input" />
|
|
<a-checkbox v-model:checked="q.required" class="q-req-checkbox">必填</a-checkbox>
|
|
</div>
|
|
|
|
<!-- 打分题特有展示 -->
|
|
<div v-if="q.type === 'rate'" class="q-body-content">
|
|
<a-rate :value="5" disabled />
|
|
<span class="hint-text">( 默认五星满分,一星扣2分 )</span>
|
|
</div>
|
|
|
|
<!-- 选择题特有选项配置 (支持分值、跳题逻辑) -->
|
|
<div v-if="q.type === 'radio' || q.type === 'checkbox'" class="q-body-content">
|
|
<div class="options-header">
|
|
<span class="opt-label-head">选项文字</span>
|
|
<span class="opt-score-head">对应分值</span>
|
|
<span class="opt-jump-head">选项跳题跳转逻辑 (选中时)</span>
|
|
<span class="opt-del-head">操作</span>
|
|
</div>
|
|
|
|
<div v-for="(opt, oIndex) in q.options" :key="oIndex" class="option-row">
|
|
<a-input v-model:value="opt.label" placeholder="选项文字" class="opt-input" />
|
|
<a-input-number v-model:value="opt.score" :min="0" :max="100" class="opt-score-input" placeholder="分值" />
|
|
|
|
<a-select v-model:value="opt.logicJump" placeholder="常规下一题" class="opt-jump-select">
|
|
<a-select-option value="">常规跳转(下一题)</a-select-option>
|
|
<template v-for="(otherQ, otherIndex) in questions">
|
|
<a-select-option v-if="otherIndex > index" :key="otherQ.id" :value="otherQ.id">
|
|
跳至 Q{{ otherIndex + 1 }} ({{ otherQ.title.substring(0, 10) }}...)
|
|
</a-select-option>
|
|
</template>
|
|
<a-select-option value="end">直接结束问卷</a-select-option>
|
|
</a-select>
|
|
|
|
<a-button type="text" danger @click="deleteOption(q, oIndex)" class="opt-del-btn">
|
|
<template #icon><MinusCircleOutlined /></template>
|
|
</a-button>
|
|
</div>
|
|
|
|
<a-button type="dashed" block @click="addOption(q)" style="margin-top: 8px">
|
|
<template #icon><PlusOutlined /></template>
|
|
添加新选项
|
|
</a-button>
|
|
</div>
|
|
|
|
<!-- 多行文本题特有展示 -->
|
|
<div v-if="q.type === 'textarea'" class="q-body-content">
|
|
<a-textarea placeholder="群众意见输入框占位符预览..." :rows="2" disabled />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 问卷手机填报端预览 Modal -->
|
|
<a-modal
|
|
v-model:open="previewVisible"
|
|
title="问卷手机填报效果预览"
|
|
:footer="null"
|
|
:width="420"
|
|
wrapClassName="phone-preview-modal"
|
|
>
|
|
<div class="phone-frame">
|
|
<div class="phone-screen">
|
|
<div class="phone-header">
|
|
<span class="phone-title">{{ surveyInfo?.title || '民意测评问卷' }}</span>
|
|
</div>
|
|
<div class="phone-content" v-if="questions.length > 0">
|
|
<div class="survey-intro">
|
|
您好!为了进一步提升我们的政务服务品质,耽误您1分钟时间参与本次民意调查测评,感谢您的配合!
|
|
</div>
|
|
|
|
<!-- 使用通用问卷渲染器 -->
|
|
<SurveyFormRenderer :questions="questions" v-model:value="previewAnswers" />
|
|
|
|
<a-button type="primary" block size="large" style="margin-top: 24px; border-radius: 8px" @click="handleSubmitPreview">
|
|
模拟提交问卷
|
|
</a-button>
|
|
</div>
|
|
<div class="phone-content empty-preview" v-else>
|
|
<a-empty description="该问卷尚未配置题目,请先前往左侧添加题目" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a-modal>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue';
|
|
import SurveyFormRenderer from '../my-survey/components/SurveyFormRenderer.vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import { message } from 'ant-design-vue';
|
|
import {
|
|
ArrowLeftOutlined,
|
|
SaveOutlined,
|
|
StarOutlined,
|
|
BorderInnerOutlined,
|
|
AppstoreOutlined,
|
|
FormOutlined,
|
|
InfoCircleOutlined,
|
|
UpOutlined,
|
|
DownOutlined,
|
|
DeleteOutlined,
|
|
MinusCircleOutlined,
|
|
PlusOutlined,
|
|
EyeOutlined
|
|
} from '@ant-design/icons-vue';
|
|
import DictLabel from '/@/components/support/dict-label/index.vue';
|
|
import { DICT_CODE_ENUM } from '/@/constants/support/dict-const';
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
|
|
import { surveySampleApi } from '/@/api/business/jwpy/survey-sample-api';
|
|
|
|
const surveyId = ref(null);
|
|
const surveyInfo = ref({});
|
|
const questions = ref([]);
|
|
const activeQuestionId = ref(null);
|
|
const saving = ref(false);
|
|
|
|
// 加载问卷详情
|
|
const loadSurveyDetails = async () => {
|
|
surveyId.value = Number(route.query.id);
|
|
if (!surveyId.value) {
|
|
message.error('未指定问卷模板ID');
|
|
router.push('/mydc/questionnaire');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await surveySampleApi.querySurveys({ pageNum: 1, pageSize: 500 });
|
|
const localSurveys = res.data?.list || [];
|
|
const found = localSurveys.find(item => item.surveyId === surveyId.value);
|
|
if (found) {
|
|
surveyInfo.value = found;
|
|
try {
|
|
questions.value = found.content ? JSON.parse(found.content) : [];
|
|
if (questions.value.length > 0) {
|
|
activeQuestionId.value = questions.value[0].id;
|
|
}
|
|
} catch (e) {
|
|
questions.value = [];
|
|
}
|
|
} else {
|
|
message.error('未找到对应问卷模板,已自动返回列表');
|
|
router.push('/mydc/questionnaire');
|
|
}
|
|
} catch (err) {
|
|
message.error('加载问卷模板详情失败');
|
|
}
|
|
};
|
|
|
|
// 增加题目控件
|
|
const addQuestion = (type) => {
|
|
const newQ = {
|
|
id: 'q_' + Date.now(),
|
|
type: type,
|
|
title: '',
|
|
required: true,
|
|
options: []
|
|
};
|
|
|
|
// 如果是选择题,默认给两个选项
|
|
if (type === 'radio' || type === 'checkbox') {
|
|
newQ.options = [
|
|
{ label: '满意', score: 10, logicJump: '' },
|
|
{ label: '不满意', score: 2, logicJump: '' }
|
|
];
|
|
}
|
|
|
|
questions.value.push(newQ);
|
|
activeQuestionId.value = newQ.id;
|
|
message.success('已添加新题目');
|
|
};
|
|
|
|
// 题目删除
|
|
const deleteQuestion = (id) => {
|
|
questions.value = questions.value.filter(q => q.id !== id);
|
|
if (activeQuestionId.value === id && questions.value.length > 0) {
|
|
activeQuestionId.value = questions.value[0].id;
|
|
}
|
|
};
|
|
|
|
// 题目位置移动
|
|
const moveQuestion = (index, direction) => {
|
|
const targetIndex = index + direction;
|
|
if (targetIndex < 0 || targetIndex >= questions.value.length) return;
|
|
const temp = questions.value[index];
|
|
questions.value[index] = questions.value[targetIndex];
|
|
questions.value[targetIndex] = temp;
|
|
};
|
|
|
|
// 添加选项
|
|
const addOption = (q) => {
|
|
q.options.push({ label: '新选项', score: 10, logicJump: '' });
|
|
};
|
|
|
|
// 删除选项
|
|
const deleteOption = (q, oIndex) => {
|
|
if (q.options.length <= 1) {
|
|
message.warning('选项至少保留 1 个');
|
|
return;
|
|
}
|
|
q.options.splice(oIndex, 1);
|
|
};
|
|
|
|
// 题型标签
|
|
const getQuestionTypeLabel = (type) => {
|
|
const map = {
|
|
'rate': '五星打分题',
|
|
'radio': '单项选择题',
|
|
'checkbox': '多项选择题',
|
|
'textarea': '多行文本框'
|
|
};
|
|
return map[type] || '未知题型';
|
|
};
|
|
|
|
// 业务标签颜色
|
|
const getBizTypeColor = (bizType) => {
|
|
const map = { '110': 'red', 'hz': 'blue', 'crj': 'purple', 'cjg': 'green', 'ajbl': 'orange' };
|
|
return map[bizType] || 'cyan';
|
|
};
|
|
|
|
// 保存问卷设计
|
|
const handleSave = async () => {
|
|
const emptyQ = questions.value.some(q => !q.title.trim());
|
|
if (emptyQ) {
|
|
message.warning('画布中存在题目名称未填写的题目,请完善后再保存');
|
|
return;
|
|
}
|
|
|
|
saving.value = true;
|
|
try {
|
|
await surveySampleApi.updateSurvey({
|
|
surveyId: surveyId.value,
|
|
content: JSON.stringify(questions.value)
|
|
});
|
|
message.success('保存成功');
|
|
handleBack();
|
|
} catch (err) {
|
|
message.error('保存设计失败');
|
|
} finally {
|
|
saving.value = false;
|
|
}
|
|
};
|
|
|
|
// 返回上一级
|
|
const handleBack = () => {
|
|
router.push('/mydc/questionnaire');
|
|
};
|
|
|
|
const previewVisible = ref(false);
|
|
const previewAnswers = ref({});
|
|
|
|
const handlePreview = () => {
|
|
previewAnswers.value = {};
|
|
previewVisible.value = true;
|
|
};
|
|
|
|
const handleSubmitPreview = () => {
|
|
message.success('答卷模拟提交成功!');
|
|
previewVisible.value = false;
|
|
};
|
|
|
|
onMounted(() => {
|
|
loadSurveyDetails();
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 全屏弹性高度,锁定滚动条 */
|
|
.flex-layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: calc(100vh - 120px);
|
|
overflow: hidden;
|
|
padding: 16px;
|
|
background-color: #f0f2f5;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 顶部状态栏 */
|
|
.designer-header {
|
|
height: 52px;
|
|
background: #ffffff;
|
|
border-radius: 8px;
|
|
padding: 0 16px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
margin-bottom: 12px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.left-info {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.back-btn {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.divider {
|
|
margin: 0 12px;
|
|
color: #d9d9d9;
|
|
}
|
|
|
|
.survey-title {
|
|
font-size: 15px;
|
|
color: #262626;
|
|
}
|
|
|
|
.right-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
/* 主画布 */
|
|
.designer-main {
|
|
display: flex;
|
|
flex: 1;
|
|
gap: 12px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 左侧:题型控件区 */
|
|
.left-panel {
|
|
width: 260px;
|
|
background: #ffffff;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.panel-title {
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
color: #595959;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.widget-list {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 10px;
|
|
}
|
|
|
|
.widget-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 12px 16px;
|
|
background: #fafafa;
|
|
border: 1px dashed #d9d9d9;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.widget-item:hover {
|
|
background: #e6f7ff;
|
|
border-color: #1890ff;
|
|
color: #1890ff;
|
|
}
|
|
|
|
.widget-icon {
|
|
font-size: 16px;
|
|
margin-right: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.widget-label {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.designer-tips-card {
|
|
margin-top: auto;
|
|
background: #fafafa;
|
|
border: 1px solid #f0f0f0;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
}
|
|
|
|
.tips-title {
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
color: #fa8c16;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.tips-text {
|
|
font-size: 11px;
|
|
color: #8c8c8c;
|
|
line-height: 1.4;
|
|
margin-bottom: 4px;
|
|
}
|
|
.tips-text:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* 画布面板 */
|
|
.canvas-panel {
|
|
flex: 1;
|
|
background: #ffffff;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
overflow-y: auto;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.empty-canvas {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
|
|
.question-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
|
|
/* 题目卡片 */
|
|
.question-card {
|
|
border: 1px solid #f0f0f0;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
background: #fafafa;
|
|
transition: all 0.2s ease;
|
|
position: relative;
|
|
}
|
|
|
|
.question-card:hover {
|
|
border-color: #d9d9d9;
|
|
}
|
|
|
|
.question-card.is-active {
|
|
border-color: #1890ff;
|
|
background: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.08);
|
|
}
|
|
|
|
.q-card-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 12px;
|
|
border-bottom: 1px dashed #f0f0f0;
|
|
padding-bottom: 8px;
|
|
}
|
|
|
|
.q-number {
|
|
font-size: 14px;
|
|
font-weight: 800;
|
|
color: #1890ff;
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.q-type-badge {
|
|
font-size: 11px;
|
|
background: rgba(0, 0, 0, 0.04);
|
|
color: #595959;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.q-actions {
|
|
margin-left: auto;
|
|
display: flex;
|
|
gap: 2px;
|
|
}
|
|
|
|
.q-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.q-title-input {
|
|
flex: 1;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.q-req-checkbox {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.q-body-content {
|
|
background: #fafafa;
|
|
border-radius: 6px;
|
|
padding: 12px;
|
|
border: 1px dashed #f0f0f0;
|
|
}
|
|
|
|
.hint-text {
|
|
font-size: 12px;
|
|
color: #bfbfbf;
|
|
margin-left: 10px;
|
|
}
|
|
|
|
/* 选择题选项表格配置 */
|
|
.options-header {
|
|
display: grid;
|
|
grid-template-columns: 2fr 1fr 2.5fr 40px;
|
|
gap: 8px;
|
|
font-size: 11px;
|
|
color: #8c8c8c;
|
|
padding-bottom: 4px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.option-row {
|
|
display: grid;
|
|
grid-template-columns: 2fr 1fr 2.5fr 40px;
|
|
gap: 8px;
|
|
align-items: center;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.opt-score-input {
|
|
width: 100%;
|
|
}
|
|
|
|
.opt-jump-select {
|
|
width: 100%;
|
|
}
|
|
|
|
.opt-del-btn {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
/* 手机预览容器框 - 打造真机质感 */
|
|
.phone-frame {
|
|
width: 360px;
|
|
height: 600px;
|
|
background: #2f3640;
|
|
border-radius: 36px;
|
|
padding: 12px;
|
|
margin: 0 auto;
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
|
|
position: relative;
|
|
}
|
|
|
|
.phone-screen {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #f5f6fa;
|
|
border-radius: 26px;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 隐藏手机屏内部滚动条 */
|
|
.phone-screen::-webkit-scrollbar {
|
|
width: 4px;
|
|
}
|
|
.phone-screen::-webkit-scrollbar-thumb {
|
|
background: rgba(0, 0, 0, 0.1);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.phone-header {
|
|
height: 50px;
|
|
background: #1890ff;
|
|
color: #ffffff;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
|
|
}
|
|
|
|
.phone-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
padding: 0 16px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.phone-content {
|
|
padding: 16px;
|
|
flex: 1;
|
|
}
|
|
|
|
.survey-intro {
|
|
font-size: 12px;
|
|
color: #7f8c8d;
|
|
line-height: 1.6;
|
|
background: #ffffff;
|
|
border-radius: 8px;
|
|
padding: 10px 12px;
|
|
margin-bottom: 16px;
|
|
border: 1px solid #eef1f6;
|
|
}
|
|
|
|
.preview-q-card {
|
|
background: #ffffff;
|
|
border-radius: 10px;
|
|
padding: 14px;
|
|
margin-bottom: 14px;
|
|
border: 1px solid #eef1f6;
|
|
}
|
|
|
|
.q-title {
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
color: #2c3e50;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.q-req {
|
|
color: #e74c3c;
|
|
margin-right: 3px;
|
|
}
|
|
|
|
.rate-hint {
|
|
margin-left: 10px;
|
|
font-size: 12px;
|
|
color: #f1c40f;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.empty-preview {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
</style>
|
|
|