Appearance
BizSignature 手写签名
纯 canvas + Pointer Events 签名板:鼠标 / 触摸 / 手写笔统一,按 devicePixelRatio 高清导出 PNG;跨设备重绘保持笔迹、清空 / 确认操作条、透明底或指定背景导出;协议阅读门控(滚动到底 + 阅读倒计时 + 同意勾选全满足后开放签署)。审批签署、回单确认、单据电子签名、协议签署。零第三方依赖。
基础签署
请在此区域内签名
签名 + 确认事件回显 PNG。
<script setup lang="ts">
/** 场景:审批签署——签名板 + 确认后回显签名图 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizSignature } from 'vue3-ep-biz-lib'
const signUrl = ref('')
const onConfirm = (dataUrl: string): void => {
signUrl.value = dataUrl
ElMessage.success('签名已保存')
}
</script>
<template>
<div style="max-width: 560px">
<BizSignature @confirm="onConfirm" />
<div v-if="signUrl" style="margin-top: 12px">
<div style="font-size: 13px; color: var(--el-text-color-secondary); margin-bottom: 6px">签名回显(PNG 数据):</div>
<img :src="signUrl" alt="签名" style="max-height: 80px; border: 1px dashed var(--el-border-color); padding: 4px" />
</div>
</div>
</template>
显示代码
笔迹样式
细线蓝笔(0.15cm 笔锋)
粗线红笔(马克笔)
pen-color / pen-width / height 自定义。<script setup lang="ts">
/** 场景:笔迹样式——颜色 / 线宽 / 画布高度自定义 */
import { BizSignature } from 'vue3-ep-biz-lib'
</script>
<template>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; max-width: 720px">
<BizSignature pen-color="#1E4DFF" :pen-width="1.5" :height="150" placeholder="细线蓝笔(0.15cm 笔锋)" />
<BizSignature pen-color="#B71C1C" :pen-width="4" :height="150" placeholder="粗线红笔(马克笔)" />
</div>
</template>
显示代码
合同签署流
签署人 + 手机号 + 签名校验齐全后提交。
<script setup lang="ts">
/** 场景:合同签署流——签署人 + 手机号 + 签名,校验齐全后提交 */
import { computed, ref } from 'vue'
import { ElButton, ElForm, ElFormItem, ElInput, ElMessage } from 'element-plus'
import { BizSignature } from 'vue3-ep-biz-lib'
const signer = ref('')
const mobile = ref('')
const signUrl = ref('')
const signed = ref(false)
const ready = computed(() => signer.value.trim() && mobile.value.length === 11 && signed.value)
const onConfirm = (dataUrl: string): void => {
signUrl.value = dataUrl
signed.value = true
}
const submit = (): void => {
if (!ready.value) {
ElMessage.warning('请完整填写签署信息并签名')
return
}
ElMessage.success('合同签署完成,已生成签署记录')
}
</script>
<template>
<div style="max-width: 560px">
<ElForm label-width="90px">
<ElFormItem label="签署人" required>
<ElInput v-model="signer" placeholder="与合同主体一致" />
</ElFormItem>
<ElFormItem label="手机号" required>
<ElInput v-model="mobile" maxlength="11" placeholder="用于签署短信通知" />
</ElFormItem>
<ElFormItem label="手写签名" required>
<BizSignature :height="150" confirm-text="确认签署" @confirm="onConfirm" />
</ElFormItem>
<ElFormItem>
<ElButton type="primary" :disabled="!ready" @click="submit">完成签署</ElButton>
</ElFormItem>
</ElForm>
</div>
</template>
显示代码
白底导出
请在此区域内签名
background-color 指定导出背景(默认透明底适合叠加合同底图)。<script setup lang="ts">
/** 场景:导出背景——白底导出便于打印 / 归档(默认透明底适合叠加到合同底图) */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
const whiteUrl = ref('')
</script>
<template>
<div style="max-width: 560px">
<BizSignature
background-color="#FFFFFF"
:height="160"
@confirm="(url: string) => (whiteUrl = url)"
/>
<div v-if="whiteUrl" style="margin-top: 10px; background: var(--el-fill-color); padding: 8px; display: inline-block">
<img :src="whiteUrl" alt="白底签名" style="max-height: 70px" />
<span style="font-size: 12px; color: var(--el-text-color-secondary); margin-left: 8px">白底导出(归档 / 打印)</span>
</div>
</div>
</template>
显示代码
只读回显
请签名
disabled 禁止再绘制,查看已签署结果。<script setup lang="ts">
/** 场景:只读回显——审批详情页查看签署结果(disabled 禁止再绘制) */
import { ref } from 'vue'
import { ElButton } from 'element-plus'
import { BizSignature } from 'vue3-ep-biz-lib'
const signUrl = ref('')
const onConfirm = (dataUrl: string): void => {
signUrl.value = dataUrl
}
</script>
<template>
<div style="max-width: 560px">
<BizSignature
:height="150"
:disabled="!!signUrl"
:show-toolbar="!signUrl"
:placeholder="signUrl ? '签署已完成(只读)' : '请签名'"
@confirm="onConfirm"
/>
<div v-if="signUrl" style="margin-top: 10px; display: flex; gap: 10px; align-items: center">
<img :src="signUrl" alt="已签署" style="max-height: 60px; border: 1px dashed var(--el-border-color); padding: 4px" />
<ElButton size="small" text type="primary" @click="signUrl = ''">重新签署</ElButton>
</div>
</div>
</template>
显示代码
外部控制(expose)
请在此区域内签名
isEmpty:否
clear / isEmpty / toDataURL 组合自定义操作条。<script setup lang="ts">
/** 场景:外部控制——expose clear / isEmpty / toDataURL 组合自定义操作条 */
import { ref } from 'vue'
import { ElButton, ElMessage, ElTag } from 'element-plus'
import { BizSignature } from 'vue3-ep-biz-lib'
import type { BizSignatureInstance } from 'vue3-ep-biz-lib'
const sigRef = ref<BizSignatureInstance>()
const lastUrl = ref('')
const exportUrl = (): void => {
if (sigRef.value?.isEmpty()) {
ElMessage.warning('尚未签名')
return
}
lastUrl.value = sigRef.value?.toDataURL() ?? ''
ElMessage.success('已导出签名数据')
}
</script>
<template>
<div style="max-width: 560px">
<BizSignature ref="sigRef" :height="160" :show-toolbar="false" @change="(empty: boolean) => !empty && (lastUrl = '')" />
<div style="margin-top: 10px; display: flex; gap: 8px; align-items: center">
<ElButton size="small" @click="sigRef?.clear()">clear()</ElButton>
<ElButton size="small" type="primary" @click="exportUrl">toDataURL()</ElButton>
<ElTag size="small" type="info">isEmpty:{{ sigRef?.isEmpty() ? '是' : '否' }}</ElTag>
<img v-if="lastUrl" :src="lastUrl" alt="导出" style="max-height: 44px; margin-left: 8px" />
</div>
</div>
</template>
显示代码
协议阅读门控
员工竞业协议
一、竞业限制范围
乙方在离职后 24 个月内,不得入职与甲方存在竞争关系的企业,不得以任何形式为竞争方提供服务。
二、补偿标准
甲方按乙方离职前十二个月平均工资的 30%,按月支付竞业补偿金。
三、违约责任
乙方违反本协议约定的,应一次性向甲方支付相当于全部补偿金三倍的违约金,并继续履行竞业限制义务。
四、其他
本协议自双方签署之日起生效,一式两份。如对条款有疑问,请在签署前咨询人力资源部。(正文持续滚动到底后可勾选同意)
请继续滚动阅读至协议底部
请在此区域内签名
(未签署)
agreement 传入即启用:协议区滚动到底解锁勾选,勾选后才可「确认签名」;confirm 事件第二参数附阅读状态(标题 / 是否读完 / 阅读秒数 / 是否同意)。<script setup lang="ts">
/** 协议阅读门控:滚动到底解锁勾选,勾选后才可确认签署;confirm 事件附协议阅读状态 */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
import type { BizSignatureAgreementState } from 'vue3-ep-biz-lib'
const stateText = ref('(未签署)')
const onConfirm = (dataUrl: string, agreement?: BizSignatureAgreementState): void => {
stateText.value =
agreement === undefined
? '未启用协议门控'
: `已同意「${agreement.title}」· 阅读 ${agreement.seconds}s · dataUrl 长度 ${dataUrl.length}`
}
</script>
<template>
<div style="max-width: 520px">
<BizSignature
:agreement="{
title: '员工竞业协议',
content: `一、竞业限制范围\n乙方在离职后 24 个月内,不得入职与甲方存在竞争关系的企业,不得以任何形式为竞争方提供服务。\n\n二、补偿标准\n甲方按乙方离职前十二个月平均工资的 30%,按月支付竞业补偿金。\n\n三、违约责任\n乙方违反本协议约定的,应一次性向甲方支付相当于全部补偿金三倍的违约金,并继续履行竞业限制义务。\n\n四、其他\n本协议自双方签署之日起生效,一式两份。如对条款有疑问,请在签署前咨询人力资源部。(正文持续滚动到底后可勾选同意)`,
}"
@confirm="onConfirm"
/>
<p style="margin: 12px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
{{ stateText }}
</p>
</div>
</template>
显示代码
阅读倒计时
服务开通协议(倒计时签署)
第 1 章 服务条款。双方确认本协议项下权利义务,任何修订需以书面形式作出并经双方签署。(示例条款,滚动到底并等待倒计时结束)
第 2 章 服务条款。双方确认本协议项下权利义务,任何修订需以书面形式作出并经双方签署。(示例条款,滚动到底并等待倒计时结束)
第 3 章 服务条款。双方确认本协议项下权利义务,任何修订需以书面形式作出并经双方签署。(示例条款,滚动到底并等待倒计时结束)
10s 后可签署
请在此区域内签名
阅读门槛 10 秒:滚动到底解锁勾选,倒计时结束后「确认签名」可用
agreement.duration 阅读秒数门槛:倒计时结束前确认按钮禁用(与滚动到底叠加生效)。<script setup lang="ts">
/** 阅读倒计时:duration 秒门槛 + 滚动到底双约束,倒计时结束前确认按钮禁用 */
import { BizSignature } from 'vue3-ep-biz-lib'
const content = Array.from({ length: 3 }, (_, i) => `第 ${i + 1} 章 服务条款。双方确认本协议项下权利义务,任何修订需以书面形式作出并经双方签署。(示例条款,滚动到底并等待倒计时结束)`).join('\n\n')
</script>
<template>
<div style="max-width: 520px">
<BizSignature
:agreement="{
title: '服务开通协议(倒计时签署)',
content,
duration: 10,
maxHeight: 160,
}"
/>
<p style="margin: 12px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
阅读门槛 10 秒:滚动到底解锁勾选,倒计时结束后「确认签名」可用
</p>
</div>
</template>
显示代码
自定义协议排版
数据授权协议
数据授权范围(v3.2)
为提供风险监测服务,需授权读取以下数据:
- 企业基础工商信息与年报
- 设备运行指标(脱敏后)
- 授权有效期 12 个月,可随时在「设置-授权管理」中撤回
版本 v3.2 · 生效日期 2026-10-01 · 历史版本可在协议档案中查阅
请继续滚动阅读至协议底部
请在此区域内签名
插槽内容同样参与滚动到底判定;read-complete 事件:未读完
agreement 插槽整体替换协议正文(富文本 / 版本号 / 加粗条款),滚动到底判定不受影响。<script setup lang="ts">
/** 自定义协议排版:agreement 插槽整体替换正文(富文本 / 版本号 / 加粗条款),滚动判定不受影响 */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
const readDone = ref(false)
</script>
<template>
<div style="max-width: 520px">
<BizSignature
pen-color="#c45656"
:agreement="{ title: '数据授权协议', requireScroll: true }"
@read-complete="readDone = true"
>
<template #agreement>
<h4 style="margin: 0 0 8px; font-size: 14px">数据授权范围(v3.2)</h4>
<p style="margin: 0 0 8px">为提供风险监测服务,需授权读取以下数据:</p>
<ul style="margin: 0 0 8px; padding-left: 18px; line-height: 22px">
<li>企业基础工商信息与年报</li>
<li>设备运行指标(脱敏后)</li>
<li><strong>授权有效期 12 个月</strong>,可随时在「设置-授权管理」中撤回</li>
</ul>
<p style="margin: 0; color: var(--el-text-color-secondary); font-size: 12px">
版本 v3.2 · 生效日期 2026-10-01 · 历史版本可在协议档案中查阅
</p>
</template>
</BizSignature>
<p style="margin: 12px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
插槽内容同样参与滚动到底判定;read-complete 事件:{{ readDone ? '已读完' : '未读完' }}
</p>
</div>
</template>
显示代码
已签署协议回显
员工竞业协议(已签署 · v2.1)
一、竞业限制范围:离职后 24 个月内不得入职竞争企业。
二、补偿标准:按离职前十二个月平均工资 30% 按月支付。
(只读回显:签署于 2026-09-12,协议快照随签名一并归档)
请在此区域内签名
disabled + agreement(require-scroll: false)只读展示协议与当时同意状态,审查归档场景。<script setup lang="ts">
/** 已签署回显:disabled 只读 + 协议版本说明,审查归档场景(勾选框只读展示当时同意状态) */
import { BizSignature } from 'vue3-ep-biz-lib'
import { ElMessage } from 'element-plus'
const onPreview = (): void => {
ElMessage.info('(演示)业务侧打开协议档案:竞业协议 v2.1 签署快照')
}
</script>
<template>
<div style="max-width: 520px">
<BizSignature
disabled
:agreement="{
title: '员工竞业协议(已签署 · v2.1)',
content: '一、竞业限制范围:离职后 24 个月内不得入职竞争企业。\n二、补偿标准:按离职前十二个月平均工资 30% 按月支付。\n\n(只读回显:签署于 2026-09-12,协议快照随签名一并归档)',
requireScroll: false,
agreeText: '本人已于 2026-09-12 阅读并同意上述协议(v2.1)',
}"
/>
<el-button style="margin-top: 8px" text type="primary" @click="onPreview">查看签署快照</el-button>
</div>
</template>
显示代码
印章盖印基础
请在此区域内签名
×
拖动印章调整落章位置、滚轮缩放大小、悬停右上角 × 移除;签名后点「确认签名」导出笔迹 + 印章合成图。
seals 传入即启用印章层:拖拽定位 / 滚轮缩放 / 悬停删除(触屏设备删除按钮常显),确认导出笔迹 + 印章合成 PNG。<script setup lang="ts">
/** 印章盖印基础:单枚公章拖拽定位 + 滚轮缩放,签名后确认合成导出 */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
const result = ref('')
/** 生成内联 SVG 公章(真实项目替换为印章管理系统下发的透明底 PNG) */
const makeSeal = (name: string, sub: string): string => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="100" cy="100" r="94" fill="none" stroke="#c0392b" stroke-width="6"/>
<circle cx="100" cy="100" r="74" fill="none" stroke="#c0392b" stroke-width="2"/>
<path d="M100 60 l7 14.5 16 2.4-11.5 11.2 2.7 15.9-14.2-7.4-14.2 7.4 2.7-15.9L77 76.9l16-2.4z" fill="#c0392b"/>
<path id="arc" d="M 28 100 A 72 72 0 0 1 172 100" fill="none"/>
<text font-family="serif" font-size="17" fill="#c0392b" letter-spacing="2">
<textPath href="#arc" startOffset="50%" text-anchor="middle">${name}</textPath>
</text>
<text x="100" y="152" text-anchor="middle" font-family="serif" font-size="15" fill="#c0392b">${sub}</text>
</svg>`
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
}
</script>
<template>
<div style="max-width: 520px">
<BizSignature
background-color="#fff"
:seals="[{ image: makeSeal('某某科技有限公司', '合同专用章'), width: 120 }]"
@confirm="(url) => (result = url)"
/>
<p style="margin: 10px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
拖动印章调整落章位置、滚轮缩放大小、悬停右上角 × 移除;签名后点「确认签名」导出笔迹 + 印章合成图。
</p>
<img v-if="result" :src="result" alt="合成结果" style="margin-top: 10px; width: 240px; border: 1px solid var(--el-border-color-lighter); border-radius: 6px" />
</div>
</template>
显示代码
文档底图盖章
document-image 作为最底层图层(cover 铺满签署区);确认导出 = 底图 + 笔迹 + 印章三层合成。
document-image 作为最底层图层(cover 铺满),导出 = 底图 + 笔迹 + 印章三层合成,合同页签署栏场景。<script setup lang="ts">
/** 文档底图盖章:合同页扫描作为底图,签名与印章叠加其上,导出三层合成 */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
const result = ref('')
const makeSeal = (name: string, sub: string): string => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="100" cy="100" r="94" fill="none" stroke="#c0392b" stroke-width="6"/>
<circle cx="100" cy="100" r="74" fill="none" stroke="#c0392b" stroke-width="2"/>
<path d="M100 60 l7 14.5 16 2.4-11.5 11.2 2.7 15.9-14.2-7.4-14.2 7.4 2.7-15.9L77 76.9l16-2.4z" fill="#c0392b"/>
<path id="arc" d="M 28 100 A 72 72 0 0 1 172 100" fill="none"/>
<text font-family="serif" font-size="17" fill="#c0392b" letter-spacing="2">
<textPath href="#arc" startOffset="50%" text-anchor="middle">${name}</textPath>
</text>
<text x="100" y="152" text-anchor="middle" font-family="serif" font-size="15" fill="#c0392b">${sub}</text>
</svg>`
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
}
/** 生成 A4 合同页底图(真实项目为扫描件 / PDF 渲染图) */
const makeDocument = (): string => {
const lines = Array.from({ length: 9 }, (_, i) => `<rect x="60" y="${210 + i * 34}" width="${i % 3 === 2 ? 340 : 480}" height="10" rx="5" fill="#d5d8dd"/>`).join('')
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="600" height="560">
<rect width="600" height="560" fill="#ffffff"/>
<text x="300" y="72" text-anchor="middle" font-family="serif" font-size="26" fill="#303133">技术服务合同(节选页)</text>
<text x="300" y="104" text-anchor="middle" font-family="serif" font-size="14" fill="#909399">合同编号:CT20261023-215</text>
${lines}
<text x="60" y="544" font-family="serif" font-size="14" fill="#909399">(签署栏 · 甲方签署人签名并加盖公章后生效)</text>
</svg>`
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
}
</script>
<template>
<div style="max-width: 560px">
<BizSignature
:height="260"
background-color="#fff"
placeholder="请在签署栏签名"
:document-image="makeDocument()"
:seals="[{ image: makeSeal('某某科技有限公司', '合同专用章'), width: 132, x: 0.66, y: 0.5 }]"
@confirm="(url) => (result = url)"
/>
<p style="margin: 10px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
document-image 作为最底层图层(cover 铺满签署区);确认导出 = 底图 + 笔迹 + 印章三层合成。
</p>
<img v-if="result" :src="result" alt="合成结果" style="margin-top: 10px; width: 300px; border: 1px solid var(--el-border-color-lighter); border-radius: 6px" />
</div>
</template>
显示代码
多枚印章并存
请在此区域内签名
×
×
两枚印章独立操作(拖拽 / 滚轮缩放 / 悬停删除);仅盖章不签名也可确认(签署物 = 笔迹或印章至少其一)。
公章 + 财务章独立拖拽 / 缩放 / 删除;仅盖章(无笔迹)也可确认——签署物 = 笔迹或印章至少其一。
<script setup lang="ts">
/** 多枚印章:公章 + 财务章并存(各自独立拖拽 / 缩放 / 删除) */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
const result = ref('')
const makeSeal = (name: string, sub: string, color: string): string => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="100" cy="100" r="94" fill="none" stroke="${color}" stroke-width="6"/>
<circle cx="100" cy="100" r="74" fill="none" stroke="${color}" stroke-width="2"/>
<path d="M100 60 l7 14.5 16 2.4-11.5 11.2 2.7 15.9-14.2-7.4-14.2 7.4 2.7-15.9L77 76.9l16-2.4z" fill="${color}"/>
<path id="arc" d="M 28 100 A 72 72 0 0 1 172 100" fill="none"/>
<text font-family="serif" font-size="17" fill="${color}" letter-spacing="2">
<textPath href="#arc" startOffset="50%" text-anchor="middle">${name}</textPath>
</text>
<text x="100" y="152" text-anchor="middle" font-family="serif" font-size="15" fill="${color}">${sub}</text>
</svg>`
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
}
</script>
<template>
<div style="max-width: 520px">
<BizSignature
background-color="#fff"
:seals="[
{ id: 'contract', image: makeSeal('某某科技有限公司', '合同专用章', '#c0392b'), width: 126, x: 0.3, y: 0.4 },
{ id: 'finance', image: makeSeal('某某科技有限公司', '财务专用章', '#b03a2e'), width: 104, x: 0.68, y: 0.55, opacity: 0.85 },
]"
@confirm="(url) => (result = url)"
/>
<p style="margin: 10px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
两枚印章独立操作(拖拽 / 滚轮缩放 / 悬停删除);仅盖章不签名也可确认(签署物 = 笔迹或印章至少其一)。
</p>
<img v-if="result" :src="result" alt="合成结果" style="margin-top: 10px; width: 240px; border: 1px solid var(--el-border-color-lighter); border-radius: 6px" />
</div>
</template>
显示代码
印章样式定制
请在此区域内签名
×
width / opacity / x / y 定制初始样式与位置(比例口径,挂载后按容器尺寸换算);拖拽缩放后可经 getSeals 读取最终摆放随单据存档。
width / opacity / x / y 定制初始样式与位置;getSeals() 读取拖拽缩放后的最终摆放随单据存档。<script setup lang="ts">
/** 印章样式定制:width / opacity / 初始坐标(x·y 比例),getSeals 读取摆放状态 */
import { ref } from 'vue'
import { BizSignature } from 'vue3-ep-biz-lib'
import type { BizSignatureInstance } from 'vue3-ep-biz-lib'
import { ElMessage } from 'element-plus'
const signRef = ref<BizSignatureInstance>()
const sealSvg = (() => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="100" cy="100" r="94" fill="none" stroke="#2c6e49" stroke-width="6"/>
<circle cx="100" cy="100" r="74" fill="none" stroke="#2c6e49" stroke-width="2"/>
<path d="M100 60 l7 14.5 16 2.4-11.5 11.2 2.7 15.9-14.2-7.4-14.2 7.4 2.7-15.9L77 76.9l16-2.4z" fill="#2c6e49"/>
<path id="arc" d="M 28 100 A 72 72 0 0 1 172 100" fill="none"/>
<text font-family="serif" font-size="17" fill="#2c6e49" letter-spacing="2">
<textPath href="#arc" startOffset="50%" text-anchor="middle">某某科技有限公司</textPath>
</text>
<text x="100" y="152" text-anchor="middle" font-family="serif" font-size="15" fill="#2c6e49">审核专用章</text>
</svg>`
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
})()
const readSeals = (): void => {
const seals = signRef.value?.getSeals() ?? []
ElMessage.info(`当前 ${seals.length} 枚印章,首枚位置 (${Math.round(seals[0]?.left ?? 0)}, ${Math.round(seals[0]?.top ?? 0)}) 宽 ${Math.round(seals[0]?.width ?? 0)}px`)
}
</script>
<template>
<div style="max-width: 520px">
<BizSignature
ref="signRef"
background-color="#fff"
pen-color="#2c6e49"
:height="180"
:seals="[{ image: sealSvg, width: 96, opacity: 0.75, x: 0.08, y: 0.12 }]"
/>
<div style="margin-top: 10px; display: flex; gap: 8px">
<el-button size="small" @click="readSeals">getSeals() 读取摆放状态</el-button>
</div>
<p style="margin: 10px 0 0; font-size: 13px; color: var(--el-text-color-secondary)">
width / opacity / x / y 定制初始样式与位置(比例口径,挂载后按容器尺寸换算);拖拽缩放后可经 getSeals 读取最终摆放随单据存档。
</p>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| height | number | 200 | 画布高度(px,宽度自适应) |
| pen-color | string | '#1f2d3d' | 画笔颜色 |
| pen-width | number | 2.5 | 画笔线宽 |
| background-color | string | 'transparent' | 导出背景色 |
| show-toolbar | boolean | true | 内置操作条(清空 / 确认) |
| confirm-text | string | '确认签名' | 确认按钮文案 |
| placeholder | string | '请在此区域内签名' | 占位提示 |
| disabled | boolean | false | 只读 |
| agreement | BizSignatureAgreement | — | 协议阅读门控(传入即启用):{ title, content, maxHeight=240, requireScroll=true, duration=0, agreeText };全满足后开放签署,confirm 附协议状态 |
| seals | BizSignatureSealItem[] | — | 印章盖印层(传入即启用):{ id?, image, width=120, opacity=0.9, x=0.72, y=0.55 },可拖拽 / 滚轮缩放 / 悬停删除(触屏常显),确认时与笔迹合成导出 |
| document-image | string | '' | 底图(合同页扫描 / A4 模板):最底层图层,签名与印章叠加其上 |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| confirm | (dataUrl: string, agreement?: BizSignatureAgreementState) | 点击确认签名(PNG dataURL);agreement 门控启用时第二参数附 { title, readCompleted, seconds, accepted } |
| change | (empty: boolean) | 签署状态变化 |
| agreement-accept | (accepted: boolean) | 协议同意勾选状态变化 |
| read-complete | — | 首次滚动阅读到底(正文不足一屏时挂载即触发) |
Slots
| 插槽名 | 说明 |
|---|---|
| toolbar-extra | 操作条右侧扩展位 |
| agreement | 协议正文整体替换(保留滚动到底判定),配合 agreement 配置使用 |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
| clear | () => void | 清空重签(印章层保留) |
| toDataURL | () => string | 导出 PNG dataURL(仅笔迹 + 背景) |
| isEmpty | () => boolean | 是否未签署 |
| getAgreementState | () => BizSignatureAgreementState | undefined | 协议阅读状态(未启用 agreement 时为 undefined) |
| resetAgreement | () => void | 重置协议阅读状态(勾选 / 阅读进度 / 倒计时) |
| exportImage | () => Promise<string> | 全图层合成导出(底图 + 笔迹 + 印章);未启用印章 / 底图时等价 toDataURL |
| getSeals | () => SealState[] | 当前印章摆放状态(拖拽后位置 / 缩放 / 不透明度) |