feat[preview]: 适配签名组件

- 适配签名组件 PreviewSign
This commit is contained in:
Huangzhe
2025-03-21 18:04:15 +08:00
parent 03f79ee66a
commit 9b237cb443
3 changed files with 92 additions and 25 deletions

View File

@@ -1,12 +1,16 @@
<script setup lang="ts">
import { computed, onMounted, ref, useTemplateRef, toRefs } from 'vue';
const props = defineProps<{
element: any;
active: boolean;
index: number;
}>();
const { element, active } = toRefs(props);
import { computed, onMounted, ref, useTemplateRef } from 'vue';
import CommonApi from '@/api/common.js';
// question 属性
const element = defineModel<question>('element', { default: {} });
// 属性框是否激活
const active = defineModel<boolean>('active', { default: false });
// 题目索引
const index = defineModel<number>('index', { default: 0 });
// 答案
const answer = defineModel<string>('answer', { default: '' });
// 错误信息
const errorMessage = defineModel<string>('errorMessage', { default: '' });
const signatureCanvas = useTemplateRef('signatureCanvas');
@@ -54,10 +58,7 @@ const togglePen = () => {
isEraser.value = !isEraser.value;
setPenStyle();
};
const errorMessage = defineModel('errorMessage', {
type: String,
default: ''
});
onMounted(() => {
if (!signatureCanvas.value) return;
// 将 canvas 宽度和窗口的宽度保持一致
@@ -146,10 +147,24 @@ const clearCanvas = () => {
/**
* 保存画布
* @param type {'dataUrl' | 'blob'} 保存类型
* @return {string | Blob | undefined | null}
*/
const saveCanvas = () => {
const saveCanvas = (type: 'dataUrl' | 'blob'): string | Blob | undefined | null => {
let img: string | Blob | undefined | null = undefined;
if (!ctx || !signatureCanvas.value) return;
return signatureCanvas.value.toDataURL('image/png');
if (type === 'blob') {
signatureCanvas.value.toBlob(
(blob) => {
img = blob;
},
'image/png',
{ quality: 0.9 }
);
return img;
}
if (type === 'dataUrl') return signatureCanvas.value.toDataURL('image/png');
};
/**
@@ -168,10 +183,19 @@ const emit = defineEmits(['update:element']);
const emitValue = () => {
emit('update:element', element.value);
};
/**
* 上传文件
*/
async function handleUploadImg() {
const file = new File([saveCanvas('blob')!], 'sign.png', { type: 'image/png' });
const { url } = await CommonApi.cosUpload(file);
// 传递答案
answer.value = url;
}
</script>
<template>
<!-- <van-cell>-->
<van-field
:label="element.stem"
:required="element.config.is_required === 1"
@@ -211,13 +235,12 @@ const emitValue = () => {
:class="isEraser ? 'mobilefont-huabi' : 'mobilefont-rubber'"
@click="togglePen"
></span>
<span class="icon mobilefont mobilefont-shangchuan" @click="saveCanvas"></span>
<span class="icon mobilefont mobilefont-shangchuan" @click="handleUploadImg"></span>
</div>
<div v-else class="sign-tips">请在空白区域书写您的签名</div>
</div>
</template>
</van-field>
<!-- </van-cell>-->
</template>
<style lang="scss" scoped>

View File

@@ -323,14 +323,15 @@
<!-- v-model:answer="question.answer"-->
<!-- isMobile-->
<!-- />-->
<!-- &lt;!&ndash; 签名题 &ndash;&gt;-->
<!-- <q-sign-->
<!-- v-else-if="question.question_type === 22"-->
<!-- :config="question.config"-->
<!-- :question="question"-->
<!-- v-model:answer="question.answer"-->
<!-- 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)"
/>
<!-- &lt;!&ndash; 知情同意书 &ndash;&gt;-->
<!-- <q-consent-->
<!-- v-else-if="question.question_type === 23"-->
@@ -540,6 +541,7 @@ import { getQuestionIndex } from '@/utils/utils.js';
import icon from '@/assets/img/create-right-back.png';
import PreviewCheckbox from '@/views/Survey/views/Preview/components/questions/PreviewCheckbox.vue';
import PreviewRate from '@/views/Survey/views/Preview/components/questions/PreviewRate.vue';
import PreviewSign from '@/views/Survey/views/Preview/components/questions/PreviewSign.vue';
const isPreview = defineModel('isPreview', {
type: Boolean,
default: true

View File

@@ -0,0 +1,42 @@
<script setup lang="ts">
import SignQuestion from '@/views/Design/components/Questions/SignQuestion.vue';
import { ref, watch } from 'vue';
const question = defineModel<question>('question', { default: {} });
const answer = defineModel<{ value: string }>('answer', { default: undefined });
const answerValue = ref<string>('');
const answerIndex = defineModel<number>('answerIndex', { default: 0 });
// emit
const emit = defineEmits(['changeAnswer']);
// 如果 answer 不为空,需要解析答案
answer.value?.value && parseAnswer();
/**
* 监听答案,如果答案变动,重新生成答案,然后提交
*/
watch(answerValue, (newValue) => {
emit('changeAnswer', { value: newValue });
});
/**
* 解析答案
* answer 格式
* {
* value: 'url'
* }
*/
function parseAnswer() {
answerValue.value = answer.value.value;
}
</script>
<template>
<sign-question
:element="question"
:active="false"
:index="answerIndex"
v-model:answer="answerValue"
:error-message="question.error"
/>
</template>
<style scoped lang="scss"></style>