This commit is contained in:
2026-06-01 17:19:45 +08:00
parent 67e40e36ea
commit 22c82c6751
12 changed files with 748 additions and 115 deletions
@@ -8,6 +8,20 @@ const setting = {
<el-form-item label="详情" prop="description">
<text-editor v-model="formData.description"></text-editor>
</el-form-item>
<el-form-item label="补充填写" prop="fillRequired">
<el-switch
v-model="formData.fillRequired"
active-text="需要填写"
inactive-text="无需填写">
</el-switch>
</el-form-item>
<el-form-item label="填写提示" prop="fillPlaceholder" v-if="formData.fillRequired">
<el-input
maxlength="255"
placeholder="例如:请填写原因"
v-model="formData.fillPlaceholder">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
@@ -26,7 +40,11 @@ const setting = {
methods:{
onOpen(option,ext){
console.log(option)
this.formData = { ...option }
this.formData = {
...option,
fillRequired: !!option.fillRequired,
fillPlaceholder: option.fillPlaceholder || ""
}
this.ext = ext
this.visible = true
},
@@ -20,6 +20,14 @@ const subjectForm = {
placeholder="请输入题目"
style="flex: 1">
</el-input>
<el-button
type="primary"
icon="el-icon-setting"
size="mini"
style="margin-left: 8px;"
@click="openSubjectVisibleSetting(subjectIndex, subject)">
隐显逻辑
</el-button>
</div>
<div class="subject-meta">
@@ -214,6 +222,87 @@ const subjectForm = {
<setting ref="settingRef" @confirm="onSettingConfirm"></setting>
<txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import>
<bank ref="bankRef" @confirm="onBankConfirm"></bank>
<el-dialog
title="设置题目隐显逻辑"
:visible.sync="subjectVisibleSetting.visible"
append-to-body
width="520px">
<el-form :model="subjectVisibleSetting.formData" label-width="110px">
<el-form-item label="启用逻辑">
<el-switch
v-model="subjectVisibleSetting.formData.enabled"
active-text="启用"
inactive-text="关闭">
</el-switch>
</el-form-item>
<template v-if="subjectVisibleSetting.formData.enabled">
<el-form-item label="处理方式">
<el-radio-group v-model="subjectVisibleSetting.formData.action">
<el-radio label="show">选中后显示本题</el-radio>
<el-radio label="hide">选中后隐藏本题</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="条件关系">
<el-radio-group v-model="subjectVisibleSetting.formData.logic">
<el-radio label="AND">并且</el-radio>
<el-radio label="OR">或者</el-radio>
</el-radio-group>
</el-form-item>
<div
v-for="(condition, conditionIndex) in subjectVisibleSetting.formData.conditions"
:key="conditionIndex"
class="subject-visible-condition">
<el-form-item :label="'条件' + (conditionIndex + 1)">
<div style="display: flex; gap: 8px;">
<el-select
v-model="condition.subjectId"
placeholder="请选择触发题目"
style="flex: 1;"
@change="subjectVisibleRuleSubjectChange(condition)">
<el-option
v-for="item in subjectVisibleRuleSubjects"
:key="item.id"
:label="item.title || '未填写题目'"
:value="item.id">
</el-option>
</el-select>
<el-select
v-model="condition.optionId"
placeholder="请选择触发选项"
style="flex: 1;">
<el-option
v-for="item in getSubjectVisibleRuleOptions(condition.subjectId)"
:key="item.id"
:label="item.text || '未填写选项'"
:value="item.id">
</el-option>
</el-select>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeSubjectVisibleRuleCondition(conditionIndex)">
</el-button>
</div>
</el-form-item>
</div>
<el-form-item label="">
<el-button
type="primary"
icon="el-icon-plus"
size="small"
@click="addSubjectVisibleRuleCondition">
添加条件
</el-button>
</el-form-item>
</template>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="subjectVisibleSetting.visible = false">取 消</el-button>
<el-button type="primary" @click="onSubjectVisibleSettingConfirm">确 定</el-button>
</div>
</el-dialog>
</div>
`,
components: {
@@ -230,7 +319,32 @@ const subjectForm = {
subjects: [],
previewDialogVisible: false,
activity: {},
formRules: {}
formRules: {},
subjectVisibleSetting: {
visible: false,
subjectIndex: null,
formData: {
enabled: false,
action: "show",
logic: "AND",
conditions: [
{
subjectId: "",
optionId: ""
}
]
}
}
}
},
computed: {
subjectVisibleRuleSubjects() {
if (this.subjectVisibleSetting.subjectIndex === null) {
return []
}
return this.subjects.filter((item, index) => {
return index < this.subjectVisibleSetting.subjectIndex && item.type !== "text"
})
}
},
methods: {
@@ -351,13 +465,113 @@ const subjectForm = {
//选项设置确认
onSettingConfirm({option, ext}) {
this.subjects[ext.subjectIndex].options[ext.optionIndex] = option
this.$set(this.subjects[ext.subjectIndex].options, ext.optionIndex, option)
console.log(this.subjects[ext.subjectIndex].options[ext.optionIndex])
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "isCorrect", option.isCorrect)
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint)
},
//打开题目隐显逻辑设置,用于配置当前题目受前置选择题的哪个选项控制显示或隐藏
openSubjectVisibleSetting(subjectIndex, subject) {
const conditions = this.buildSubjectVisibleConditions(subject)
this.subjectVisibleSetting.subjectIndex = subjectIndex
this.subjectVisibleSetting.formData = {
enabled: !!subject.visibleRuleEnabled,
action: subject.visibleRuleAction || "show",
logic: subject.visibleRuleLogic || "AND",
conditions
}
this.subjectVisibleSetting.visible = true
},
//构建题目隐显逻辑条件,已有条件按实际数量回显;未配置时默认提供一条空条件
buildSubjectVisibleConditions(subject) {
let visibleRuleConditions = subject.visibleRuleConditions || []
if (typeof visibleRuleConditions === "string") {
try {
visibleRuleConditions = JSON.parse(visibleRuleConditions)
} catch (e) {
visibleRuleConditions = []
}
}
const conditions = visibleRuleConditions || []
const result = conditions.map((condition) => {
return {
subjectId: condition.subjectId || "",
optionId: condition.optionId || ""
}
})
if (result.length === 0) {
result.push({
subjectId: "",
optionId: ""
})
}
return result
},
//根据触发题目获取可选项,用于每条隐显条件选择触发选项
getSubjectVisibleRuleOptions(subjectId) {
const subject = this.subjects.find((item) => {
return item.id === subjectId
})
if (!subject || !subject.options) {
return []
}
return subject.options
},
//切换触发题目后清空当前条件的旧选项,避免保留其他题目的选项导致隐显条件错误
subjectVisibleRuleSubjectChange(condition) {
condition.optionId = ""
},
//添加一条隐显逻辑条件,多个条件通过条件关系字段统一按并且或或者计算
addSubjectVisibleRuleCondition() {
this.subjectVisibleSetting.formData.conditions.push({
subjectId: "",
optionId: ""
})
},
//删除一条隐显逻辑条件,至少保留一条条件用于继续配置
removeSubjectVisibleRuleCondition(conditionIndex) {
if (this.subjectVisibleSetting.formData.conditions.length === 1) {
this.$message.warning("至少保留一条条件")
return
}
this.subjectVisibleSetting.formData.conditions.splice(conditionIndex, 1)
},
//保存题目隐显逻辑到当前题目对象,后续保存题目时随 subjects 一起提交
onSubjectVisibleSettingConfirm() {
const subjectIndex = this.subjectVisibleSetting.subjectIndex
if (subjectIndex === null) {
return
}
const formData = this.subjectVisibleSetting.formData
if (formData.enabled) {
for (let i = 0; i < formData.conditions.length; i++) {
const condition = formData.conditions[i]
if (!condition.subjectId || !condition.optionId) {
this.$message.warning("请选择条件" + (i + 1) + "的触发题目和触发选项")
return
}
}
}
this.$set(this.subjects[subjectIndex], "visibleRuleEnabled", formData.enabled)
this.$set(this.subjects[subjectIndex], "visibleRuleAction", formData.enabled ? formData.action : "show")
this.$set(this.subjects[subjectIndex], "visibleRuleLogic", formData.enabled ? formData.logic : "AND")
this.$set(this.subjects[subjectIndex], "visibleRuleConditions", formData.enabled ? formData.conditions.map((condition) => {
return {
subjectId: condition.subjectId,
optionId: condition.optionId
}
}) : [])
this.subjectVisibleSetting.visible = false
},
//从文本导入
openTxtImport() {
this.$refs.txtImportRef.visible = true;
@@ -5,7 +5,7 @@ const answer = {
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportUserAnswerXlsx">导出xlsx</el-button>
</el-row>
<el-table :data="tableData">
<el-table :data="tableData" v-loading="tableLoading">
<el-table-column label="序号" type="index" width="70"></el-table-column>
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
@@ -30,17 +30,24 @@ const answer = {
onOpen(activityId) {
this.activityId = activityId
this.dialogVisible = true
this.tableColumns = []
this.tableData = []
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.pageData()
},
pageData() {
this.pageForm.activityId = this.activityId
this.tableLoading = true
$.post("/platform/qsv/survey/userAnswer", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableColumns = res.data.tableColumns
this.tableData = res.data.tableData.list
this.pageForm.totalCount = res.data.tableData.totalCount
}
}).always(() => {
this.tableLoading = false
})
},
@@ -53,7 +60,7 @@ const answer = {
$.post("/platform/qsv/survey/deleteUserAnswer", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.list()
this.pageData()
}
})
})
@@ -2,6 +2,42 @@
layout("/layouts/platform.html"){
#-->
<style>
.survey-report-dialog {
margin-top: 40px !important;
height: calc(100vh - 80px);
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.survey-report-dialog .el-dialog__header {
flex: 0 0 auto;
}
.survey-report-dialog .el-dialog__body {
flex: 1;
min-height: 0;
overflow: hidden;
padding-top: 10px;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.survey-report-toolbar {
flex: 0 0 auto;
}
.survey-report-body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding-right: 8px;
box-sizing: border-box;
}
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
@@ -1,41 +1,44 @@
const report = {
/*language=HTML*/
template: `
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%">
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
</el-row>
<div v-for="(subject,subjectIndex) in subjects" class="subject">
<div>
<div class="title">
第{{subjectIndex+1}}题: {{subject.title}}
<span class="type" v-if="subject.type==='text'">[填空题]</span>
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
<span class="type" v-else-if="subject.type==='text'">[多选题]</span>
</div>
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%" custom-class="survey-report-dialog">
<div class="survey-report-toolbar">
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
</el-row>
</div>
<div class="survey-report-body">
<div v-for="(subject,subjectIndex) in subjects" class="subject">
<div>
<div class="title">
第{{subjectIndex+1}}题: {{subject.title}}
<span class="type" v-if="subject.type==='text'">[填空题]</span>
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
<span class="type" v-else-if="subject.type==='checkbox'">[多选题]</span>
</div>
<div v-if="subject.type==='text'">
{{subject.texts.join('、')}}
</div>
<div v-if="subject.type==='text'">
<el-button type="text" @click="openTextDetail(subject)">查看填写内容</el-button>
</div>
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
<el-table :data="subject.options" size="small">
<el-table-column label="选项" prop="text"></el-table-column>
<el-table-column label="小计" prop="selectCount" width="100"></el-table-column>
<el-table-column label="比例" width="500">
<template slot-scope="scope">
<el-progress
:percentage="Math.round(scope.row.selectCount / subject.selectTotal * 100)"></el-progress>
</template>
</el-table-column>
<el-table-column label="详情" width="100px">
<template slot-scope="{row}">
<el-button type="text" @click="openDetail(subject.id,row.id)">详情</el-button>
</template>
</el-table-column>
</el-table>
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
<el-table :data="subject.options" size="small">
<el-table-column label="选项" prop="text"></el-table-column>
<el-table-column label="小计" prop="selectCount" width="100"></el-table-column>
<el-table-column label="比例" width="500">
<template slot-scope="scope">
<el-progress
:percentage="Math.round(scope.row.selectCount / subject.selectTotal * 100)"></el-progress>
</template>
</el-table-column>
<el-table-column label="详情" width="100px">
<template slot-scope="{row}">
<el-button type="text" @click="openDetail(subject.id,row.id)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
@@ -45,9 +48,22 @@ const report = {
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="所属工会" prop="unionName"></el-table-column>
<el-table-column label="所属单位" prop="unitName"></el-table-column>
<el-table-column label="补充理由" prop="fillContent" show-overflow-tooltip></el-table-column>
<el-table-column label="选择时间" prop="attemptDate"></el-table-column>
</el-table>
</el-dialog>
<el-dialog :title="textSubject.title || '填写内容'" :visible.sync="textVisible" width="50%" append-to-body>
<el-table :data="textAnswers" size="small">
<el-table-column label="序号" type="index" width="70"></el-table-column>
<el-table-column label="姓名" prop="userName" width="100"></el-table-column>
<el-table-column label="工号" prop="loginName" width="120"></el-table-column>
<el-table-column label="所属工会" prop="unionName" width="140"></el-table-column>
<el-table-column label="所属单位" prop="unitName" width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="填写内容" prop="text" show-overflow-tooltip></el-table-column>
<el-table-column label="提交时间" prop="submitTime" width="160"></el-table-column>
</el-table>
</el-dialog>
</el-dialog>
`,
@@ -59,7 +75,10 @@ const report = {
report: null,
subjects: [],
optionVisible: false,
optionUsers: []
optionUsers: [],
textVisible: false,
textSubject: {},
textAnswers: []
}
},
methods: {
@@ -73,8 +92,6 @@ const report = {
})
},
openDetail(subjectId, optionId) {
console.log(subjectId)
console.log(optionId)
$.post("/platform/qsv/survey/selectOptionUsers", {
activityId: this.activityId,
subjectId,
@@ -87,6 +104,13 @@ const report = {
}
})
},
openTextDetail(subject) {
this.textSubject = subject
this.textAnswers = subject.textAnswers || (subject.texts || []).map((text) => {
return { text }
})
this.textVisible = true
},
exportReportXlsx(){
this.$downLoad("/platform/qsv/survey/exportReportXlsx", { activityId: this.activityId })
}
@@ -80,6 +80,27 @@ layout("/layouts/platform_h5.html"){
resize: none;
width: 100%;
}
.option-fill-box {
border: 1px solid #e3e3e3;
margin: 0 16px 8px 46px;
background-color: #fff;
padding: 0;
display: flex;
}
.option-fill-box input {
background-color: #fff;
border: none !important;
padding: 10px;
font-size: 14px;
line-height: 18px;
display: inline-block;
margin: 0;
-webkit-appearance: none;
resize: none;
width: 100%;
}
</style>
<div id="app" v-cloak>
@@ -87,7 +108,7 @@ layout("/layouts/platform_h5.html"){
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2>
<div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
@@ -102,31 +123,43 @@ layout("/layouts/platform_h5.html"){
v-if="['radio','checkbox'].includes(subject.type)"
>
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
<template v-for="(option,index) in subject.options">
<van-cell
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
<div
class="option-fill-box"
:key="option.id + '-fill'"
v-if="isOptionFillVisible(subject, option)">
<input
type="text"
v-model="subject.optionFillContents[option.id]"
:placeholder="option.fillPlaceholder || '请填写补充内容'"
:readonly="answerRecord.isFinish"
@click.stop />
</div>
</template>
</van-cell-group>
</van-checkbox-group>
<!--填空题-->
<div class="ui-input-box" v-if="subject.type==='text'">
<input type="text" v-model="subject.userFillContent" :readonly="answerRecord.isFinish" />
<input type="text" v-model="subject.userFillContent" :placeholder="'请输入' + subject.title" :readonly="answerRecord.isFinish" />
</div>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
@@ -158,6 +191,11 @@ layout("/layouts/platform_h5.html"){
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
},
visibleSubjects() {
return this.subjects.filter((subject) => {
return this.isSubjectVisible(subject)
})
}
},
@@ -193,14 +231,106 @@ layout("/layouts/platform_h5.html"){
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$refs["subject" + subject.id][0].toggleAll(false)
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
this.$set(subject, "userSelectOptionIds", answer?.optionIds || [])
this.$set(subject, "optionFillContents", answer?.optionFillContents || {})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
this.$set(subject, "userFillContent", answer?.text)
}
})
if (!this.answerRecord.isFinish) {
this.clearHiddenSubjectAnswers()
}
},
//判断题目是否显示,未配置隐显逻辑的题目默认显示;已配置的题目按条件关系计算后再执行显示或隐藏动作
isSubjectVisible(subject) {
if (!subject.visibleRuleEnabled) {
return true
}
const conditions = this.getVisibleRuleConditions(subject)
if (conditions.length === 0) {
return true
}
const results = conditions.map((condition) => {
const triggerSubject = this.subjects.find((item) => {
return item.id === condition.subjectId
})
return triggerSubject
&& triggerSubject.userSelectOptionIds
&& triggerSubject.userSelectOptionIds.includes(condition.optionId)
})
const matched = subject.visibleRuleLogic === "OR"
? results.some((item) => {
return item
})
: results.every((item) => {
return item
})
if (subject.visibleRuleAction === "hide") {
return !matched
}
return matched
},
//读取隐显逻辑条件,只使用后台保存的条件数组参与显示或隐藏判断
getVisibleRuleConditions(subject) {
let conditions = subject.visibleRuleConditions || []
if (typeof conditions === "string") {
try {
conditions = JSON.parse(conditions)
} catch (e) {
conditions = []
}
}
conditions = conditions.filter((condition) => {
return condition.subjectId && condition.optionId
})
if (conditions.length > 0) {
return conditions
}
return []
},
//清空当前隐藏题目的答案,避免隐藏题残留旧选项或填空内容参与后续提交
clearHiddenSubjectAnswers() {
this.subjects.forEach((subject) => {
if (this.isSubjectVisible(subject)) {
return
}
if (["radio", "checkbox"].includes(subject.type)) {
this.$set(subject, "userSelectOptionIds", [])
this.$set(subject, "optionFillContents", {})
} else if (subject.type === "text") {
this.$set(subject, "userFillContent", null)
}
})
},
//判断选项是否已被选择,用于控制选项补充填写框显示和提交校验
isOptionSelected(subject, optionId) {
return subject.userSelectOptionIds && subject.userSelectOptionIds.includes(optionId)
},
//选中需要补充填写的选项后显示输入框,例如选择“否”后填写原因
isOptionFillVisible(subject, option) {
return option.fillRequired && this.isOptionSelected(subject, option.id)
},
//清空未选中选项的补充填写内容,避免取消选择后残留旧内容
clearUnselectedOptionFillContents(subject) {
if (!subject.optionFillContents) {
this.$set(subject, "optionFillContents", {})
}
if (!subject.options) {
return
}
subject.options.forEach((option) => {
if (!this.isOptionSelected(subject, option.id)) {
this.$delete(subject.optionFillContents, option.id)
}
})
},
@@ -215,6 +345,10 @@ layout("/layouts/platform_h5.html"){
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
this.$nextTick(() => {
this.clearUnselectedOptionFillContents(subject)
this.clearHiddenSubjectAnswers()
})
},
//预览图片
@@ -231,13 +365,20 @@ layout("/layouts/platform_h5.html"){
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
const subject = this.subjects[i]
for (let i = 0; i < this.visibleSubjects.length; i++) {
const subject = this.visibleSubjects[i]
if (["radio", "checkbox"].includes(subject.type)) {
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
for (let j = 0; j < subject.options.length; j++) {
const option = subject.options[j]
if (this.isOptionFillVisible(subject, option) && !subject.optionFillContents[option.id]) {
this.$toast.fail("请填写第" + (i + 1) + "题的补充内容")
return
}
}
} else if ("text" === subject.type) {
if (!subject.userFillContent) {
this.$toast.fail("第" + (i + 1) + "题未作答")
@@ -255,11 +396,12 @@ layout("/layouts/platform_h5.html"){
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
subjects: this.visibleSubjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
userFillContent: subject.type === "text" ? subject.userFillContent : null
userFillContent: subject.type === "text" ? subject.userFillContent : null,
optionFillContents: ["checkbox", "radio"].includes(subject.type) ? subject.optionFillContents : {}
}
})
})