feat: 新增包装测试

This commit is contained in:
钱冠学
2024-11-01 14:11:23 +08:00
parent 58fb5ccd42
commit 91f6c96257
20 changed files with 1166 additions and 522 deletions

View File

@@ -106,6 +106,7 @@ export default {
<style lang="scss">
@import './style/customize/index.scss';
@import './style/utils.scss';
@import './style/scroller.scss';
@font-face {
font-display: optional;
@@ -136,16 +137,7 @@ div {
.scrollbar,
.ant-table-body,
.vxe-table--body-wrapper {
&::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #ffffff;
}
&::-webkit-scrollbar-thumb {
background-color: #d8d8d8;
border-radius: 10px;
}
@extend .scroller;
}
.ant-table-header,
.ant-table-hide-scrollbar {

View File

@@ -29,9 +29,13 @@ const replacing = ref([]);
const urlList = ref([]);
watch(
() => props.urls,
[() => props.urls, () => props.url],
() => {
urlList.value = props.urls || [];
if (props.urls?.length) {
urlList.value = props.urls || [];
} else if (props.url) {
urlList.value = [props.url];
}
},
{
immediate: true
@@ -79,21 +83,30 @@ function onBeforeUpload(file, fileList) {
return true;
}
function setReplacingStatus(index, status) {
if (index === undefined || index === null) {
return;
}
replacing.value[index] = status;
replacing.value = [...replacing.value];
}
// 自定义上传文件
async function onUpload(e, index) {
loading.value = true;
replacing.value[index] = true;
replacing.value = [...replacing.value];
setReplacingStatus(index, true);
const { file, onSuccess, onError } = e;
const fileName = file.name.replaceAll(/\s/g, '');
// 图片验重,此方法并不可靠
if (!props.allowRepeat) {
const index = urlList.value.findIndex((item) => item.split('_').slice(2).join('_') === fileName);
const index = urlList.value.findIndex(
(item) => item.split('_').slice(2).join('_') === fileName
);
if (index !== -1) {
loading.value = false;
replacing.value.splice(index, 1, false);
setReplacingStatus(index, false);
return message.error('图片不能重复');
}
}
@@ -137,19 +150,20 @@ function onChange(info, index) {
urlList.value.push(decodeURIComponent(url));
}
emits('update:urls', urlList.value);
emits('update:url', urlList.value[0] || '');
}
loading.value = false;
replacing.value.splice(index, 1, false);
setReplacingStatus(index, false);
}
if (status === 'done') {
message.success(`${info.file.name} 上传成功.`);
loading.value = false;
replacing.value.splice(index, 1, false);
setReplacingStatus(index, false);
} else if (status === 'error') {
message.error(`${info.file.name} 上传失败.`);
loading.value = false;
replacing.value.splice(index, 1, false);
setReplacingStatus(index, false);
}
}
</script>
@@ -157,7 +171,7 @@ function onChange(info, index) {
<template>
<div class="image-uploader" :class="{ single: props.max === 1 }">
<div v-for="(item, index) in urlList" :key="index" class="image-uploader-item">
<a-spin :spinning="replacing[index]">
<a-spin :spinning="replacing[index] || false">
<!-- 图片 -->
<img :src="item" alt="" class="preview-image" />
<!-- 删除 -->

View File

@@ -4,6 +4,10 @@
align-items: center;
}
.flex-column {
flex-direction: column;
}
.flex-start,
.flex.flex-start {
display: flex;
@@ -29,9 +33,11 @@
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
.full-size {
width: 100%;
height: 100%;

32
src/style/scroller.scss Normal file
View File

@@ -0,0 +1,32 @@
.scroller {
&::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #FFFFFF;
}
&::-webkit-scrollbar-thumb {
background-color: #D8D8D8;
border-radius: 10px;
}
}
.scroller-x {
overflow-x: auto;
@extend .scroller;
}
.scroller-y {
overflow-y: auto;
@extend .scroller;
}
.scroller-xy {
overflow-x: auto;
overflow-y: auto;
@extend .scroller;
}

View File

@@ -1,5 +1,14 @@
<script setup>
import { computed, defineEmits, defineExpose, reactive, ref, defineProps, watch, watchEffect } from 'vue';
import {
computed,
defineEmits,
defineExpose,
reactive,
ref,
defineProps,
watch,
watchEffect
} from 'vue';
import { CaretRightOutlined } from '@ant-design/icons-vue';
import SectionTitle from '@/components/layout/title/SectionTitle.vue';
@@ -17,7 +26,7 @@ import {
packageTypeEnumLabelMap
} from '../consts';
import conceptJson from '../json/concept';
import conceptJson from '../json/concept.json';
import tasteJson from '../json/taste.json';
import packageJson from '../json/package.json';
@@ -142,18 +151,25 @@ function getPopupContainer(el) {
return el.parentNode.parentNode || document.body;
}
const indicatorTooltipText = computed(() => indicatorTooltipTexts[props.schemeType][projectFormModel.testType]);
const indicatorTooltipText = computed(
() => indicatorTooltipTexts[props.schemeType][projectFormModel.testType]
);
const expandIndicator = ref(true);
const expandIndicator2 = ref(false);
function getIndicatorList(type, suffix = '') {
let result = [];
if (![schemeEnum.concept, schemeEnum.taste, schemeEnum.package].includes(props.schemeType)) {
return [];
return result;
}
if (schemeEnum.package === props.schemeType) {
return packageJson[`${type}_${suffix}`];
result = packageJson[`${type}_${suffix}`];
} else {
result = [{}, conceptJson, tasteJson, packageJson][props.schemeType][type];
}
return [{}, conceptJson, tasteJson, packageJson][props.schemeType][type];
return result;
}
const standardIndicatorList = computed(() => getIndicatorList(`check_list_standard`, 'outer'));
@@ -165,18 +181,34 @@ const quickTestIndicator2List = computed(() => getIndicatorList(`check_list_quic
const pairIndicatorList = computed(() => getIndicatorList(`check_list_pair`, 'outer'));
const pairIndicator2List = computed(() => getIndicatorList(`check_list_pair`, 'inner'));
const isCheckedAll = computed(() => standardChecked.value.length === standardIndicatorList.value.length);
const isIndeterminate = computed(() => standardChecked.value.length !== standardIndicatorList.value.length);
const isCheckedAll = computed(
() => standardChecked.value.length === standardIndicatorList.value.length
);
const isIndeterminate = computed(
() => standardChecked.value.length !== standardIndicatorList.value.length
);
const standardChecked = ref(standardIndicatorList.value.filter((i) => i.selected).map((i) => i.value));
const quickTestChecked = ref(quickTestIndicatorList.value.filter((i) => i.selected).map((i) => i.value));
const standardChecked = ref(
standardIndicatorList.value.filter((i) => i.selected).map((i) => i.value)
);
const quickTestChecked = ref(
quickTestIndicatorList.value.filter((i) => i.selected).map((i) => i.value)
);
const pairChecked = ref(pairIndicatorList.value.filter((i) => i.selected).map((i) => i.value));
const isCheckedAll2 = computed(() => standardChecked2.value.length === standardIndicator2List.value.length);
const isIndeterminate2 = computed(() => standardChecked2.value.length !== standardIndicator2List.value.length);
const isCheckedAll2 = computed(
() => standardChecked2.value.length === standardIndicator2List.value.length
);
const isIndeterminate2 = computed(
() => standardChecked2.value.length !== standardIndicator2List.value.length
);
const standardChecked2 = ref(standardIndicator2List.value.filter((i) => i.selected).map((i) => i.value));
const quickTestChecked2 = ref(quickTestIndicator2List.value.filter((i) => i.selected).map((i) => i.value));
const standardChecked2 = ref(
standardIndicator2List.value.filter((i) => i.selected).map((i) => i.value)
);
const quickTestChecked2 = ref(
quickTestIndicator2List.value.filter((i) => i.selected).map((i) => i.value)
);
const pairChecked2 = ref(pairIndicator2List.value.filter((i) => i.selected).map((i) => i.value));
watchEffect(() => {
@@ -194,7 +226,9 @@ watchEffect(() => {
function toggleCheckAll() {
if (isCheckedAll.value) {
standardChecked.value = standardIndicatorList.value.filter((item) => item.disabled).map((item) => item.value);
standardChecked.value = standardIndicatorList.value
.filter((item) => item.disabled)
.map((item) => item.value);
} else {
standardChecked.value = standardIndicatorList.value.map((item) => item.value);
}
@@ -202,7 +236,9 @@ function toggleCheckAll() {
function toggleCheckAll2() {
if (isCheckedAll2.value) {
standardChecked2.value = standardIndicator2List.value.filter((item) => item.disabled).map((item) => item.value);
standardChecked2.value = standardIndicator2List.value
.filter((item) => item.disabled)
.map((item) => item.value);
} else {
standardChecked2.value = standardIndicator2List.value.map((item) => item.value);
}
@@ -276,7 +312,13 @@ function validateForm() {
}[projectFormModel.testType];
resolve({
status: 'fulfilled',
data: Object.assign({}, resolveData[0], resolveData[1], { concept_indexes }, { concept_indexes2 })
data: Object.assign(
{},
resolveData[0],
resolveData[1],
{ concept_indexes },
{ concept_indexes2 }
)
});
});
}
@@ -290,7 +332,12 @@ defineExpose({
<div>
<SectionTitle class="mb-18">项目配置</SectionTitle>
<a-form ref="projectFormRef" :model="projectFormModel" :rules="projectFormRules" :label-col="{ span: 4 }">
<a-form
ref="projectFormRef"
:model="projectFormModel"
:rules="projectFormRules"
:label-col="{ span: 4 }"
>
<a-row :gutter="6">
<a-col :span="16">
<a-form-item label="品类品牌" name="surveyCategoryStr" required :label-col="{ span: 6 }">
@@ -335,7 +382,12 @@ defineExpose({
<a-form-item label="测试版本" name="testType">
<a-radio-group v-model:value="projectFormModel.testType">
<a-radio :value="item.id" v-for="item in testTypeList" :key="item.id" @click="onChangeTestType(item)">
<a-radio
:value="item.id"
v-for="item in testTypeList"
:key="item.id"
@click="onChangeTestType(item)"
>
{{ item.name }}
</a-radio>
</a-radio-group>
@@ -438,19 +490,21 @@ defineExpose({
>
<div v-if="projectFormModel.testType === testTypeEnum.standard">
<div class="check-box">
<div v-for="item in standardIndicatorList" :key="item.value" class="check-item">
<a-checkbox
:checked="standardChecked.includes(item.value)"
:value="item.value"
:disabled="item.disabled"
class="custom-checkbox my-checkbox"
@change="onStandardCheckboxChange"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
</a-checkbox>
</div>
<template v-for="item in standardIndicatorList" :key="item.value">
<div v-if="!item.hidden" class="check-item">
<a-checkbox
:checked="standardChecked.includes(item.value)"
:value="item.value"
:disabled="item.disabled"
class="custom-checkbox my-checkbox"
@change="onStandardCheckboxChange"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
</a-checkbox>
</div>
</template>
<div v-for="item in 10" :key="item" class="check-item"></div>
</div>
</div>
@@ -459,7 +513,11 @@ defineExpose({
<a-checkbox-group v-model:value="quickTestChecked">
<div class="check-box">
<div v-for="item in quickTestIndicatorList" :key="item.value" class="check-item">
<a-checkbox class="custom-checkbox my-checkbox" :value="item.value" :disabled="item.disabled">
<a-checkbox
class="custom-checkbox my-checkbox"
:value="item.value"
:disabled="item.disabled"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
@@ -473,8 +531,16 @@ defineExpose({
<div v-if="projectFormModel.testType === testTypeEnum.pair">
<a-checkbox-group v-model:value="pairChecked">
<div class="check-box">
<div v-for="item in pairIndicatorList" :key="item.value" class="check-item check-item-three">
<a-checkbox class="custom-checkbox my-checkbox" :value="item.value" :disabled="item.disabled">
<div
v-for="item in pairIndicatorList"
:key="item.value"
class="check-item check-item-three"
>
<a-checkbox
class="custom-checkbox my-checkbox"
:value="item.value"
:disabled="item.disabled"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
@@ -488,7 +554,8 @@ defineExpose({
<template
v-if="
[schemeEnum.package].includes(props.schemeType) && projectFormModel.packageType.includes(packageTypeEnum.inner)
[schemeEnum.package].includes(props.schemeType) &&
projectFormModel.packageType.includes(packageTypeEnum.inner)
"
>
<div v-if="projectFormModel.packageType.length === 2" class="flex mb-12 mt-12">
@@ -516,19 +583,21 @@ defineExpose({
>
<div v-if="projectFormModel.testType === testTypeEnum.standard">
<div class="check-box">
<div v-for="item in standardIndicator2List" :key="item.value" class="check-item">
<a-checkbox
:checked="standardChecked2.includes(item.value)"
:value="item.value"
:disabled="item.disabled"
class="custom-checkbox my-checkbox"
@change="onStandardCheckboxChange2"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
</a-checkbox>
</div>
<template v-for="item in standardIndicator2List" :key="item.value">
<div v-if="!item.hidden" class="check-item">
<a-checkbox
:checked="standardChecked2.includes(item.value)"
:value="item.value"
:disabled="item.disabled"
class="custom-checkbox my-checkbox"
@change="onStandardCheckboxChange2"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
</a-checkbox>
</div>
</template>
<div v-for="item in 10" :key="item" class="check-item"></div>
</div>
</div>
@@ -537,7 +606,11 @@ defineExpose({
<a-checkbox-group v-model:value="quickTestChecked2">
<div class="check-box">
<div v-for="item in quickTestIndicator2List" :key="item.value" class="check-item">
<a-checkbox class="custom-checkbox my-checkbox" :value="item.value" :disabled="item.disabled">
<a-checkbox
class="custom-checkbox my-checkbox"
:value="item.value"
:disabled="item.disabled"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>
@@ -551,8 +624,16 @@ defineExpose({
<div v-if="projectFormModel.testType === testTypeEnum.pair">
<a-checkbox-group v-model:value="pairChecked2">
<div class="check-box">
<div v-for="item in pairIndicator2List" :key="item.value" class="check-item check-item-three">
<a-checkbox class="custom-checkbox my-checkbox" :value="item.value" :disabled="item.disabled">
<div
v-for="item in pairIndicator2List"
:key="item.value"
class="check-item check-item-three"
>
<a-checkbox
class="custom-checkbox my-checkbox"
:value="item.value"
:disabled="item.disabled"
>
<span :class="{ 'check-label': item.disabled }">
{{ item.label }}
</span>

View File

@@ -27,7 +27,12 @@
class="custom-select show-select"
:dropdownStyle="{ zIndex: 10000 }"
>
<a-select-option :value="`${item.code}`" :label="item.title" v-for="item in scenesList" :key="`${item.code}`">
<a-select-option
:value="`${item.code}`"
:label="item.title"
v-for="item in scenesList"
:key="`${item.code}`"
>
{{ item.parentTitle }}-{{ item.title }}
</a-select-option>
</a-select>
@@ -43,7 +48,12 @@
class="custom-select show-select"
:dropdownStyle="{ zIndex: 10000 }"
>
<a-select-option :value="item.id" :label="item.title" v-for="item in tagsList" :key="item.id">
<a-select-option
:value="item.id"
:label="item.title"
v-for="item in tagsList"
:key="item.id"
>
<div style="display: flex; justify-content: space-between">
<span :style="countColor(item.color)" :title="item.title">{{ item.title }}</span>
<span class="icon" v-show="isAdmin">
@@ -96,7 +106,12 @@ import { defineComponent, reactive, ref, watch, onBeforeMount, createVNode } fro
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import { message, Modal } from 'ant-design-vue';
import { PlusOutlined, EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
ExclamationCircleOutlined
} from '@ant-design/icons-vue';
import { getTagsList, deleteTags, getSceneListForSelect } from '@/views/ProjectManage/api';
import addTag from '@/views/ProjectManage/components/addTag.vue';
import useEmitter from '@/composables/useEmitter';

View File

@@ -1,5 +1,5 @@
<script setup>
import { computed, defineProps } from 'vue';
import { computed, defineProps, ref, watch } from 'vue';
import conceptJson from '../json/concept.json';
import tasteJson from '../json/taste.json';
@@ -27,6 +27,36 @@ const questionList = computed(() => {
return [{}, conceptJson, tasteJson, packageJson][props.schemeType][questionIndex];
});
// 分页加载,否则数据多时,页面会卡顿
const page = ref(1);
const pageSize = ref(10);
const deferredRenderThreshold = 30;
const questionListForRender = computed(() =>
questionList.value.slice(0, page.value * pageSize.value)
);
watch(questionList, renderDom, { immediate: true });
function renderDom() {
if (questionList.value.length < deferredRenderThreshold) {
page.value = Math.ceil(deferredRenderThreshold / pageSize.value);
return;
}
page.value = 1;
increasePage();
}
function increasePage() {
if (page.value * pageSize.value >= questionList.value.length) {
return;
}
setTimeout(() => {
page.value += 1;
increasePage();
}, 280);
}
</script>
<template>
@@ -39,7 +69,12 @@ const questionList = computed(() => {
<div class="head-title-two">样本量要求60</div>
</div>
<div class="question-content" v-for="(item, index) in questionList" :key="index" :class="{ nb: item.noBottom }">
<div
class="question-content"
v-for="(item, index) in questionListForRender"
:key="index"
:class="{ nb: item.noBottom }"
>
<div class="question-title" v-if="item?.seq || item?.title">
<span v-if="item?.seq" class="question-seq">{{ item.seq }}</span>
<span v-if="item?.title" v-html="item.title"></span>
@@ -53,7 +88,12 @@ const questionList = computed(() => {
<div class="question-tip mb-8" v-if="item?.tip">{{ item.tip }}</div>
<div class="question-ans mb-8" v-for="it in item.ans" :key="it" :class="{ 'group-title': it.isGroupTitle }">
<div
class="question-ans mb-8"
v-for="it in item.ans"
:key="it"
:class="{ 'group-title': it.isGroupTitle }"
>
<span v-if="it.isGroupTitle">{{ it.title }}</span>
<span v-else v-html="it"></span>
</div>

View File

@@ -77,16 +77,19 @@ function onSave() {
<div class="content-box">
<!-- 配置 -->
<div class="content scrollbar">
<slot></slot>
<div class="flex flex-column left">
<div class="flex-auto full-width scroller-y content-wrapper">
<slot></slot>
</div>
<div class="flex-none full-width footer">
<slot name="footer"></slot>
</div>
</div>
<!-- 模版详情 -->
<div ref="templateScrollerRef" class="content scrollbar">
<div class="template-box">
<SectionTitle>模板详情</SectionTitle>
<SurveySchemeTemplate :scheme-type="props.schemeType" :test-type="props.testType" />
</div>
<div ref="templateScrollerRef" class="right scroller-y">
<SectionTitle>模板详情</SectionTitle>
<SurveySchemeTemplate :scheme-type="props.schemeType" :test-type="props.testType" />
</div>
</div>
</div>
@@ -136,12 +139,17 @@ function onSave() {
display: flex;
justify-content: space-between;
.content {
width: calc(50% - 12px);
padding: 22px;
.left,
.right {
width: calc(50% - 8px);
height: calc(100vh - 150px);
}
.content-wrapper,
.right {
overflow: auto;
overflow: overlay;
padding: 22px;
background-color: #ffffff;
border-radius: 6px;
position: relative;

View File

@@ -67,37 +67,49 @@ export const encodeList = [
'Z'
];
let indicator2_1 = '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个口味分别询问被访者相关问题。';
const indicatorCommon1 = '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个';
const indicatorCommon2 = '分别询问被访者相关问题';
let indicator2_1 = indicatorCommon1 + '问卷将针对每个口味分别询问被访者相关问题。';
indicator2_1 += '特别的,若勾选「属性具体评价」则会针对每个口味的属性询问被访者的评价';
const indicator2_2 = '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个口味分别询问被访者相关问题';
const indicator2_3 = '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个口味分别询问被访者相关问题';
export const indicatorTooltipTexts = {
[schemeEnum.concept]: {
[testTypeEnum.standard]: '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个概念分别询问被访者相关问题',
[testTypeEnum.quickTest]:
'您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个概念分别询问被访者相关问题',
[testTypeEnum.pair]: '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个概念分别询问被访者相关问题'
[testTypeEnum.standard]: indicatorCommon1 + '概念' + indicatorCommon2,
[testTypeEnum.quickTest]: indicatorCommon1 + '概念' + indicatorCommon2,
[testTypeEnum.pair]: indicatorCommon1 + '概念' + indicatorCommon2
},
[schemeEnum.taste]: {
[testTypeEnum.standard]: indicator2_1,
[testTypeEnum.quickTest]: indicator2_2,
[testTypeEnum.pair]: indicator2_3
[testTypeEnum.quickTest]: indicatorCommon1 + '口味' + indicatorCommon2,
[testTypeEnum.pair]: indicatorCommon1 + '口味' + indicatorCommon2
},
[schemeEnum.package]: {
[testTypeEnum.standard]: '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个包装分别询问被访者相关问题',
[testTypeEnum.quickTest]:
'您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个包装分别询问被访者相关问题',
[testTypeEnum.pair]: '您在此处勾选拟调研的指标,每个指标对应一道问题,问卷将针对每个包装分别询问被访者相关问题'
[testTypeEnum.standard]: indicatorCommon1 + '包装' + indicatorCommon2,
[testTypeEnum.quickTest]: indicatorCommon1 + '包装' + indicatorCommon2,
[testTypeEnum.pair]: indicatorCommon1 + '包装' + indicatorCommon2
}
};
export const packageTypeEnum = {
basic: 0, // 配置 step 组件中,显示 “基础配置” 的,并不真的是包装类型
outer: 1,
inner: 2
inner: 2,
inout: 3 // 后端需要的 package_type 字段: 123前端多选需要给他转一下
};
export function getPackageForApi(packageType = []) {
if (packageType.includes(packageTypeEnum.outer) && packageType.includes(packageTypeEnum.inner)) {
return packageTypeEnum.inout;
}
if (packageType.includes(packageTypeEnum.outer)) {
return packageTypeEnum.outer;
}
if (packageType.includes(packageTypeEnum.inner)) {
return packageTypeEnum.inner;
}
}
export const packageTypeEnumLabelMap = {
[packageTypeEnum.outer]: '外箱测试',
[packageTypeEnum.inner]: '内包测试'

View File

@@ -197,7 +197,9 @@ export default {
},
{
seq: 'A2',
title: `与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?${qType('【单选题】')}`,
title: `与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?${qType(
'【单选题】'
)}`,
topic: '[系统自动插入新品概念方向一图片]',
tip: '#新颖独特性 新品概念方向一',
ans: ['非常新颖独特', '比较新颖独特', '谈不上有没有,一般', '不太新颖独特', '一点也不新颖独特']
@@ -275,7 +277,9 @@ export default {
},
{
seq: 'A11',
title: `您刚才看到的这款产品,下列哪句话最能描述它对您购买习惯的影响程度?${qType('【填空题】')}`,
title: `您刚才看到的这款产品,下列哪句话最能描述它对您购买习惯的影响程度?${qType(
'【填空题】'
)}`,
topic: '[系统自动插入新品概念方向一图片]',
tip: '#购买行为影响 新品概念方向一',
ans: [
@@ -338,7 +342,9 @@ export default {
},
{
seq: 'A15',
title: `看完这款产品介绍后,您觉得这款介绍所描述的内容容易理解吗?您觉得它是……?${qType('【单选题】')}`,
title: `看完这款产品介绍后,您觉得这款介绍所描述的内容容易理解吗?您觉得它是……?${qType(
'【单选题】'
)}`,
topic: '[系统自动插入新品概念方向一图片]',
tip: '#理解度 新品概念方向一',
ans: ['非常容易理解', '比较容易理解', '一般', '有些不容易理解', '非常不容易理解']
@@ -512,7 +518,9 @@ export default {
},
{
seq: 'B2',
title: `与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?${qType('【单选题】')}`,
title: `与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?${qType(
'【单选题】'
)}`,
topic: '[系统自动插入新品概念方向二图片]',
tip: '#新颖独特性 新品概念方向二',
ans: ['非常新颖独特', '比较新颖独特', '谈不上有没有,一般', '不太新颖独特', '一点也不新颖独特']
@@ -590,7 +598,9 @@ export default {
},
{
seq: 'B11',
title: `您刚才看到的这款产品,下列哪句话最能描述它对您购买习惯的影响程度?${qType('【单选题】')}`,
title: `您刚才看到的这款产品,下列哪句话最能描述它对您购买习惯的影响程度?${qType(
'【单选题】'
)}`,
topic: '[系统自动插入新品概念方向二图片]',
tip: '#购买行为影响 新品概念方向二',
ans: [
@@ -652,7 +662,9 @@ export default {
},
{
seq: 'B15',
title: `看完这款产品介绍后,您觉得这款介绍所描述的内容容易理解吗?您觉得它是……?${qType('【单选题】')}`,
title: `看完这款产品介绍后,您觉得这款介绍所描述的内容容易理解吗?您觉得它是……?${qType(
'【单选题】'
)}`,
topic: '[系统自动插入新品概念方向二图片]',
tip: '#理解度 新品概念方向二',
ans: ['非常容易理解', '比较容易理解', '一般', '有些不容易理解', '非常不容易理解']

View File

@@ -196,7 +196,13 @@
"title": "与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?<span style=\"font-weight:700;\">【单选题】</span>",
"topic": "[系统自动插入新品概念方向一图片]",
"tip": "#新颖独特性 新品概念方向一",
"ans": ["非常新颖独特", "比较新颖独特", "谈不上有没有,一般", "不太新颖独特", "一点也不新颖独特"]
"ans": [
"非常新颖独特",
"比较新颖独特",
"谈不上有没有,一般",
"不太新颖独特",
"一点也不新颖独特"
]
},
{
"seq": "A3",
@@ -495,7 +501,13 @@
"title": "与市场上其他同类产品相比,您认为这款介绍中描述的产品的新颖独特程度是怎样的呢?<span style=\"font-weight:700;\">【单选题】</span>",
"topic": "[系统自动插入新品概念方向二图片]",
"tip": "#新颖独特性 新品概念方向二",
"ans": ["非常新颖独特", "比较新颖独特", "谈不上有没有,一般", "不太新颖独特", "一点也不新颖独特"]
"ans": [
"非常新颖独特",
"比较新颖独特",
"谈不上有没有,一般",
"不太新颖独特",
"一点也不新颖独特"
]
},
{
"seq": "B3",

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,16 @@
{
"check_list_standard_outer": [
{
"value": "无提示认知1",
"value": "package_out_head",
"label": "外箱的图片题",
"hidden": true,
"disabled": false,
"selected": true,
"alliance": "1",
"fullView": true
},
{
"value": "package_out_head_not_prompt_1",
"label": "无提示认知1",
"disabled": false,
"selected": true,
@@ -9,7 +18,7 @@
"fullView": true
},
{
"value": "无提示认知2",
"value": "package_out_head_not_prompt_2",
"label": "无提示认知2",
"disabled": false,
"selected": true,
@@ -17,7 +26,7 @@
"fullView": true
},
{
"value": "堆头可见度",
"value": "package_out_head_visibility",
"label": "堆头可见度",
"disabled": false,
"selected": true,
@@ -25,7 +34,7 @@
"fullView": true
},
{
"value": "包装品牌关联",
"value": "package_out_brand",
"label": "包装品牌关联",
"disabled": false,
"selected": true,
@@ -39,19 +48,19 @@
"selected": true
},
{
"value": "包装视觉吸引力1",
"value": "package_out_attraction_1",
"label": "包装视觉吸引力1",
"disabled": false,
"alliance": "2"
},
{
"value": "包装视觉吸引力2",
"value": "package_out_attraction_2",
"label": "包装视觉吸引力2",
"disabled": false,
"alliance": "2"
},
{
"value": "包装视觉吸引力3",
"value": "package_out_attraction_3",
"label": "包装视觉吸引力3",
"disabled": false,
"alliance": "2"
@@ -81,7 +90,7 @@
"selected": true
},
{
"value": "包装设计",
"value": "package_out_design",
"label": "包装设计",
"disabled": false
},
@@ -92,7 +101,7 @@
"selected": true
},
{
"value": "包装品牌影响",
"value": "package_out_brand_influence",
"label": "包装品牌影响",
"disabled": false
},
@@ -103,54 +112,63 @@
"selected": true
},
{
"value": "新颖独特性",
"value": "package_out_novelty_uniqueness",
"label": "新颖独特性",
"disabled": false
},
{
"value": "系列感",
"value": "package_out_serial_sense",
"label": "系列感",
"disabled": false
},
{
"value": "taste_drink_time",
"value": "package_out_drink_time",
"label": "饮用时间",
"disabled": false
},
{
"value": "taste_drink_occasion",
"value": "package_out_drink_occasion",
"label": "饮用场合",
"disabled": false
},
{
"value": "taste_drink_todo",
"value": "package_out_drink_todo",
"label": "饮用时做什么",
"disabled": false
},
{
"value": "taste_sales_channel",
"value": "package_out_sales_channel",
"label": "售卖渠道",
"disabled": false
},
{
"value": "taste_price_test",
"value": "package_out_price_test",
"label": "价格测试",
"disabled": false
},
{
"value": "包装品类关联",
"value": "package_out_category_association",
"label": "包装品类关联",
"disabled": false
},
{
"value": "taste_forced_contrast",
"value": "package_out_forced_sort",
"label": "强制对比",
"disabled": false
}
],
"check_list_standard_inner": [
{
"value": "无提示认知1",
"value": "package_inter_head",
"label": "内包的图片题",
"hidden": true,
"disabled": false,
"selected": true,
"alliance": "1",
"fullView": true
},
{
"value": "package_inter_head_not_prompt_1",
"label": "无提示认知1",
"disabled": false,
"selected": true,
@@ -158,7 +176,7 @@
"fullView": true
},
{
"value": "无提示认知2",
"value": "package_inter_head_not_prompt_2",
"label": "无提示认知2",
"disabled": false,
"selected": true,
@@ -166,7 +184,7 @@
"fullView": true
},
{
"value": "货架可见度",
"value": "package_inter_head_visibility",
"label": "货架可见度",
"disabled": false,
"selected": true,
@@ -174,7 +192,7 @@
"fullView": true
},
{
"value": "包装品牌关联",
"value": "package_inter_brand",
"label": "包装品牌关联",
"disabled": false,
"selected": true,
@@ -188,19 +206,19 @@
"selected": true
},
{
"value": "包装视觉吸引力1",
"value": "package_inter_attraction_1",
"label": "包装视觉吸引力1",
"disabled": false,
"alliance": "2"
},
{
"value": "包装视觉吸引力2",
"value": "package_inter_attraction_2",
"label": "包装视觉吸引力2",
"disabled": false,
"alliance": "2"
},
{
"value": "包装视觉吸引力3",
"value": "package_inter_attraction_3",
"label": "包装视觉吸引力3",
"disabled": false,
"alliance": "2"
@@ -230,7 +248,7 @@
"selected": true
},
{
"value": "包装设计",
"value": "package_inter_design",
"label": "包装设计",
"disabled": false
},
@@ -241,7 +259,7 @@
"selected": true
},
{
"value": "包装品牌影响",
"value": "package_inter_brand_influence",
"label": "包装品牌影响",
"disabled": false
},
@@ -252,47 +270,47 @@
"selected": true
},
{
"value": "新颖独特性",
"value": "package_inter_novelty_uniqueness",
"label": "新颖独特性",
"disabled": false
},
{
"value": "系列感",
"value": "package_inter_serial_sense",
"label": "系列感",
"disabled": false
},
{
"value": "taste_drink_time",
"value": "package_inter_drink_time",
"label": "饮用时间",
"disabled": false
},
{
"value": "taste_drink_occasion",
"value": "package_inter_drink_occasion",
"label": "饮用场合",
"disabled": false
},
{
"value": "taste_drink_todo",
"value": "package_inter_drink_todo",
"label": "饮用时做什么",
"disabled": false
},
{
"value": "taste_sales_channel",
"value": "package_inter_sales_channel",
"label": "售卖渠道",
"disabled": false
},
{
"value": "taste_price_test",
"value": "package_inter_price_test",
"label": "价格测试",
"disabled": false
},
{
"value": "包装品类关联",
"value": "package_inter_category_association",
"label": "包装品类关联",
"disabled": false
},
{
"value": "taste_forced_contrast",
"value": "package_inter_forced_sort",
"label": "强制对比",
"disabled": false
}
@@ -305,7 +323,7 @@
"selected": true
},
{
"value": "包装设计",
"value": "package_out_design",
"label": "包装设计",
"disabled": false
},
@@ -315,7 +333,7 @@
"disabled": false
},
{
"value": "强制对比",
"value": "package_out_forced_sort",
"label": "强制对比",
"disabled": false
}
@@ -328,7 +346,7 @@
"selected": true
},
{
"value": "包装设计",
"value": "package_inter_design",
"label": "包装设计",
"disabled": false
},
@@ -338,7 +356,7 @@
"disabled": false
},
{
"value": "强制对比",
"value": "package_inter_forced_sort",
"label": "强制对比",
"disabled": false
}

View File

@@ -3,11 +3,15 @@ export function red(text) {
}
export function black(text) {
return `<span style="font-weight:700;color:black;text-decoration:underline;">${text || ''}</span>`;
return `<span style="font-weight:700;color:black;text-decoration:underline;">${
text || ''
}</span>`;
}
export function green(text) {
return `<span style="font-weight:700;color:green;text-decoration:underline;">${text || ''}</span>`;
return `<span style="font-weight:700;color:green;text-decoration:underline;">${
text || ''
}</span>`;
}
export function qType(text) {

View File

@@ -148,20 +148,26 @@ export default {
},
{
seq: 'A1',
title: `请问您对您刚才品尝过的${red('口味A')}${black('总体喜欢程度')}是怎样的?${qType('【单选题】')}`,
title: `请问您对您刚才品尝过的${red('口味A')}${black('总体喜欢程度')}是怎样的?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#总体喜欢程度 口味一名称',
ans: ['非常喜欢', '比较喜欢', '一般', '不太喜欢', '完全不喜欢']
},
{
seq: 'A2',
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red('口味A')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red(
'口味A'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#不喜欢方面 口味一名称'
},
{
seq: 'A3',
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red('口味A')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red(
'口味A'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#喜欢的方面 口味一名称'
},
@@ -176,9 +182,9 @@ export default {
},
{
seq: 'A5',
title: `与目前市场上销售的其它${black('同类产品')}相比,请问您觉得这款${red('口味A')}${black(
'新颖独特性'
)}如何呢?${qType('【单选题】')}`,
title: `与目前市场上销售的其它${black('同类产品')}相比,请问您觉得这款${red(
'口味A'
)}${black('新颖独特性')}如何呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#新颖独特性 口味一名称',
ans: ['非常新颖独特', '比较新颖独特', '谈不上有没有,一般', '不太新颖独特', '一点也不新颖独特']
@@ -195,50 +201,66 @@ export default {
table: {
headers: ['', '喜欢程度'],
rows: [
['奶香味(喝起来奶香浓醇)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['甜味(自然清甜味,非人工添加糖剂)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['稀稠度(喝起来的厚薄程度)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['醇厚度(喝起来没有被稀释过的感觉)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢']
[
'奶香味(喝起来奶香浓醇)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'甜味(自然清甜味,非人工添加糖剂)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'稀稠度(喝起来的厚薄程度)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'醇厚度(喝起来没有被稀释过的感觉)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
]
]
}
},
{
seq: 'A6.1',
title: `请问您觉得这个${red('口味A')}喝起来的${black('奶香味(喝起来奶香浓醇)')}如何?${qType('【单选题】')}`,
title: `请问您觉得这个${red('口味A')}喝起来的${black(
'奶香味(喝起来奶香浓醇)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-奶香味(喝起来奶香浓醇) 口味一名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'A6.2',
title: `请问您觉得这个${red('口味A')}喝起来的${black('甜味(自然清甜味,非人工添加糖剂)')}如何?${qType(
'【单选题】'
)}`,
title: `请问您觉得这个${red('口味A')}喝起来的${black(
'甜味(自然清甜味,非人工添加糖剂)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-甜味(自然清甜味,非人工添加糖剂) 口味一名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'A6.3',
title: `请问您觉得这个${red('口味A')}喝起来的${black('稀稠度(喝起来的厚薄程度)')}如何?${qType('【单选题】')}`,
title: `请问您觉得这个${red('口味A')}喝起来的${black(
'稀稠度(喝起来的厚薄程度)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-稀稠度(喝起来的厚薄程度) 口味一名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'A6.4',
title: `请问您觉得这个${red('口味A')}喝起来的${black('醇厚度(喝起来没有被稀释过的感觉)')}如何?${qType(
'【单选题】'
)}`,
title: `请问您觉得这个${red('口味A')}喝起来的${black(
'醇厚度(喝起来没有被稀释过的感觉)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-醇厚度(喝起来没有被稀释过的感觉) 口味一名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'A7',
title: `根据您品尝到的这款${red('口味A')}的口味和口感,您认为这款产品适合${black('在什么时候饮用')}呢?${qType(
'【单选题】'
)}`,
title: `根据您品尝到的这款${red('口味A')}的口味和口感,您认为这款产品适合${black(
'在什么时候饮用'
)}呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用时间 口味一名称',
ans: [
@@ -275,14 +297,18 @@ export default {
},
{
seq: 'A8',
title: `您认为这款${red('口味A')}最适合${black('在哪里饮用')}这产品呢?${qType('【单选题】')}`,
title: `您认为这款${red('口味A')}最适合${black('在哪里饮用')}这产品呢?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用场合 口味一名称',
ans: ['在家中(如自己家或朋友亲戚家)', '在工作/学习场所', '在户外/餐饮场所']
},
{
seq: 'A9',
title: `请设想一下,您饮用该${red('口味A')}${black('最可能')}${black('做什么')}呢?${qType('【单选题】')}`,
title: `请设想一下,您饮用该${red('口味A')}${black('最可能')}${black(
'做什么'
)}呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用时做什么 口味一名称',
ans: [
@@ -366,7 +392,9 @@ export default {
},
{
seq: 'A10',
title: `您认为您刚才品尝的这款${red('口味A')}适合${black('在什么地方售卖')}呢?${qType('【多选题】')}`,
title: `您认为您刚才品尝的这款${red('口味A')}适合${black('在什么地方售卖')}呢?${qType(
'【多选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#售卖渠道 口味一名称',
ans: [
@@ -423,9 +451,9 @@ export default {
},
{
seq: 'A11',
title: `您刚才品尝的这款${red('口味A')},下列哪句话最能描述它对您的${black('购买习惯的影响程度')}${qType(
'【单选题】'
)}`,
title: `您刚才品尝的这款${red('口味A')},下列哪句话最能描述它对您的${black(
'购买习惯的影响程度'
)}${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#购买行为影响 口味一名称',
ans: [
@@ -437,9 +465,11 @@ export default {
},
{
seq: 'A12',
title: `您刚才提到这款${red('口味A')}会替代您目前正在饮用的产品,那么您能告诉我您会用它${black(
'替代'
)}哪个或哪些您${black('目前正在饮')}用的饮品呢?${qType('【多选题】')}`,
title: `您刚才提到这款${red(
'口味A'
)}会替代您目前正在饮用的产品,那么您能告诉我您会用它${black('替代')}哪个或哪些您${black(
'目前正在饮'
)}用的饮品呢?${qType('【多选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#品类替代 口味一名称',
ans: [
@@ -472,7 +502,9 @@ export default {
},
{
seq: 'A13',
title: `基于这款${red('口味A')}介绍中的描述和价格信息,综合您品尝到的口味,您倾向于饮用这款产品的频率为${black(
title: `基于这款${red(
'口味A'
)}介绍中的描述和价格信息,综合您品尝到的口味,您倾向于饮用这款产品的频率为${black(
'每周几次'
)}${qType('【多选题】')}`,
topic: '[题干系统自动插入口味编号]',
@@ -529,20 +561,26 @@ export default {
},
{
seq: 'B1',
title: `请问您对您刚才品尝过的${red('口味B')}${black('总体喜欢程度')}是怎样的?${qType('【单选题】')}`,
title: `请问您对您刚才品尝过的${red('口味B')}${black('总体喜欢程度')}是怎样的?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#总体喜欢程度 口味二名称',
ans: ['非常喜欢', '比较喜欢', '一般', '不太喜欢', '完全不喜欢']
},
{
seq: 'B2',
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red('口味B')}的哪些方面?${qType('【单选题】')}`,
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red(
'口味B'
)}的哪些方面?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#不喜欢的方面 口味二名称'
},
{
seq: 'B3',
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red('口味B')}的哪些方面?${qType('【单选题】')}`,
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red(
'口味B'
)}的哪些方面?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#喜欢的方面 口味二名称'
},
@@ -557,12 +595,18 @@ export default {
},
{
seq: 'B5',
title: `与目前市场上销售的其它${black('同类产品')}相比,请问您觉得这款${red('口味B')}的新颖独特性如何呢?${qType(
'【单选题】'
)}`,
title: `与目前市场上销售的其它${black('同类产品')}相比,请问您觉得这款${red(
'口味B'
)}的新颖独特性如何呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#新颖独特性 口味二名称',
ans: ['非常新颖独特', '比较新颖独特', '谈不上有没有,一般', '不太新颖独特', '一点也不新颖独特']
ans: [
'非常新颖独特',
'比较新颖独特',
'谈不上有没有,一般',
'不太新颖独特',
'一点也不新颖独特'
]
},
{
seq: 'B6',
@@ -576,50 +620,66 @@ export default {
table: {
headers: ['', '喜欢程度'],
rows: [
['奶香味(喝起来奶香浓醇)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['甜味(自然清甜味,非人工添加糖剂)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['稀稠度(喝起来的厚薄程度)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'],
['醇厚度(喝起来没有被稀释过的感觉)', '非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢']
[
'奶香味(喝起来奶香浓醇)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'甜味(自然清甜味,非人工添加糖剂)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'稀稠度(喝起来的厚薄程度)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
],
[
'醇厚度(喝起来没有被稀释过的感觉)',
'非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢'
]
]
}
},
{
seq: 'B6.1',
title: `请问您觉得这个${red('口味B')}喝起来的${black('奶香味(喝起来奶香浓醇)')}如何?${qType('【单选题】')}`,
title: `请问您觉得这个${red('口味B')}喝起来的${black(
'奶香味(喝起来奶香浓醇)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-奶香味(喝起来奶香浓醇) 口味二名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'B6.2',
title: `请问您觉得这个${red('口味B')}喝起来的${black('甜味(自然清甜味,非人工添加糖剂)')}如何?${qType(
'【单选题】'
)}`,
title: `请问您觉得这个${red('口味B')}喝起来的${black(
'甜味(自然清甜味,非人工添加糖剂)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-甜味(自然清甜味,非人工添加糖剂) 口味二名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'B6.3',
title: `请问您觉得这个${red('口味B')}喝起来的${black('稀稠度(喝起来的厚薄程度)')}如何?${qType('【单选题】')}`,
title: `请问您觉得这个${red('口味B')}喝起来的${black(
'稀稠度(喝起来的厚薄程度)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-稀稠度(喝起来的厚薄程度) 口味二名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'B6.4',
title: `请问您觉得这个${red('口味B')}喝起来的${black('醇厚度(喝起来没有被稀释过的感觉)')}如何?${qType(
'【单选题】'
)}`,
title: `请问您觉得这个${red('口味B')}喝起来的${black(
'醇厚度(喝起来没有被稀释过的感觉)'
)}如何?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#属性具体评价-醇厚度(喝起来没有被稀释过的感觉) 口味二名称',
ans: ['太过', '有一点过', '刚好', '有一点不够', '完全不够']
},
{
seq: 'B7',
title: `根据您品尝到的这款${red('口味B')}的口味和口感,您认为这款产品适合${black('在什么时候饮用')}呢?${qType(
'【单选题】'
)}`,
title: `根据您品尝到的这款${red('口味B')}的口味和口感,您认为这款产品适合${black(
'在什么时候饮用'
)}呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用时间 口味二名称',
ans: [
@@ -656,14 +716,18 @@ export default {
},
{
seq: 'B8',
title: `您认为这款${red('口味B')}最适合${black('在哪里饮用')}这产品呢?${qType('【单选题】')}`,
title: `您认为这款${red('口味B')}最适合${black('在哪里饮用')}这产品呢?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用场合 口味二名称',
ans: ['在家中(如自己家或朋友亲戚家)', '在工作/学习场所', '在户外/餐饮场所']
},
{
seq: 'B9',
title: `请设想一下,您饮用该${red('口味B')}${black('最可能')}${black('做什么')}呢?${qType('【单选题】')}`,
title: `请设想一下,您饮用该${red('口味B')}${black('最可能')}${black(
'做什么'
)}呢?${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#饮用时做什么 口味二名称',
ans: [
@@ -747,7 +811,9 @@ export default {
},
{
seq: 'B10',
title: `您认为您刚才品尝的这款${red('口味B')}适合${black('在什么地方售卖')}呢?${qType('【多选题】')}`,
title: `您认为您刚才品尝的这款${red('口味B')}适合${black('在什么地方售卖')}呢?${qType(
'【多选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#售卖渠道 口味二名称',
ans: [
@@ -804,9 +870,9 @@ export default {
},
{
seq: 'B11',
title: `您刚才品尝的这款${red('口味B')},下列哪句话最能描述它对您的${black('购买习惯的影响程度')}${qType(
'【单选题】'
)}`,
title: `您刚才品尝的这款${red('口味B')},下列哪句话最能描述它对您的${black(
'购买习惯的影响程度'
)}${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#购买行为影响 口味二名称',
ans: [
@@ -818,9 +884,11 @@ export default {
},
{
seq: 'B12',
title: `您刚才提到这款${red('口味B')}会替代您目前正在饮用的产品,那么您能告诉我您会用它${black(
'替代'
)}哪个或哪些您${black('目前正在饮')}用的饮品呢?${qType('【多选题】')}`,
title: `您刚才提到这款${red(
'口味B'
)}会替代您目前正在饮用的产品,那么您能告诉我您会用它${black('替代')}哪个或哪些您${black(
'目前正在饮'
)}用的饮品呢?${qType('【多选题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#品类替代 口味二名称',
ans: [
@@ -853,7 +921,9 @@ export default {
},
{
seq: 'B13',
title: `基于这款${red('口味B')}介绍中的描述和价格信息,综合您品尝到的口味,您倾向于饮用这款产品的频率为${black(
title: `基于这款${red(
'口味B'
)}介绍中的描述和价格信息,综合您品尝到的口味,您倾向于饮用这款产品的频率为${black(
'每周几次'
)}${qType('【单选题】')}`,
topic: '[题干系统自动插入口味编号]',
@@ -898,7 +968,9 @@ export default {
},
{
seq: 'E1',
title: `综合比较这几款产品的口味和口感,您${black('更加喜欢')}哪一款产品呢?${qType('【单选题】')}`,
title: `综合比较这几款产品的口味和口感,您${black('更加喜欢')}哪一款产品呢?${qType(
'【单选题】'
)}`,
tip: '#强制对比',
noBottom: true
},
@@ -927,7 +999,9 @@ export default {
},
{
seq: 'A1',
title: `请问您对您刚才品尝过的${red('口味A')}${black('总体喜欢程度')}是怎样的?${qType('【单选题】')}`,
title: `请问您对您刚才品尝过的${red('口味A')}${black('总体喜欢程度')}是怎样的?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#总体喜欢程度 口味一名称',
ans: ['非常喜欢', '比较喜欢', '一般', '不太喜欢', '完全不喜欢']
@@ -949,7 +1023,9 @@ export default {
},
{
seq: 'B1',
title: `请问您对您刚才品尝过的${red('口味B')}${black('总体喜欢程度')}是怎样的?${qType('【单选题】')}`,
title: `请问您对您刚才品尝过的${red('口味B')}${black('总体喜欢程度')}是怎样的?${qType(
'【单选题】'
)}`,
topic: '[题干系统自动插入口味编号]',
tip: '#总体喜欢程度 口味二名称',
ans: ['非常喜欢', '比较喜欢', '一般', '不太喜欢', '完全不喜欢']
@@ -959,7 +1035,9 @@ export default {
},
{
seq: 'E1',
title: `综合比较这几款产品的口味和口感,您${black('更加喜欢')}哪一款产品呢?${qType('【单选题】')}`,
title: `综合比较这几款产品的口味和口感,您${black('更加喜欢')}哪一款产品呢?${qType(
'【单选题】'
)}`,
tip: '#强制对比',
noBottom: true
},
@@ -1019,13 +1097,17 @@ export default {
},
{
seq: 'A1',
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red('口味A')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red(
'口味A'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#不喜欢方面 口味一名称'
},
{
seq: 'A2',
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red('口味A')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red(
'口味A'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#喜欢方面 口味一名称'
},
@@ -1034,13 +1116,17 @@ export default {
},
{
seq: 'B1',
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red('口味B')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${red('不喜欢')}这款${red(
'口味B'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#不喜欢方面 口味二名称'
},
{
seq: 'B2',
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red('口味B')}的哪些方面?${qType('【填空题】')}`,
title: `您已经品尝了这款产品,请告诉我您${green('喜欢')}这款${red(
'口味B'
)}的哪些方面?${qType('【填空题】')}`,
topic: '[题干系统自动插入口味编号]',
tip: '#喜欢方面 口味二名称'
}

View File

@@ -171,7 +171,13 @@
"title": "与目前市场上销售的其它<span style=\"font-weight:700;color:black;text-decoration:underline;\">同类产品</span>相比,请问您觉得这款<span style=\"font-weight:700;color:red;text-decoration:underline;\">口味A</span>的<span style=\"font-weight:700;color:black;text-decoration:underline;\">新颖独特性</span>如何呢?<span style=\"font-weight:700;\">【单选题】</span>",
"topic": "[题干系统自动插入口味编号]",
"tip": "#新颖独特性 口味一名称",
"ans": ["非常新颖独特", "比较新颖独特", "谈不上有没有,一般", "不太新颖独特", "一点也不新颖独特"]
"ans": [
"非常新颖独特",
"比较新颖独特",
"谈不上有没有,一般",
"不太新颖独特",
"一点也不新颖独特"
]
},
{
"seq": "A6",
@@ -181,10 +187,22 @@
"table": {
"headers": ["", "喜欢程度"],
"rows": [
["奶香味(喝起来奶香浓醇)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["甜味(自然清甜味,非人工添加糖剂)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["稀稠度(喝起来的厚薄程度)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["醇厚度(喝起来没有被稀释过的感觉)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"]
[
"奶香味(喝起来奶香浓醇)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"甜味(自然清甜味,非人工添加糖剂)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"稀稠度(喝起来的厚薄程度)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"醇厚度(喝起来没有被稀释过的感觉)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
]
]
}
},
@@ -524,7 +542,13 @@
"title": "与目前市场上销售的其它<span style=\"font-weight:700;color:black;text-decoration:underline;\">同类产品</span>相比,请问您觉得这款<span style=\"font-weight:700;color:red;text-decoration:underline;\">口味B</span>的新颖独特性如何呢?<span style=\"font-weight:700;\">【单选题】</span>",
"topic": "[题干系统自动插入口味编号]",
"tip": "#新颖独特性 口味二名称",
"ans": ["非常新颖独特", "比较新颖独特", "谈不上有没有,一般", "不太新颖独特", "一点也不新颖独特"]
"ans": [
"非常新颖独特",
"比较新颖独特",
"谈不上有没有,一般",
"不太新颖独特",
"一点也不新颖独特"
]
},
{
"seq": "B6",
@@ -534,10 +558,22 @@
"table": {
"headers": ["", "喜欢程度"],
"rows": [
["奶香味(喝起来奶香浓醇)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["甜味(自然清甜味,非人工添加糖剂)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["稀稠度(喝起来的厚薄程度)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"],
["醇厚度(喝起来没有被稀释过的感觉)", "非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"]
[
"奶香味(喝起来奶香浓醇)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"甜味(自然清甜味,非人工添加糖剂)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"稀稠度(喝起来的厚薄程度)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
],
[
"醇厚度(喝起来没有被稀释过的感觉)",
"非常喜欢、比较喜欢、一般,谈不上喜欢不喜欢、不太喜欢、一点也不喜欢"
]
]
}
},

View File

@@ -13,7 +13,15 @@ import BasicConfig from '../components/BasicConfig.vue';
import PackageTestItem from './PackageTestItem.vue';
import Steps from '../components/Steps.vue';
import { schemeEnum, testTypeEnum, standardNewestEnum, packageTypeEnum, encodeList } from '../consts';
import {
schemeEnum,
testTypeEnum,
standardNewestEnum,
packageTypeEnum,
encodeList,
getPackageForApi
} from '../consts';
import { isFullView } from './util';
import { postTemplates } from '../api';
@@ -46,19 +54,31 @@ const expandInnerNewest = ref(true);
const expandInnerStandard = ref(true);
// 标准版 - 外箱
const outerNewList1 = ref([getNewItem(standardNewestEnum.newest), getNewItem(standardNewestEnum.newest)]);
const outerNewList1 = ref([
getNewItem(standardNewestEnum.newest),
getNewItem(standardNewestEnum.newest)
]);
const outerStandardList1 = ref([getNewItem(standardNewestEnum.standard)]);
// 标准版 - 内包
const innerNewList1 = ref([getNewItem(standardNewestEnum.newest), getNewItem(standardNewestEnum.newest)]);
const innerNewList1 = ref([
getNewItem(standardNewestEnum.newest),
getNewItem(standardNewestEnum.newest)
]);
const innerStandardList1 = ref([getNewItem(standardNewestEnum.standard)]);
// 快测版 - 外箱
const outerNewList2 = ref([getNewItem(standardNewestEnum.newest), getNewItem(standardNewestEnum.newest)]);
const outerNewList2 = ref([
getNewItem(standardNewestEnum.newest),
getNewItem(standardNewestEnum.newest)
]);
const outerStandardList2 = ref([getNewItem(standardNewestEnum.standard)]);
// 快测版 - 内包
const innerNewList2 = ref([getNewItem(standardNewestEnum.newest), getNewItem(standardNewestEnum.newest)]);
const innerNewList2 = ref([
getNewItem(standardNewestEnum.newest),
getNewItem(standardNewestEnum.newest)
]);
const innerStandardList2 = ref([getNewItem(standardNewestEnum.standard)]);
// 配对版 - 外箱
@@ -194,10 +214,30 @@ function onAddItem(pType, standardAndNewest) {
}
function updateEncode() {
[outerNewList1.value, outerStandardList1.value] = updateEncodeForGroup(outerNewList1.value, outerStandardList1.value);
[innerNewList1.value, innerStandardList1.value] = updateEncodeForGroup(innerNewList1.value, innerStandardList1.value);
[outerNewList2.value, outerStandardList2.value] = updateEncodeForGroup(outerNewList2.value, outerStandardList2.value);
[innerNewList2.value, innerStandardList2.value] = updateEncodeForGroup(innerNewList2.value, innerStandardList2.value);
[outerNewList1.value, outerStandardList1.value] = updateEncodeForGroup(
outerNewList1.value,
outerStandardList1.value
);
[innerNewList1.value, innerStandardList1.value] = updateEncodeForGroup(
innerNewList1.value,
innerStandardList1.value
);
[outerNewList2.value, outerStandardList2.value] = updateEncodeForGroup(
outerNewList2.value,
outerStandardList2.value
);
[innerNewList2.value, innerStandardList2.value] = updateEncodeForGroup(
innerNewList2.value,
innerStandardList2.value
);
[outerNewList3.value, outerStandardList3.value] = updateEncodeForGroup(
outerNewList3.value,
outerStandardList3.value
);
[innerNewList3.value, innerStandardList3.value] = updateEncodeForGroup(
innerNewList3.value,
innerStandardList3.value
);
}
function updateEncodeForGroup(list1, list2) {
@@ -272,7 +312,7 @@ function checkTasteType(list) {
const newestList = [];
const newList = JSON.parse(JSON.stringify(list));
newList.forEach((i) => {
switch (i.data.taste_type) {
switch (i.data.package_type) {
case standardNewestEnum.standard:
standardList.push(i);
break;
@@ -294,15 +334,9 @@ function checkTasteType(list) {
return true;
}
function checkTaste() {
const list = {
[testTypeEnum.standard]: list1.value,
[testTypeEnum.quickTest]: list2.value,
[testTypeEnum.pair]: list3.value
}[testType.value];
function checkAdvanced(list, packageType) {
// 检查是否有空名称
const names = list.map((item) => item.data.taste_name);
const names = list.map((item) => item.data.package_name);
const emptyNameExists = names.some((name) => !name.trim());
if (emptyNameExists) {
message.error('包装名称不可为空,请检查后重试!');
@@ -311,7 +345,7 @@ function checkTaste() {
// 检查是否有重复名称
const nameCounts = list
.map((item) => item.data.taste_name)
.map((item) => item.data.package_name)
.reduce((acc, name) => {
acc[name] = (acc[name] || 0) + 1;
return acc;
@@ -322,68 +356,133 @@ function checkTaste() {
return false;
}
if ([testTypeEnum.standard].includes(testType.value)) {
// 检查是否有空关键属性指标
const indicators = list.flatMap((item) => item.data.taste_attr_indicator);
const emptyIndicatorsExists = indicators.some((name) => !name.trim());
if (emptyIndicatorsExists) {
message.error('关键属性指标不可为空,请检查后重试!');
const metricFieldMap = {
[testTypeEnum.standard]: 'standardChecked',
[testTypeEnum.quickTest]: 'quickTestChecked',
[testTypeEnum.pair]: 'pairChecked'
};
let metricField = metricFieldMap[testType.value];
metricField += packageType.value === packageTypeEnum.inner ? '2' : '';
const metricList = metric.value[metricField];
if (isFullView(metricList, packageType)) {
if (list.some((item) => !item.data.package_cover_picture?.length)) {
message.error('堆头图片不可为空,请检查后重试!');
return false;
}
// 检查同一包装下是否有重复的关键属性指标
if (
list.some((item) => {
item.data.taste_attr_indicator;
const idt = item.data.taste_attr_indicator;
return Array.from(new Set(idt)).length !== idt.length;
})
) {
message.error('同一包装内的关键属性指标不可重复,请检查后重试!');
if (list.some((item) => !item.data.not_hint_package_picture)) {
message.error('无提示包装图片不可为空,请检查后重试!');
return false;
}
}
return [testTypeEnum.standard, testTypeEnum.quickTest].includes(testType.value) ? checkTasteType(list) : true;
if (list.some((item) => !item.data.hint_package_picture)) {
message.error('提示后包装图片不可为空,请检查后重试!');
return false;
}
return [testTypeEnum.standard, testTypeEnum.quickTest].includes(testType.value)
? checkTasteType(list)
: true;
}
function checkOuter() {
if (packageType.value.includes(packageTypeEnum.outer)) {
const map = {
[testTypeEnum.standard]: [...outerNewList1.value, ...outerStandardList1.value],
[testTypeEnum.quickTest]: [...outerNewList2.value, ...outerStandardList2.value],
[testTypeEnum.pair]: [...outerNewList3.value, ...outerStandardList3.value]
};
const list = map[testType.value];
return checkAdvanced(list, packageTypeEnum.outer);
}
return true;
}
function checkInner() {
if (packageType.value.includes(packageTypeEnum.inner)) {
const map = {
[testTypeEnum.standard]: [...innerNewList1.value, ...innerStandardList1.value],
[testTypeEnum.quickTest]: [...innerNewList2.value, ...innerStandardList2.value],
[testTypeEnum.pair]: [...innerNewList3.value, ...innerStandardList3.value]
};
const list = map[testType.value];
return checkAdvanced(list, packageTypeEnum.inner);
}
return true;
}
const basicConfigRef = ref(null);
function onPrev() {
const index = stepList.value.findIndex((item) => item.id === stepId.value);
stepId.value = stepList.value[Math.max(0, index - 1)].id;
}
function onNext() {
const index = stepList.value.findIndex((item) => item.id === stepId.value);
stepId.value = stepList.value[Math.min(stepList.value.length - 1, index + 1)].id;
}
async function onSave() {
const result = await basicConfigRef.value.validateForm();
if (result.status === 'rejected') {
message.error(result.reason.flatMap((i) => i.errors).join('、'));
stepId.value = packageTypeEnum.basic;
return;
}
if (!checkTaste()) {
if (!checkOuter()) {
stepId.value = packageTypeEnum.outer;
return;
}
const list = {
[testTypeEnum.standard]: list1.value,
[testTypeEnum.quickTest]: list2.value,
[testTypeEnum.pair]: list3.value
}[testType.value].map((i) => Object.assign({}, i.data, { taste_encode: '' }));
if (!checkInner()) {
stepId.value = packageTypeEnum.inner;
return;
}
const metricList = [];
const metricListTemp = [
...(result.data.concept_indexes || []),
...(result.data.concept_indexes2 || [])
].map((i) => Object.assign({ type: i, is_select: 1 }));
metricListTemp.forEach((item) => {
if (!metricList.find((met) => met.type === item.type)) {
metricList.push(item);
}
});
const outerList = {
[testTypeEnum.standard]: [...outerNewList1.value, ...outerStandardList1.value],
[testTypeEnum.quickTest]: [...outerNewList2.value, ...outerStandardList2.value],
[testTypeEnum.pair]: [outerNewList3.value, ...outerStandardList3.value]
}[testType.value].map((i) => Object.assign({}, i.data));
const innerList = {
[testTypeEnum.standard]: [...innerNewList1.value, ...innerStandardList1.value],
[testTypeEnum.quickTest]: [...innerNewList2.value, ...innerStandardList2.value],
[testTypeEnum.pair]: [innerNewList3.value, ...innerStandardList3.value]
}[testType.value].map((i) => Object.assign({}, i.data));
const packageType = getPackageForApi(result.data.packageType);
const params = {
brand_id: result.data.brand_id,
scene_code_info: result.data.scene_code_info,
package_type: packageType,
sn: templateSn.value,
project_name: result.data.project_name || '',
tags: result.data.tags || [],
remarks: result.data.remarks || '',
concept_indexes: (result.data.concept_indexes || []).map((i) =>
Object.assign({
type: i,
is_select: 1
})
),
study_tastes: list,
study_package_out: [],
study_package_inter: []
concept_indexes: metricList || [],
study_package_out: outerList || [],
study_package_inter: innerList || []
};
const confirmModal = Modal.confirm({
@@ -424,6 +523,8 @@ async function onSave() {
:scheme-type="schemeEnum.package"
:test-type="testType"
:show-save="false"
:no-padding="true"
class="template-modal"
@save="onSave"
>
<Steps v-model:value="stepId" :list="stepList" />
@@ -486,7 +587,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-outer-newest-1">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteOuterNewestStandardItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteOuterNewestStandardItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -515,7 +620,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-outer-newest-2">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteOuterNewestQuickTestItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteOuterNewestQuickTestItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -541,11 +650,7 @@ async function onSave() {
:test-type="testTypeEnum.pair"
:package-type="packageTypeEnum.outer"
:metric="metric.pairChecked"
>
<div class="actions">
<i class="iconfont action-button draggable-outer-newest-3">&#xe71b;</i>
</div>
</PackageTestItem>
/>
</template>
</draggable>
</template>
@@ -595,7 +700,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-outer-standard-1">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteOuterStandardStandardItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteOuterStandardStandardItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -624,7 +733,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-outer-standard-2">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteOuterStandardQuickTestItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteOuterStandardQuickTestItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -650,11 +763,7 @@ async function onSave() {
:test-type="testTypeEnum.pair"
:package-type="packageTypeEnum.outer"
:metric="metric.pairChecked"
>
<div class="actions">
<i class="iconfont action-button draggable-outer-standard-3">&#xe71b;</i>
</div>
</PackageTestItem>
/>
</template>
</draggable>
</template>
@@ -706,7 +815,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-inner-newest-1">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteInnerNewestStandardItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteInnerNewestStandardItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -735,7 +848,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-inner-newest-2">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteInnerNewestQuickTestItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteInnerNewestQuickTestItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -761,11 +878,7 @@ async function onSave() {
:test-type="testTypeEnum.pair"
:package-type="packageTypeEnum.inner"
:metric="metric.pairChecked2"
>
<div class="actions">
<i class="iconfont action-button draggable-inner-newest-3">&#xe71b;</i>
</div>
</PackageTestItem>
/>
</template>
</draggable>
</template>
@@ -815,7 +928,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-inner-standard-1">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteInnerStandardStandardItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteInnerStandardStandardItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -844,7 +961,11 @@ async function onSave() {
>
<div class="actions">
<i class="iconfont action-button draggable-inner-standard-2">&#xe71b;</i>
<i class="iconfont action-button" @click="onDeleteInnerStandardQuickTestItem(element.key)">&#xe6b5;</i>
<i
class="iconfont action-button"
@click="onDeleteInnerStandardQuickTestItem(element.key)"
>&#xe6b5;</i
>
</div>
</PackageTestItem>
</template>
@@ -870,23 +991,26 @@ async function onSave() {
:test-type="testTypeEnum.pair"
:package-type="packageTypeEnum.inner"
:metric="metric.pairChecked2"
>
<div class="actions">
<i class="iconfont action-button draggable-inner-standard-3">&#xe71b;</i>
</div>
</PackageTestItem>
/>
</template>
</draggable>
</template>
</template>
<div class="footer">
<div class="footer-inner">
<a-button class="custom-button btn-outline">上一步</a-button>
<a-button class="custom-button btn-outline">一步</a-button>
<template #footer>
<div class="flex-none full-width flex flex-end footer">
<a-button v-if="stepId !== stepList[0].id" class="custom-button btn-outline" @click="onPrev"
>一步</a-button
>
<a-button
v-if="stepId !== stepList[stepList.length - 1].id"
class="custom-button btn-outline"
@click="onNext"
>下一步</a-button
>
<a-button type="primary" class="custom-button" @click="onSave">保存方案</a-button>
</div>
</div>
</template>
</TemplateModal>
</template>
@@ -895,6 +1019,10 @@ async function onSave() {
margin-bottom: 10px;
}
.p-20 {
padding: 20px;
}
.pointer {
cursor: pointer;
}
@@ -926,18 +1054,17 @@ async function onSave() {
transform: rotate(90deg);
}
.scroller {
height: calc(100% - 52px);
}
.footer {
height: 52px;
background-color: #FFFFFF;
padding: 0 20px;
background-color: #ffffff;
.footer-inner {
display: flex;
justify-content: flex-end;
align-items: center;
.custom-button {
margin-right: 14px;
}
.custom-button:not(:last-child) {
margin-right: 14px;
}
}
</style>

View File

@@ -99,28 +99,43 @@ function onNameChange() {
<div v-if="fullView" class="flex item-row mb-24">
<div class="flex-none label">测试品牌</div>
<a-input v-model:value="item.study_brand" :maxlength="12" placeholder="请输入测试品牌" class="custom-input">
<a-input
v-model:value="item.study_brand"
:maxlength="12"
placeholder="请输入测试品牌"
class="custom-input"
>
<template #suffix>
<span class="suffix">
{{ `${item.package_name?.length || 0} / 12` }}
{{ `${item.study_brand?.length || 0} / 12` }}
</span>
</template>
</a-input>
</div>
<div v-if="fullView" class="item-row">
<div v-if="fullView" class="item-row mb-10">
<div class="flex-none label mb-8">堆头图片</div>
<ImageUploader v-model:urls="item.package_cover_picture" :max="9" image-name="货架" />
</div>
<div v-if="fullView" class="item-row">
<div v-if="fullView" class="item-row mb-24">
<div class="flex-none label mb-8">无提示包装图片无品牌信息</div>
<ImageUploader v-model:url="item.not_hint_package_picture" :max="1" :multiple="false" image-name="包装" />
<ImageUploader
v-model:url="item.not_hint_package_picture"
:max="1"
:multiple="false"
image-name="包装"
/>
</div>
<div class="item-row">
<div v-if="fullView" class="flex-none label mb-8">提示后包装图片含品牌信息</div>
<ImageUploader v-model:url="item.hint_package_picture" :max="1" :multiple="false" image-name="包装" />
<ImageUploader
v-model:url="item.hint_package_picture"
:max="1"
:multiple="false"
image-name="包装"
/>
</div>
</div>
</template>

View File

@@ -211,7 +211,9 @@ function checkTaste() {
}
}
return [testTypeEnum.standard, testTypeEnum.quickTest].includes(testType.value) ? checkTasteType(list) : true;
return [testTypeEnum.standard, testTypeEnum.quickTest].includes(testType.value)
? checkTasteType(list)
: true;
}
const basicConfigRef = ref(null);
@@ -284,7 +286,12 @@ async function onSave() {
</script>
<template>
<TemplateModal v-model:visible="shown" :scheme-type="schemeEnum.taste" :test-type="testType" @save="onSave">
<TemplateModal
v-model:visible="shown"
:scheme-type="schemeEnum.taste"
:test-type="testType"
@save="onSave"
>
<BasicConfig
ref="basicConfigRef"
:scheme-type="schemeEnum.taste"

View File

@@ -197,8 +197,13 @@ function onMultipleLineInputChange(evt) {
</template>
</a-input>
<i class="iconfont" :class="[`drag-handler-indicator-${props.itemKey}`]">&#xe71b;</i>
<i v-if="item?.taste_attr_indicator?.length > 1" class="iconfont" @click="onDeleteIndicator(index)"
<i class="iconfont" :class="[`drag-handler-indicator-${props.itemKey}`]"
>&#xe71b;</i
>
<i
v-if="item?.taste_attr_indicator?.length > 1"
class="iconfont"
@click="onDeleteIndicator(index)"
>&#xe6b5;</i
>
</div>