feat/design: 优化矩阵题样式和功能
- 新增矩阵题类型的支持和样式 - 修复矩阵题选项保存逻辑 -优化矩阵题输入框样式 - 新增项目名称保存功能 - 调整问卷创建页面逻辑
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -40,6 +40,7 @@ declare module 'vue' {
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanRow: typeof import('vant/es')['Row']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanStep: typeof import('vant/es')['Step']
|
||||
VanStepper: typeof import('vant/es')['Stepper']
|
||||
VanSwitch: typeof import('vant/es')['Switch']
|
||||
VanTab: typeof import('vant/es')['Tab']
|
||||
|
||||
@@ -43,3 +43,10 @@ export function saveSettings(params) {
|
||||
data: params
|
||||
});
|
||||
}
|
||||
export function saveProjectName(sn, params) {
|
||||
return request({
|
||||
url: `/console/surveys/${sn}/project_name`,
|
||||
method: 'PATCH',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
}
|
||||
|
||||
input {
|
||||
outline-color: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.el-input__wrapper,
|
||||
|
||||
@@ -235,7 +235,6 @@ const questionMove = (action) => {
|
||||
const temp = questions.value[props.questionIndex];
|
||||
questions.value.splice(props.questionIndex, 1);
|
||||
questions.value.splice(props.questionIndex + 1, 0, temp);
|
||||
|
||||
emit('move', 'down');
|
||||
} else if (action.action === 'up') {
|
||||
if (props.questionIndex === 0) {
|
||||
@@ -247,14 +246,12 @@ const questionMove = (action) => {
|
||||
emit('move', 'up');
|
||||
} else {
|
||||
// 复制 题目 生成新的id 更新最新的 last index
|
||||
const temp = questions.value[props.questionIndex];
|
||||
|
||||
const temp = JSON.parse(JSON.stringify(questions.value[props.questionIndex]));
|
||||
const newQuestion = {
|
||||
...temp,
|
||||
id: uuidv4(),
|
||||
question_index: questionsInfo.value.survey.last_question_index + 1
|
||||
};
|
||||
|
||||
questions.value.splice(props.questionIndex + 1, 0, newQuestion);
|
||||
questionsInfo.value.survey.last_question_index += 1;
|
||||
emit('copy', newQuestion);
|
||||
|
||||
@@ -12,10 +12,13 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min_select = Number(value);
|
||||
actionQuestion.config.min_select = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
<!-- <template #input>-->
|
||||
<!-- <van-step></van-step>-->
|
||||
<!-- </template>-->
|
||||
<template #right-icon>
|
||||
<span>个</span>
|
||||
</template>
|
||||
@@ -31,7 +34,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.max_select = Number(value);
|
||||
actionQuestion.config.max_select = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.line_height = Number(value);
|
||||
actionQuestion.config.line_height = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -52,7 +52,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.line_height = Number(value);
|
||||
actionQuestion.config.line_height = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -90,7 +90,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min = Number(value);
|
||||
actionQuestion.config.min = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -110,7 +110,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.max = Number(value);
|
||||
actionQuestion.config.max = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -151,7 +151,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.line_height = Number(value);
|
||||
actionQuestion.config.line_height = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -170,7 +170,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.line_height = Number(value);
|
||||
actionQuestion.config.line_height = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min_number = Number(value);
|
||||
actionQuestion.config.min_number = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -31,7 +31,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.max_number = Number(value);
|
||||
actionQuestion.config.max_number = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -53,7 +53,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min_size = Number(value);
|
||||
actionQuestion.config.min_size = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -72,7 +72,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.max_size = Number(value);
|
||||
actionQuestion.config.max_size = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min_select = Number(value);
|
||||
actionQuestion.config.min_select = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -95,7 +95,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.min_select = Number(value);
|
||||
actionQuestion.config.min_select = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
@@ -114,7 +114,7 @@
|
||||
@blur="emit('saveOption')"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
actionQuestion.config.max_select = Number(value);
|
||||
actionQuestion.config.max_select = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
|
||||
@@ -120,14 +120,14 @@ function emitInfo() {
|
||||
}
|
||||
|
||||
function intervalChange(value) {
|
||||
localConfig.value.score_interval = Number(value) === 0 ? 1 : Number(value);
|
||||
localConfig.value.score_interval = value === 0 ? 1 : value;
|
||||
setDefaultMax();
|
||||
emitInfo();
|
||||
}
|
||||
|
||||
const minChange = (value) => {
|
||||
const oldMax = Number(props.config.min);
|
||||
localConfig.value.min = Number(value);
|
||||
localConfig.value.min = value;
|
||||
if (localConfig.value.min > localConfig.value.max) {
|
||||
localConfig.value.min = oldMax;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ const minChange = (value) => {
|
||||
|
||||
function maxChange(value) {
|
||||
const oldMax = Number(props.config.max);
|
||||
localConfig.value.max = Number(value);
|
||||
localConfig.value.max = value;
|
||||
if (!isSurplus()) {
|
||||
localConfig.value.max = oldMax;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.v
|
||||
import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
||||
import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
|
||||
|
||||
const question = defineModel<question>('element', { default: () => ({}), required: false });
|
||||
const question = defineModel<question>('element', {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line
|
||||
const activeComponent = computed<Component>(() => {
|
||||
switch (question.value.question_type) {
|
||||
@@ -33,30 +38,33 @@ console.log(rows.value, cols.value);
|
||||
active: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:element']);
|
||||
const emitValue = () => {
|
||||
emit('update:element', element.value);
|
||||
console.log(question.value);
|
||||
emit('update:element', question.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-field
|
||||
v-model="element.stem"
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
v-model="question.stem"
|
||||
:label="question.stem"
|
||||
:required="question.config.is_required === 1"
|
||||
label-align="top"
|
||||
class="contenteditable-question-title"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
<!-- 使用 title 插槽来自定义标题 -->
|
||||
<template #label>
|
||||
<h1>
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="emitValue" />
|
||||
</h1>
|
||||
<contenteditable v-model="question.stem" :active="active" @blur="emitValue" />
|
||||
</template>
|
||||
|
||||
<template #input>
|
||||
<!-- <div style="width: 1000px; overflow: scroll">-->
|
||||
<Component :is="activeComponent" v-model:rows="rows" v-model:cols="cols" />
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
<!-- 使用 label 插槽来自定义标题 -->
|
||||
<!-- <template #input>-->
|
||||
@@ -104,7 +112,7 @@ const emitValue = () => {
|
||||
<!-- </template>-->
|
||||
</van-field>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.matrix-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
@@ -116,8 +124,6 @@ const emitValue = () => {
|
||||
|
||||
th,
|
||||
td {
|
||||
//min-width: 80px;
|
||||
//padding: 8px;
|
||||
border-width: 0 0 1px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -126,24 +132,4 @@ const emitValue = () => {
|
||||
.td-input {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
width: 85%;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
outline: 1px solid #ddd;
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
background-color: red;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type='radio'] {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
<th v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
class="van-icon matrix-checkbox"
|
||||
type="checkbox"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
@@ -114,4 +115,38 @@ function handleMatrixRadioChange(row: number, col: number) {
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/css/theme';
|
||||
|
||||
.matrix-table {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.matrix-checkbox {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border: 1px solid #f4f4f4;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
appearance: none; /* 去除默认样式 */
|
||||
//transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.matrix-checkbox:checked {
|
||||
border-color: transparent; /* 选中时边框颜色 */
|
||||
}
|
||||
|
||||
.matrix-checkbox:checked::before {
|
||||
content: '\e728';
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background-color: $theme-color; /* 选中颜色 */
|
||||
color: #fff;
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="radio"
|
||||
class="van-icon matrix-radio"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@@ -97,4 +98,38 @@ const emitValue = () => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/css/theme';
|
||||
|
||||
.matrix-table {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.matrix-radio {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border: 1px solid #f4f4f4;
|
||||
border-radius: 50%;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
appearance: none; /* 去除默认样式 */
|
||||
//transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.matrix-radio:checked {
|
||||
border-color: transparent; /* 选中时边框颜色 */
|
||||
}
|
||||
|
||||
.matrix-radio:checked::before {
|
||||
content: '\e728';
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background-color: $theme-color; /* 选中颜色 */
|
||||
color: #fff;
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="请输入"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="getInputValue(rowIndex, colIndex)"
|
||||
@change="handleMatrixTextChange(rowIndex, colIndex, $event)"
|
||||
@@ -95,4 +96,27 @@ function handleMatrixTextChange(row: number, col: number, e: Event) {
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/css/theme';
|
||||
|
||||
.matrix-table {
|
||||
text-align: left;
|
||||
|
||||
tr,
|
||||
td {
|
||||
//width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
width: 70%;
|
||||
padding: 0 5px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: 1px solid #f4f4f4;
|
||||
|
||||
&:focus {
|
||||
outline: 1px solid $theme-color;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -350,7 +350,8 @@ import {
|
||||
saveQuestion,
|
||||
snQuestions,
|
||||
sync,
|
||||
saveSettings
|
||||
saveSettings,
|
||||
saveProjectName
|
||||
} from '@/api/design/index';
|
||||
import Design from '@/views/Design/Index.vue';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
@@ -419,6 +420,10 @@ const saveTitle = () => {
|
||||
sn: route.query.sn,
|
||||
title: questionInfo.value.survey.title,
|
||||
introduction: questionInfo.value.survey.introduction
|
||||
}).then((res) => {
|
||||
if (res.data) {
|
||||
saveProjectName(route.query.sn, { project_name: questionInfo.value.survey.title });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -580,7 +585,7 @@ const previewQuestion = () => {
|
||||
router.push({ name: 'preview', query: { ...route.query } });
|
||||
};
|
||||
|
||||
onMounted(async() => {
|
||||
onMounted(async () => {
|
||||
await getQuestionDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user