Merge remote-tracking branch 'origin/feature/feature-20250331-h5' into feature/feature-20250331-h5
This commit is contained in:
2
components.d.ts
vendored
2
components.d.ts
vendored
@@ -31,8 +31,6 @@ declare module 'vue' {
|
||||
VanCol: typeof import('vant/es')['Col']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
"unplugin-auto-import": "^0.18.6",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^6.0.0",
|
||||
"vitest": "^3.0.9",
|
||||
"vue-tsc": "^2.0.21"
|
||||
},
|
||||
"browserslist": [
|
||||
|
||||
@@ -34,7 +34,7 @@ export const useQuestionStore = defineStore('questionStore', () => {
|
||||
return ![102, 104, 105, 201].includes(questions.value[0]?.question_type);
|
||||
});
|
||||
|
||||
// 作用未知
|
||||
// 作用未知, 应该是 language
|
||||
const l = ref({});
|
||||
// 主题颜色
|
||||
const themeColor = ref({});
|
||||
|
||||
110
src/types/question.d.ts
vendored
Normal file
110
src/types/question.d.ts
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
export declare interface OptionConfigType {
|
||||
type?: number;
|
||||
price?: number;
|
||||
title?: string;
|
||||
gradient?: string;
|
||||
image_url?: string[];
|
||||
child_area?: null;
|
||||
option_type?: number;
|
||||
instructions?: string[];
|
||||
binding_goods_id?: string;
|
||||
limit_right_content?: string;
|
||||
}
|
||||
|
||||
export declare interface questionOptionType {
|
||||
// 包含 HTML 标签的字符串,例如 "<p>选项1</p>"
|
||||
option?: string;
|
||||
is_other?: number;
|
||||
is_fixed?: number;
|
||||
is_remove_other?: number;
|
||||
level?: number;
|
||||
option_key?: string;
|
||||
option_index?: string;
|
||||
option_code?: string;
|
||||
option_config?: OptionConfigType;
|
||||
parent_option_index?: number;
|
||||
children?: null;
|
||||
}
|
||||
|
||||
declare interface IQuestionOption {
|
||||
type: number;
|
||||
cite_type: number;
|
||||
relation_type: number;
|
||||
relation_out_scope: number[];
|
||||
relation_last_scope: number;
|
||||
relation_first_scope: number;
|
||||
relation_question_index: number;
|
||||
options?: questionOptionType[];
|
||||
}
|
||||
|
||||
// 答案 config 类型
|
||||
export declare interface IQuestionConfig {
|
||||
text_type?: number;
|
||||
include_mark;
|
||||
disabled?: string[];
|
||||
version?: string;
|
||||
scene?: string | null;
|
||||
shelf?: string | null;
|
||||
ware?: string | null;
|
||||
row_option_groups?: string | null;
|
||||
cell_option_groups?: string | null;
|
||||
is_repeat?: number;
|
||||
allow_repeat_num?: number;
|
||||
repeat_type?: number;
|
||||
alert_text?: string;
|
||||
is_required?: number;
|
||||
is_change_row_cell?: number;
|
||||
select_random?: number;
|
||||
row_random?: number;
|
||||
cell_random?: number;
|
||||
is_three_dimensions?: number;
|
||||
material_sn?: string;
|
||||
scene_information?: string | null;
|
||||
simple_scene_information?: string | null;
|
||||
is_behavior?: number;
|
||||
is_price_tag?: number;
|
||||
is_brand?: number;
|
||||
is_initialize?: number;
|
||||
is_default_perspective?: number;
|
||||
is_disable_lines_same?: number;
|
||||
disable_lines_same?: number;
|
||||
float_window?: number;
|
||||
is_disable?: number;
|
||||
float_window_content?: string;
|
||||
popup_window?: number;
|
||||
popup_window_content?: string;
|
||||
is_show?: string[];
|
||||
quick_type?: number;
|
||||
is_limit_right_content?: number;
|
||||
option_group_random_inside?: string | null;
|
||||
option_group_random_outside?: string | null;
|
||||
}
|
||||
|
||||
// 答案 question
|
||||
export declare interface IQuestion<QuestionConfig> {
|
||||
error: string;
|
||||
answer?: unknown;
|
||||
id?: string;
|
||||
title?: string;
|
||||
stem?: string;
|
||||
other?: string;
|
||||
// options 列表项,第一个是默认
|
||||
list: questionOptionType[];
|
||||
question_index?: number;
|
||||
question_type?: number;
|
||||
config?: QuestionConfig;
|
||||
created_at?: string;
|
||||
created_user_id?: number;
|
||||
updated_user_id?: number | null;
|
||||
survey_id?: number;
|
||||
logic_config?: LogicConfig;
|
||||
options: questionOptionType[];
|
||||
associate?: any[];
|
||||
logics_has?: string | null;
|
||||
last_option_index?: number;
|
||||
question_code?: string;
|
||||
question_value?: string;
|
||||
question_tag?: string;
|
||||
planet_id?: string;
|
||||
permissions?: any | null;
|
||||
}
|
||||
33
src/types/questions/completion.d.ts
vendored
Normal file
33
src/types/questions/completion.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
declare interface ICompletionConfig {
|
||||
decimal_few: number;
|
||||
float_window: number;
|
||||
float_window_content: string;
|
||||
include_mark: number;
|
||||
is_behavior: number;
|
||||
is_brand: number;
|
||||
is_default_perspective: number;
|
||||
is_initialize: number;
|
||||
is_price_tag: number;
|
||||
is_required: number;
|
||||
is_show: string[];
|
||||
is_three_dimensions: number;
|
||||
left_prompt: string;
|
||||
line_height: number;
|
||||
line_type: number;
|
||||
material_sn: string;
|
||||
max: number | '';
|
||||
min: number | '';
|
||||
placeholder: string;
|
||||
popup_window: number;
|
||||
popup_window_content: string;
|
||||
quick_type: number;
|
||||
right_prompt: string;
|
||||
scene: string | null;
|
||||
scene_information: string | null;
|
||||
shelf: string | null;
|
||||
simple_scene_information: string | null;
|
||||
text_type: number;
|
||||
type_name: string;
|
||||
version: string;
|
||||
ware: string | null;
|
||||
}
|
||||
@@ -62,86 +62,6 @@ type Option = {
|
||||
cascade?: any[];
|
||||
};
|
||||
|
||||
/**
|
||||
* 配置类型
|
||||
* @property {string[]} disabled - 禁用的选项列表(通常为空数组)
|
||||
* @property {string} version - 版本号(通常为空字符串)
|
||||
* @property {string | null} scene - 场景(通常为 null)
|
||||
* @property {string | null} shelf - 货架(通常为 null)
|
||||
* @property {string | null} ware - 商品(通常为 null)
|
||||
* @property {string | null} row_option_groups - 行选项组(通常为 null)
|
||||
* @property {string | null} cell_option_groups - 列选项组(通常为 null)
|
||||
* @property {number} is_repeat - 是否重复(0 表示否,1 表示是)
|
||||
* @property {number} allow_repeat_num - 允许重复的数量
|
||||
* @property {number} repeat_type - 重复类型(通常为 0)
|
||||
* @property {string} alert_text - 提示文本
|
||||
* @property {number} is_required - 是否必填(0 表示否,1 表示是)
|
||||
* @property {number} is_change_row_cell - 是否允许更改行列选项(0 表示否,1 表示是)
|
||||
* @property {number} select_random - 是否随机选择行(0 表示否,1 表示是)
|
||||
* @property {number} row_random - 是否随机选择行选项(0 表示否,1 表示是)
|
||||
* @property {number} cell_random - 是否随机选择列选项(0 表示否,1 表示是)
|
||||
* @property {number} is_three_dimensions - 是否为三维矩阵(0 表示否,1 表示是)
|
||||
* @property {string} material_sn - 材料编号(通常为空字符串)
|
||||
* @property {string | null} scene_information - 场景信息(通常为 null)
|
||||
* @property {string | null} simple_scene_information - 简单场景信息(通常为 null)
|
||||
* @property {number} is_behavior - 是否为行为相关(0 表示否,1 表示是)
|
||||
* @property {number} is_price_tag - 是否为价格标签(0 表示否,1 表示是)
|
||||
* @property {number} is_brand - 是否为品牌相关(0 表示否,1 表示是)
|
||||
* @property {number} is_initialize - 是否初始化(0 表示否,1 表示是)
|
||||
* @property {number} is_default_perspective - 是否为默认视角(0 表示否,1 表示是)
|
||||
* @property {number} is_disable_lines_same - 是否禁用行列相同(0 表示否,1 表示是)
|
||||
* @property {number} disable_lines_same - 禁用行列相同的值(通常为 1)
|
||||
* @property {number} float_window - 是否显示悬浮窗(0 表示否,1 表示是)
|
||||
* @property {number} is_disable - 是否禁用(0 表示否,1 表示是)
|
||||
* @property {string} float_window_content - 悬浮窗内容(通常为空字符串)
|
||||
* @property {number} popup_window - 是否显示弹窗(0 表示否,1 表示是)
|
||||
* @property {string} popup_window_content - 弹窗内容(通常为空字符串)
|
||||
* @property {string[]} is_show - 是否显示的选项列表(通常为空数组)
|
||||
* @property {number} quick_type - 快速类型(通常为 0)
|
||||
* @property {number} is_limit_right_content - 是否限制右侧内容(0 表示否,1 表示是)
|
||||
* @property {string | null} option_group_random_inside - 行列选项组内随机(通常为 null)
|
||||
* @property {string | null} option_group_random_outside - 行列选项组外随机(通常为 null)
|
||||
*/
|
||||
type Config = {
|
||||
disabled?: string[];
|
||||
version?: string;
|
||||
scene?: string | null;
|
||||
shelf?: string | null;
|
||||
ware?: string | null;
|
||||
row_option_groups?: string | null;
|
||||
cell_option_groups?: string | null;
|
||||
is_repeat?: number;
|
||||
allow_repeat_num?: number;
|
||||
repeat_type?: number;
|
||||
alert_text?: string;
|
||||
is_required?: number;
|
||||
is_change_row_cell?: number;
|
||||
select_random?: number;
|
||||
row_random?: number;
|
||||
cell_random?: number;
|
||||
is_three_dimensions?: number;
|
||||
material_sn?: string;
|
||||
scene_information?: string | null;
|
||||
simple_scene_information?: string | null;
|
||||
is_behavior?: number;
|
||||
is_price_tag?: number;
|
||||
is_brand?: number;
|
||||
is_initialize?: number;
|
||||
is_default_perspective?: number;
|
||||
is_disable_lines_same?: number;
|
||||
disable_lines_same?: number;
|
||||
float_window?: number;
|
||||
is_disable?: number;
|
||||
float_window_content?: string;
|
||||
popup_window?: number;
|
||||
popup_window_content?: string;
|
||||
is_show?: string[];
|
||||
quick_type?: number;
|
||||
is_limit_right_content?: number;
|
||||
option_group_random_inside?: string | null;
|
||||
option_group_random_outside?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 逻辑配置类型
|
||||
* @property {string} expect - 期望值(通常为空字符串)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
interface OptionConfigType {
|
||||
type?: number;
|
||||
price?: number;
|
||||
title?: string;
|
||||
gradient?: string;
|
||||
image_url?: string[];
|
||||
child_area?: null;
|
||||
option_type?: number;
|
||||
instructions?: string[];
|
||||
binding_goods_id?: string;
|
||||
limit_right_content?: string;
|
||||
}
|
||||
|
||||
interface questionOptionType {
|
||||
// 包含 HTML 标签的字符串,例如 "<p>选项1</p>"
|
||||
option?: string;
|
||||
is_other?: number;
|
||||
is_fixed?: number;
|
||||
is_remove_other?: number;
|
||||
level?: number;
|
||||
option_key?: string;
|
||||
option_index?: string;
|
||||
option_code?: string;
|
||||
option_config?: OptionConfigType;
|
||||
parent_option_index?: number;
|
||||
children?: null;
|
||||
}
|
||||
|
||||
type questionsList = {
|
||||
type: number;
|
||||
cite_type: number;
|
||||
relation_type: number;
|
||||
relation_out_scope: number[];
|
||||
relation_last_scope: number;
|
||||
relation_first_scope: number;
|
||||
relation_question_index: number;
|
||||
options?: questionOptionType[];
|
||||
};
|
||||
|
||||
type question = {
|
||||
error: string;
|
||||
answer?: unknown;
|
||||
id?: string;
|
||||
title?: string;
|
||||
stem?: string;
|
||||
other?: string;
|
||||
list: questionsList[];
|
||||
question_index?: number;
|
||||
question_type?: number;
|
||||
config?: Config;
|
||||
created_at?: string;
|
||||
created_user_id?: number;
|
||||
updated_user_id?: number | null;
|
||||
survey_id?: number;
|
||||
logic_config?: LogicConfig;
|
||||
options: questionsList[];
|
||||
associate?: any[];
|
||||
logics_has?: string | null;
|
||||
last_option_index?: number;
|
||||
question_code?: string;
|
||||
question_value?: string;
|
||||
question_tag?: string;
|
||||
planet_id?: string;
|
||||
permissions?: any | null;
|
||||
};
|
||||
|
||||
@@ -24,26 +24,22 @@
|
||||
<!-- <img :src="icon" alt="icon" />-->
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="styleInfo.logo_status && styleInfo.logo_url"
|
||||
class="example-logo"
|
||||
:style="[
|
||||
{
|
||||
'justify-content':
|
||||
styleInfo.logo_site === 1
|
||||
? 'flex-start'
|
||||
: styleInfo.logo_site === 2
|
||||
? 'center'
|
||||
: 'flex-end'
|
||||
},
|
||||
{ 'padding-left': styleInfo.logo_site === 1 ? '20px' : '' },
|
||||
{ 'padding-right': styleInfo.logo_site === 3 ? '20px' : '' },
|
||||
{ position: styleInfo.head_img_status ? 'absolute' : '' },
|
||||
!styleInfo.head_img_status && styleInfo.background_status
|
||||
? `background-color: ${styleInfo.background_color};background-image: url(${styleInfo.background_url})`
|
||||
: ''
|
||||
]"
|
||||
>
|
||||
<div v-if="styleInfo.logo_status && styleInfo.logo_url" class="example-logo" :style="[
|
||||
{
|
||||
'justify-content':
|
||||
styleInfo.logo_site === 1
|
||||
? 'flex-start'
|
||||
: styleInfo.logo_site === 2
|
||||
? 'center'
|
||||
: 'flex-end'
|
||||
},
|
||||
{ 'padding-left': styleInfo.logo_site === 1 ? '20px' : '' },
|
||||
{ 'padding-right': styleInfo.logo_site === 3 ? '20px' : '' },
|
||||
{ position: styleInfo.head_img_status ? 'absolute' : '' },
|
||||
!styleInfo.head_img_status && styleInfo.background_status
|
||||
? `background-color: ${styleInfo.background_color};background-image: url(${styleInfo.background_url})`
|
||||
: ''
|
||||
]">
|
||||
<img class="logo" :src="styleInfo.logo_url" alt="logo" />
|
||||
</div>
|
||||
|
||||
@@ -51,14 +47,8 @@
|
||||
<!-- eslint-disable-next-line -->
|
||||
<div class="questions">
|
||||
<!-- 提前终止和正常完成 -->
|
||||
<q-last
|
||||
v-if="page === pages.length + 1"
|
||||
:code="questionsData?.action?.code"
|
||||
:action="questionsData?.action"
|
||||
:survey="questionsData?.survey"
|
||||
:isAnswer="isAnswer"
|
||||
:isTemplate="isTemplate"
|
||||
/>
|
||||
<q-last v-if="page === pages.length + 1" :code="questionsData?.action?.code" :action="questionsData?.action"
|
||||
:survey="questionsData?.survey" :isAnswer="isAnswer" :isTemplate="isTemplate" />
|
||||
<!-- 问卷名和描述 -->
|
||||
<!-- <q-first v-else-if="page === 0" isMobile :title="questionsData?.survey?.title"
|
||||
:desc="questionsData?.survey?.introduction" :questions="questionsData?.questions" :isAnswer="isAnswer"
|
||||
@@ -70,13 +60,8 @@
|
||||
:questionType="question.question_type" :questionIndex="question.question_index"
|
||||
:showTitle="styleInfo.is_question_number && true" isMobile :isAnswer="isAnswer"> -->
|
||||
|
||||
<div
|
||||
v-for="question in questions"
|
||||
v-else
|
||||
:id="'questionIndex' + question.question_index"
|
||||
:key="question.question_index"
|
||||
class="question"
|
||||
>
|
||||
<div v-for="question in questions" v-else :id="'questionIndex' + question.question_index"
|
||||
:key="question.question_index" class="question">
|
||||
<!-- <q-radio-->
|
||||
<!-- v-if="question.question_type === 1"-->
|
||||
<!-- :list="question.list"-->
|
||||
@@ -92,37 +77,17 @@
|
||||
<!-- :question="question"-->
|
||||
<!-- />-->
|
||||
<!-- 单选题 -->
|
||||
<preview-choice
|
||||
v-if="question.question_type === 1"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:config="question.config"
|
||||
:hideOptions="question.hideOptions"
|
||||
:stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn"
|
||||
:question="question"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-choice v-if="question.question_type === 1" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:config="question.config" :hideOptions="question.hideOptions" :stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn" :answerSurveySn="questionsData.answer.survey_sn" :question="question"
|
||||
@previous="previous" @next="next" @change-answer="onRelation($event, question)" />
|
||||
<!-- 多选题 -->
|
||||
<preview-checkbox
|
||||
v-else-if="question.question_type === 2"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:config="question.config"
|
||||
:hideOptions="question.hideOptions"
|
||||
:stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn"
|
||||
:question="question"
|
||||
@change-answer="onRelation($event, question)"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
/>
|
||||
<preview-checkbox v-else-if="question.question_type === 2" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:config="question.config" :hideOptions="question.hideOptions" :stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn" :answerSurveySn="questionsData.answer.survey_sn" :question="question"
|
||||
@change-answer="onRelation($event, question)" @previous="previous" @next="next" />
|
||||
<!-- <!– 级联题 –>-->
|
||||
<!-- <q-cascader-->
|
||||
<!-- v-else-if="question.question_type === 3"-->
|
||||
@@ -133,43 +98,19 @@
|
||||
<!-- isMobile-->
|
||||
<!-- />-->
|
||||
<!-- 填空题 -->
|
||||
<preview-completion
|
||||
v-else-if="question.question_type === 4"
|
||||
:config="question.config"
|
||||
:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn"
|
||||
:question="question"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-completion v-else-if="question.question_type === 4" :config="question.config" :answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn" :answerSurveySn="questionsData.answer.survey_sn" :question="question"
|
||||
@previous="previous" @next="next" @change-answer="onRelation($event, question)" />
|
||||
<!-- 打分题 -->
|
||||
<preview-rate
|
||||
v-else-if="question.question_type === 5"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:config="question.config"
|
||||
:question="question"
|
||||
isMobile
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-rate v-else-if="question.question_type === 5" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:config="question.config" :question="question" isMobile @change-answer="onRelation($event, question)" />
|
||||
<!-- 图文说明题 -->
|
||||
<preview-text-with-images
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:stem="question.stem"
|
||||
v-else-if="question.question_type === 6"
|
||||
:config="question.config"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
v-model:answer="question.answer"
|
||||
:answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn"
|
||||
:question="question"
|
||||
/>
|
||||
<preview-text-with-images :answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:stem="question.stem" v-else-if="question.question_type === 6" :config="question.config" @previous="previous"
|
||||
@next="next" v-model:answer="question.answer" :answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn" :question="question" />
|
||||
<!-- <!– 日期时间题 –>-->
|
||||
<!-- <q-date-->
|
||||
<!-- v-else-if="question.question_type === 7"-->
|
||||
@@ -179,45 +120,20 @@
|
||||
<!-- isMobile-->
|
||||
<!-- />-->
|
||||
<!-- 矩阵填空题 -->
|
||||
<preview-matrix-text
|
||||
v-else-if="question.question_type === 8"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:questionIndex="question.question_index"
|
||||
:config="question.config"
|
||||
:stem="question.stem"
|
||||
:question="question"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-matrix-text v-else-if="question.question_type === 8" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:questionIndex="question.question_index" :config="question.config" :stem="question.stem" :question="question"
|
||||
@previous="previous" @next="next" @change-answer="onRelation($event, question)" />
|
||||
<!-- 矩阵单选题 -->
|
||||
<preview-matrix-radio
|
||||
v-else-if="question.question_type === 9"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:questionIndex="question.question_index"
|
||||
:config="question.config"
|
||||
:stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn"
|
||||
:answerSurveySn="questionsData.answer.survey_sn"
|
||||
:question="question"
|
||||
@change-answer="onRelation($event, question)"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
/>
|
||||
<preview-matrix-radio v-else-if="question.question_type === 9" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:questionIndex="question.question_index" :config="question.config" :stem="question.stem"
|
||||
:answerSn="questionsData.answer.sn" :answerSurveySn="questionsData.answer.survey_sn" :question="question"
|
||||
@change-answer="onRelation($event, question)" @previous="previous" @next="next" />
|
||||
<!-- 矩阵多选题 -->
|
||||
<preview-matrix-checkbox
|
||||
v-else-if="question.question_type === 10"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:list="question.list"
|
||||
:config="question.config"
|
||||
:question="question"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-matrix-checkbox v-else-if="question.question_type === 10" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :list="question.list"
|
||||
:config="question.config" :question="question" @change-answer="onRelation($event, question)" />
|
||||
<!-- <!– 矩阵打分题 –>-->
|
||||
<!-- <matrix-rate-->
|
||||
<!-- v-else-if="question.question_type === 11"-->
|
||||
@@ -285,16 +201,10 @@
|
||||
<!-- isMobile-->
|
||||
<!-- />-->
|
||||
<!-- 文件上传题 -->
|
||||
<preview-file-upload
|
||||
v-else-if="question.question_type === 18"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:config="question.config"
|
||||
:question="question"
|
||||
isMobile
|
||||
:questionIndex="question.question_index"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-file-upload v-else-if="question.question_type === 18" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :config="question.config"
|
||||
:question="question" isMobile :questionIndex="question.question_index"
|
||||
@change-answer="onRelation($event, question)" />
|
||||
<!-- <!– 地理位置题 –>-->
|
||||
<!-- <q-map-->
|
||||
<!-- v-else-if="question.question_type === 19"-->
|
||||
@@ -323,14 +233,9 @@
|
||||
<!-- isMobile-->
|
||||
<!-- />-->
|
||||
<!-- 签名题 -->
|
||||
<preview-sign
|
||||
v-else-if="question.question_type === 22"
|
||||
:config="question.config"
|
||||
:question="question"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-sign v-else-if="question.question_type === 22" :config="question.config" :question="question"
|
||||
v-model:answer="question.answer" :answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
@change-answer="onRelation($event, question)" />
|
||||
<!-- <!– 知情同意书 –>-->
|
||||
<!-- <q-consent-->
|
||||
<!-- v-else-if="question.question_type === 23"-->
|
||||
@@ -454,26 +359,12 @@
|
||||
<!-- :question="question"-->
|
||||
<!-- />-->
|
||||
<!-- <!– 高级题型-NPS –>-->
|
||||
<preview-n-p-s
|
||||
v-else-if="question.question_type === 106"
|
||||
v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)"
|
||||
:isPreview="isPreview"
|
||||
:title="question.title"
|
||||
:stem="question.stem"
|
||||
:list="question.list"
|
||||
:config="question.config"
|
||||
:isAnswer="isAnswer"
|
||||
:questionIndex="question.question_index"
|
||||
:label="question.title"
|
||||
:loading="loading"
|
||||
:isTemplate="isTemplate"
|
||||
:showTitle="styleInfo.is_question_number"
|
||||
:question="question"
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
@change-answer="onRelation($event, question)"
|
||||
/>
|
||||
<preview-n-p-s v-else-if="question.question_type === 106" v-model:answer="question.answer"
|
||||
:answerIndex="getQuestionIndex(questionsData.questions, question)" :isPreview="isPreview"
|
||||
:title="question.title" :stem="question.stem" :list="question.list" :config="question.config"
|
||||
:isAnswer="isAnswer" :questionIndex="question.question_index" :label="question.title" :loading="loading"
|
||||
:isTemplate="isTemplate" :showTitle="styleInfo.is_question_number" :question="question" @previous="previous"
|
||||
@next="next" @change-answer="onRelation($event, question)" />
|
||||
</div>
|
||||
|
||||
<!-- <LangTranslate v-if="isAnswer && styleInfo.is_yip" translate-key="PoweredByDigitalTechnologyCenterYIP"
|
||||
@@ -484,33 +375,14 @@
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<!-- eslint-disable max-len -->
|
||||
<pfe-pagination
|
||||
v-if="isPreview"
|
||||
class="pagination"
|
||||
:isPreview="isPreview"
|
||||
:page="page"
|
||||
:pages="pages.length + 1"
|
||||
:min="styleInfo.is_home ? 0 : 1"
|
||||
:loading="loading"
|
||||
:showPrevious="styleInfo.is_up_button"
|
||||
:showStart="styleInfo.is_start_button"
|
||||
:startText="styleInfo.start_button_text"
|
||||
:showSubmit="styleInfo.is_submit_button"
|
||||
:submitText="
|
||||
localPageTimer.is_show && localPageTimer.short_time
|
||||
<pfe-pagination v-if="isPreview" class="pagination" :isPreview="isPreview" :page="page" :pages="pages.length + 1"
|
||||
:min="styleInfo.is_home ? 0 : 1" :loading="loading" :showPrevious="styleInfo.is_up_button"
|
||||
:showStart="styleInfo.is_start_button" :startText="styleInfo.start_button_text"
|
||||
:showSubmit="styleInfo.is_submit_button" :submitText="localPageTimer.is_show && localPageTimer.short_time
|
||||
? `${localPageTimer.short_time}S`
|
||||
: styleInfo.submit_button_text
|
||||
"
|
||||
:buttonTextColor="styleInfo.button_text_color"
|
||||
:buttonColor="styleInfo.button_color"
|
||||
:nextText="
|
||||
localPageTimer.is_show && localPageTimer.short_time ? `${localPageTimer.short_time}S` : ''
|
||||
"
|
||||
:nextDisabled="localPageTimer.short_time"
|
||||
isMobile
|
||||
@previous="previous"
|
||||
@next="next"
|
||||
>
|
||||
" :buttonTextColor="styleInfo.button_text_color" :buttonColor="styleInfo.button_color" :nextText="localPageTimer.is_show && localPageTimer.short_time ? `${localPageTimer.short_time}S` : ''
|
||||
" :nextDisabled="localPageTimer.short_time" isMobile @previous="previous" @next="next">
|
||||
</pfe-pagination>
|
||||
</div>
|
||||
<!-- eslint-enable max-len -->
|
||||
@@ -593,7 +465,7 @@ console.log(`now page is template? ${isTemplate.value}`);
|
||||
getQuestions();
|
||||
|
||||
// 更新数据
|
||||
async function getQuestions() {
|
||||
async function getQuestions () {
|
||||
let { data } = await AnswerApi.getQuetions({
|
||||
id: route.query.sn,
|
||||
data: {
|
||||
@@ -615,7 +487,7 @@ async function getQuestions() {
|
||||
}
|
||||
|
||||
// 上一页
|
||||
async function previous() {
|
||||
async function previous () {
|
||||
if (prevLoading.value || loading.value) {
|
||||
return;
|
||||
}
|
||||
@@ -638,7 +510,7 @@ async function previous() {
|
||||
}
|
||||
|
||||
// 下一页
|
||||
async function next(callbackBeforePage) {
|
||||
async function next (callbackBeforePage) {
|
||||
// console.log(`click next button`, prevLoading.value || loading.value);
|
||||
// if (prevLoading.value || loading.value) {
|
||||
// return;
|
||||
@@ -659,7 +531,7 @@ async function next(callbackBeforePage) {
|
||||
|
||||
// 开始答题
|
||||
// 答题
|
||||
async function answer(callback, callbackBeforePage) {
|
||||
async function answer (callback, callbackBeforePage) {
|
||||
if ((questions.value.length || !questionsData.value.questions.length) && !props.isTemplate) {
|
||||
// 表单验证(当前页)
|
||||
const errors = questions.value.filter((question) => {
|
||||
@@ -865,62 +737,6 @@ async function answer(callback, callbackBeforePage) {
|
||||
isError = true;
|
||||
question.error = translatedText.value.PleaseUploadAtLeastOneFiles(config.min_number);
|
||||
} else if (answer && questionType === 4) {
|
||||
question.error = '';
|
||||
// 填空题
|
||||
const { value } = answer;
|
||||
const newValue = value.replace(/\n|\r|\r\n/g, '');
|
||||
switch (config.text_type) {
|
||||
// 字母
|
||||
case 3:
|
||||
// eslint-disable-next-line
|
||||
const reg =
|
||||
/^[a-zA-Z·~!@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/;
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !reg.test(newValue) || !newValue.length
|
||||
: !/^[a-zA-Z]+$/.test(newValue) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : '';
|
||||
break;
|
||||
// 中文
|
||||
case 4:
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~!@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length
|
||||
: !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterChineseWords : '';
|
||||
break;
|
||||
// 邮箱
|
||||
case 5:
|
||||
isError =
|
||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : '';
|
||||
break;
|
||||
// 手机号
|
||||
case 6:
|
||||
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectPhone : '';
|
||||
break;
|
||||
// 身份证号
|
||||
case 7:
|
||||
isError =
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectID : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!isError && value.length < config.min && ![1, 2].includes(config.text_type)) {
|
||||
isError = true;
|
||||
question.error = translatedText.value.PleaseEnterMoreThanOneCharacters(config.min);
|
||||
}
|
||||
} else if (answer && questionType === 8) {
|
||||
// 矩阵填空题
|
||||
question.error = '';
|
||||
@@ -1224,7 +1040,7 @@ async function answer(callback, callbackBeforePage) {
|
||||
}
|
||||
|
||||
// 关联引用
|
||||
function onRelation(
|
||||
function onRelation (
|
||||
// 避免出现参数 undefined 情况
|
||||
{ options, value, list } = {},
|
||||
{ question_type: _questionType, question_index: _questionIndex, related, answer } = {}
|
||||
@@ -1340,7 +1156,7 @@ function onRelation(
|
||||
});
|
||||
}
|
||||
|
||||
function jumpImmediately() {
|
||||
function jumpImmediately () {
|
||||
const code = questionsData.value.action?.code;
|
||||
if (page.value !== pages.value.length + 1 && ![20004, 20011, 20016].includes(code)) {
|
||||
return;
|
||||
@@ -1393,7 +1209,7 @@ function jumpImmediately() {
|
||||
}
|
||||
|
||||
// 更新答案
|
||||
function updateAnswer(auto) {
|
||||
function updateAnswer (auto) {
|
||||
if (auto) {
|
||||
auto.forEach((autoItem) => {
|
||||
const question = questionsData.value.questions.find(
|
||||
@@ -1416,7 +1232,7 @@ function updateAnswer(auto) {
|
||||
}
|
||||
}
|
||||
// 选项隐藏
|
||||
function hideOptions(hide) {
|
||||
function hideOptions (hide) {
|
||||
const questionIndex = hide?.question_index;
|
||||
if (questionIndex) {
|
||||
const question = questionsData.value.questions.find(
|
||||
@@ -1427,7 +1243,7 @@ function hideOptions(hide) {
|
||||
}
|
||||
|
||||
// 要搜索的数组和要查找的连续数字的数量n
|
||||
function hasNConsecutiveNumbers(arr, n, onTrue, onFalse) {
|
||||
function hasNConsecutiveNumbers (arr, n, onTrue, onFalse) {
|
||||
let count = 1;
|
||||
let warnStart = 0;
|
||||
let prevNum = arr[0];
|
||||
@@ -1450,7 +1266,7 @@ function hasNConsecutiveNumbers(arr, n, onTrue, onFalse) {
|
||||
|
||||
// eslint-disable
|
||||
// 跳转链接
|
||||
function toUrl(url) {
|
||||
function toUrl (url) {
|
||||
// 创建一个新的变量来存储修改后的 URL
|
||||
let modifiedUrl = url;
|
||||
|
||||
@@ -1473,7 +1289,7 @@ function toUrl(url) {
|
||||
* 清空 answer 答案
|
||||
* @param questions
|
||||
*/
|
||||
function clearAnswer(questions) {
|
||||
function clearAnswer (questions) {
|
||||
if (!questions) return;
|
||||
questions.forEach((question) => {
|
||||
if (!question.answer) return;
|
||||
@@ -1483,6 +1299,7 @@ function clearAnswer(questions) {
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/css/main';
|
||||
|
||||
:deep(.van-cell::after) {
|
||||
display: none;
|
||||
}
|
||||
@@ -1490,7 +1307,8 @@ function clearAnswer(questions) {
|
||||
.preview-icon {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 65px; /* 根据实际图片大小调整 */
|
||||
width: 65px;
|
||||
/* 根据实际图片大小调整 */
|
||||
height: 50px;
|
||||
margin-right: 40px;
|
||||
margin-left: 30px;
|
||||
@@ -1502,8 +1320,10 @@ function clearAnswer(questions) {
|
||||
position: absolute;
|
||||
bottom: -70px;
|
||||
left: -10px;
|
||||
width: 65px; /* 根据实际图片大小调整 */
|
||||
height: 140px; /* 根据实际图片大小调整 */
|
||||
width: 65px;
|
||||
/* 根据实际图片大小调整 */
|
||||
height: 140px;
|
||||
/* 根据实际图片大小调整 */
|
||||
background: url('@/assets/img/create-right-back.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
@@ -1535,6 +1355,7 @@ function clearAnswer(questions) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.end-text {
|
||||
position: fixed;
|
||||
bottom: 65px;
|
||||
@@ -1544,11 +1365,13 @@ function clearAnswer(questions) {
|
||||
color: #a5a5ac;
|
||||
background-color: #f2f2f2;
|
||||
z-index: 10;
|
||||
|
||||
& .el-text {
|
||||
font-size: 12px;
|
||||
color: #4b4b59 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-info {
|
||||
display: flex;
|
||||
grid-template-columns: 1fr 80px;
|
||||
|
||||
@@ -12,40 +12,47 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineEmits, ref, watch } from 'vue';
|
||||
import Completion from '@/views/Design/components/Questions/Completion.vue';
|
||||
import Rate from '@/views/Design/components/Questions/Rate.vue';
|
||||
// 预览新增 v-model
|
||||
// const config = defineModel('config');
|
||||
const answer = defineModel<{ value: string | number }>('answer', { default: { value: '' } });
|
||||
import type { IQuestion } from '@/types/question';
|
||||
import { validateCompletion } from '@/views/Survey/views/Preview/components/questions/validate/previewCompletion';
|
||||
|
||||
interface ICompletionAnswer {
|
||||
value: string;
|
||||
}
|
||||
|
||||
const answer = defineModel<ICompletionAnswer>('answer', { default: {} });
|
||||
|
||||
const answerIndex = computed(() => {
|
||||
return question.value.title;
|
||||
});
|
||||
// const stem = defineModel('stem');
|
||||
const question = defineModel<question>('question', { default: () => {} });
|
||||
// const list = defineModel<questionsList[]>('list');
|
||||
// const answerSn = defineModel<string>('answerSn');
|
||||
// const answerSurveySn = defineModel<answerSurveySn>('answerSurveySn');
|
||||
// const modelValue = defineModel('modelValue');
|
||||
|
||||
// // 预览新增 emit ['changeAnswer', 'previous', 'next']
|
||||
const question = defineModel<IQuestion<ICompletionConfig>>('question', { default: () => {} });
|
||||
const emit = defineEmits(['previous', 'next', 'update:modelValue', 'saveOption', 'changeAnswer']);
|
||||
|
||||
// console.log(`answer`, answer.value);
|
||||
// console.log(question.value);
|
||||
const completionValue = ref(answer.value?.value ?? '');
|
||||
// console.log(`question:`, question.value);
|
||||
// console.log(`list: `, list.value);
|
||||
const completionValue = ref<string>(answer.value?.value ?? '');
|
||||
|
||||
// 进行提交答案
|
||||
watch(
|
||||
() => completionValue.value,
|
||||
() => {
|
||||
const res = {
|
||||
value: completionValue.value
|
||||
};
|
||||
(value) => {
|
||||
// 答案校验,生成最终答案
|
||||
const { isError } = validateCompletion(question.value, question.value.config!, String(value));
|
||||
console.log(`isError, question`, isError, question.value);
|
||||
if (isError) return;
|
||||
|
||||
const res = generateAnswer(value);
|
||||
answer.value = res;
|
||||
question.value!.answer = res;
|
||||
emit('changeAnswer', res);
|
||||
// answer emit 提交失效
|
||||
// emit('changeAnswer', res);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 生成最终答案
|
||||
* @param answer {string}
|
||||
*/
|
||||
function generateAnswer(answer: string) {
|
||||
return { value: answer };
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
interface ICompletionAnswer {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export { ICompletionAnswer };
|
||||
@@ -0,0 +1,23 @@
|
||||
// 语言转换类型
|
||||
// export interface ITranslatedText {
|
||||
// [key: string]: string | ((value: number) => string);
|
||||
// }
|
||||
|
||||
import { language } from '@/views/Survey/views/Preview/js/language';
|
||||
|
||||
type originLanguage = typeof language;
|
||||
export type languageArea = 'zh' | 'en';
|
||||
/**
|
||||
* 转换之后的 translatedText
|
||||
* originLanguage[K] 属性 value
|
||||
* 对应的属性格式为
|
||||
* ```typescript
|
||||
* ITranslatedText{
|
||||
* some: string,
|
||||
* other: (value: number) => string
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export type ITranslatedText = {
|
||||
[K in keyof originLanguage]: originLanguage[K][languageArea];
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { IQuestion } from '@/types/question';
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
import { validateEnglishLetters } from '@/views/Survey/views/Preview/components/questions/validate/validateEnglishLetters';
|
||||
import { validateChineseLetter } from '@/views/Survey/views/Preview/components/questions/validate/validateChineseLetter';
|
||||
import { validateEmail } from '@/views/Survey/views/Preview/components/questions/validate/validateEmail';
|
||||
import { validatePhone } from '@/views/Survey/views/Preview/components/questions/validate/validatePhone';
|
||||
import { validateIDCard } from '@/views/Survey/views/Preview/components/questions/validate/validateIDCard';
|
||||
import type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/validate/validateChineseLetter';
|
||||
import { validateMinLength,validateMaxLength } from '@/views/Survey/views/Preview/components/questions/validate/validateStringLength';
|
||||
|
||||
/**
|
||||
* 生成对应的语言文字
|
||||
* 目标语言暂时写死,有需求后续更改
|
||||
*/
|
||||
const translatedText = getLanguage(['zh']) as ITranslatedText;
|
||||
|
||||
/**
|
||||
* @description 填空题验证
|
||||
* @date 2022-11-22
|
||||
* @param {IQuestion<ICompletionConfig>} question - 问卷
|
||||
* @param {IQuestionConfig} config - 相关配置
|
||||
* @param {ICompletionAnswer} answer - 答案
|
||||
*/
|
||||
function validateCompletion(
|
||||
question: IQuestion<ICompletionConfig>,
|
||||
config: ICompletionConfig,
|
||||
answer: string
|
||||
) {
|
||||
// 是否有错误
|
||||
let isError = false;
|
||||
|
||||
question.error = '';
|
||||
// 处理空白字符
|
||||
const newValue = answer.replace(/\n|\r|\r\n/g, '');
|
||||
|
||||
// 根据对应的类型进行验证
|
||||
switch (config.text_type) {
|
||||
// 字母校验
|
||||
case 3:
|
||||
question.error = validateEnglishLetters(config, newValue, translatedText);
|
||||
break;
|
||||
// 中文校验
|
||||
case 4:
|
||||
question.error = validateChineseLetter(config, newValue, translatedText);
|
||||
break;
|
||||
// 邮箱校验
|
||||
case 5:
|
||||
question.error = validateEmail(newValue, translatedText);
|
||||
break;
|
||||
// 手机号
|
||||
case 6:
|
||||
question.error = validatePhone(newValue, translatedText);
|
||||
break;
|
||||
// 身份证号
|
||||
case 7:
|
||||
question.error = validateIDCard(newValue, translatedText);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 最小输入字数校验
|
||||
const minStringValidateResult = validateMinLength(answer, isError, config, translatedText);
|
||||
// 如果内容存在, 则说明有错误,初始化赋值数据
|
||||
if (minStringValidateResult) {
|
||||
const { isError: minStringError, errorMessage: minStringErrMessage } = minStringValidateResult;
|
||||
|
||||
minStringError && (isError = minStringError);
|
||||
question.error = minStringErrMessage;
|
||||
}
|
||||
|
||||
// 最大输入字数校验
|
||||
const maxStringValidateResult = validateMaxLength(answer, isError, config, translatedText);
|
||||
// 如果内容存在, 则说明有错误,初始化赋值数据
|
||||
if (maxStringValidateResult) {
|
||||
const { isError: maxStringError, errorMessage: maxStringErrMessage } = maxStringValidateResult;
|
||||
|
||||
maxStringError && (isError = maxStringError);
|
||||
question.error = maxStringErrMessage;
|
||||
}
|
||||
|
||||
// 返回错误和对应的 question
|
||||
return {
|
||||
question,
|
||||
isError
|
||||
};
|
||||
}
|
||||
|
||||
export { validateCompletion };
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { ICompletionAnswer } from '@/views/Survey/views/Preview/components/questions/types/previewCompletion';
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
export type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 校验中文字符
|
||||
* @param {ICompletionConfig} config - 相关配置
|
||||
* @param {ICompletionAnswer} answer - 答案
|
||||
* @param {ITranslatedText} translatedText - 语言转换文本
|
||||
*/
|
||||
export function validateChineseLetter(
|
||||
config: ICompletionConfig,
|
||||
answer: string,
|
||||
translatedText = getLanguage(['zh']) as ITranslatedText
|
||||
) {
|
||||
let isError: boolean;
|
||||
|
||||
// 1. 包含标点 2. 不包含标点
|
||||
// 如果包含标点,则使用正则校验,如果不包含标点,则使用
|
||||
// /^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(newValue) || !newValue.length
|
||||
// 如果包含标点,校验规则
|
||||
// 如果不包含标点,校验规则
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~!@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test(
|
||||
answer
|
||||
) || !answer.length
|
||||
: !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
answer
|
||||
) || !answer.length;
|
||||
return isError ? translatedText.PleaseEnterChineseWords : '';
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { ICompletionAnswer } from '@/views/Survey/views/Preview/components/questions/types/previewCompletion';
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
|
||||
export type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 验证邮箱格式
|
||||
* @param answer {ICompletionAnswer} 答案
|
||||
* @param translatedText {ITranslatedText} 语言转换文本
|
||||
*/
|
||||
export function validateEmail(
|
||||
answer: string,
|
||||
translatedText = getLanguage(['zh']) as ITranslatedText
|
||||
) {
|
||||
let isError: boolean;
|
||||
isError =
|
||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
answer
|
||||
);
|
||||
return isError ? translatedText.PleaseEnterACorrectEmail : '';
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
import type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 验证字母
|
||||
* @param {ICompletionConfig} config - 相关配置
|
||||
* @param {ICompletionAnswer} answer - 答案
|
||||
* @param {ITranslatedText} translatedText - 语言转换文本
|
||||
*/
|
||||
export function validateEnglishLetters(
|
||||
config: ICompletionConfig,
|
||||
answer: string,
|
||||
translatedText = getLanguage(['zh']) as ITranslatedText
|
||||
) {
|
||||
let isError: boolean;
|
||||
|
||||
// 验证规则
|
||||
const reg = /^[a-zA-Z·~!@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/;
|
||||
// 是否包含标点
|
||||
// 1. 包含标点 2. 不包含标点
|
||||
// 如果包含标点,则使用正则校验,如果不包含标点,则使用 /^[a-zA-Z]+$/ 校验
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !reg.test(answer) || !answer.length
|
||||
: !/^[a-zA-Z]+$/.test(answer) || !answer.length;
|
||||
|
||||
return isError ? translatedText.PleaseEnterEnglishLetters : '';
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { ICompletionAnswer } from '@/views/Survey/views/Preview/components/questions/types/previewCompletion';
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
import type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 验证手机号
|
||||
* @param answer {ICompletionAnswer} 答案
|
||||
* @param translatedText {ITranslatedText} 语言转换文本
|
||||
*/
|
||||
export function validateIDCard(
|
||||
answer: string,
|
||||
translatedText = getLanguage(['zh']) as ITranslatedText
|
||||
) {
|
||||
let isError: boolean;
|
||||
|
||||
isError =
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
answer
|
||||
);
|
||||
|
||||
return isError ? translatedText.PleaseEnterACorrectID : '';
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { ICompletionAnswer } from '@/views/Survey/views/Preview/components/questions/types/previewCompletion';
|
||||
import { getLanguage } from '@/views/Survey/views/Preview/js/language';
|
||||
import type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 验证手机号
|
||||
* @param answer {ICompletionAnswer} 答案
|
||||
* @param translatedText {ITranslatedText} 语言转换文本
|
||||
*/
|
||||
export function validatePhone(
|
||||
answer: string,
|
||||
translatedText = getLanguage(['zh']) as ITranslatedText
|
||||
) {
|
||||
let isError: boolean;
|
||||
|
||||
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(answer);
|
||||
return isError ? translatedText.PleaseEnterACorrectPhone : '';
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import type { ITranslatedText } from '@/views/Survey/views/Preview/components/questions/types/translatedText';
|
||||
|
||||
/**
|
||||
* 验证最小字符串长度
|
||||
* @param answer {ICompletionAnswer} 答案
|
||||
* @param isError {boolean} 是否有错误
|
||||
* @param config {ICompletionConfig} 配置信息
|
||||
* @param translatedText {ITranslatedText} 语言转换文本
|
||||
* @return {string} 错误信息
|
||||
*/
|
||||
export function validateMinLength(
|
||||
answer: string,
|
||||
isError: boolean,
|
||||
config: ICompletionConfig,
|
||||
translatedText: ITranslatedText
|
||||
) {
|
||||
// 处理异常数据,因为不给数据的时候,默认是空字符串
|
||||
if (typeof config.min === 'string' && config.min.length === 0) return;
|
||||
|
||||
// 如果已经包含报错,不处理
|
||||
if (isError) return;
|
||||
// 如果包含相应的 text_type, 也不处理,1是整数,2是小数
|
||||
if ([1, 2].includes(config.text_type)) return;
|
||||
|
||||
if (answer.length > Number(config.min)) return;
|
||||
return {
|
||||
isError: true,
|
||||
errorMessage: translatedText.PleaseEnterMoreCharacters(config.min)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证最大字符串长度
|
||||
* @param answer {ICompletionAnswer} 答案
|
||||
* @param isError {boolean} 是否有错误
|
||||
* @param config {ICompletionConfig} 配置信息
|
||||
* @param translatedText {ITranslatedText} 语言转换文本
|
||||
* @return {string} 错误信息
|
||||
*
|
||||
*/
|
||||
export function validateMaxLength(
|
||||
answer: string,
|
||||
isError: boolean,
|
||||
config: ICompletionConfig,
|
||||
translatedText: ITranslatedText
|
||||
) {
|
||||
// 处理异常数据,因为不给数据的时候,默认是空字符串
|
||||
if (typeof config.max === 'string' && config.max.length === 0) return;
|
||||
|
||||
// 如果已经包含报错,不处理
|
||||
if (isError) return;
|
||||
// 如果包含相应的 text_type, 也不处理, 1是整数,2是小数
|
||||
if ([1, 2].includes(config.text_type)) return;
|
||||
|
||||
if (answer.length < Number(config.max)) return;
|
||||
return {
|
||||
isError: true,
|
||||
errorMessage: translatedText.PleaseEnterLessCharacters(config.max)
|
||||
};
|
||||
}
|
||||
@@ -71,7 +71,11 @@ export const language = {
|
||||
en: 'Please enter a valid ID card number.',
|
||||
zh: '请输入正确的身份证号。'
|
||||
},
|
||||
PleaseEnterMoreThanOneCharacters: {
|
||||
PleaseEnterLessCharacters: {
|
||||
en: (count) => `Please enter less than ${count} character${count > 1 ? 's' : ''}.`,
|
||||
zh: (count) => `请输入小于${count}个字符。`
|
||||
},
|
||||
PleaseEnterMoreCharacters: {
|
||||
en: (count) => `Please enter more than ${count} character${count > 1 ? 's' : ''}.`,
|
||||
zh: (count) => `请输入大于${count}个字符。`
|
||||
},
|
||||
@@ -543,7 +547,24 @@ export function setLanguageTypes(types) {
|
||||
languageTypes.push(...types);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import('@/views/Survey/views/Preview/components/questions/types/translatedText').languageArea} LanguageArea
|
||||
* @typedef {import('@/views/Survey/views/Preview/components/questions/types/translatedText').ITranslatedText} ITranslatedText I
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @alias
|
||||
* @param langArr { languageArea[] } 语言区域类型
|
||||
* @returns {ITranslatedText} 获取到的文本
|
||||
*/
|
||||
export function getLanguage(langArr = languageTypes) {
|
||||
/**
|
||||
* langArr: 语言数组 default: ['zh']
|
||||
* 1. langArr 为空时,使用 ['zh']
|
||||
* 2. langArr 是数组时,使用传入的语言
|
||||
* 3. langArr 是字符串时,使用该字符串语言
|
||||
*/
|
||||
const l = [];
|
||||
if (!langArr) {
|
||||
l.push('zh');
|
||||
|
||||
7
src/views/Survey/views/Preview/js/test/language.spec.ts
Normal file
7
src/views/Survey/views/Preview/js/test/language.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { test, spec } from "vitest";
|
||||
import { getLanguage } from "../language";
|
||||
|
||||
test("检测 language 列表", () => {
|
||||
const res = getLanguage(['zh'])
|
||||
console.log(res);
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
// vite.config.ts
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig, loadEnv } from 'vite'; // 从 vite 导入 loadEnv
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
|
||||
Reference in New Issue
Block a user