import { h } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' /** * 将文本写入剪贴板。优先 Clipboard API,HTTP 等非安全上下文回退 execCommand。 */ export async function copyTextToClipboard(text: string): Promise { if (navigator.clipboard?.writeText) { try { await navigator.clipboard.writeText(text) return true } catch { // 权限拒绝或异步后丢失用户手势时,尝试 legacy 方式 } } try { const textarea = document.createElement('textarea') textarea.value = text textarea.setAttribute('readonly', '') textarea.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0' document.body.appendChild(textarea) textarea.focus() textarea.select() const ok = document.execCommand('copy') document.body.removeChild(textarea) return ok } catch { return false } } /** * 复制文本;失败时弹窗展示内容供手动复制(适用于 HTTP 测试环境等受限场景)。 */ export async function copyTextWithFallback( text: string, options?: { successMessage?: string; fallbackTitle?: string } ): Promise { const ok = await copyTextToClipboard(text) if (ok) { ElMessage.success(options?.successMessage ?? '已复制到剪贴板') return } await ElMessageBox.alert( h('textarea', { value: text, readonly: true, style: 'width:100%;min-height:88px;padding:8px 12px;border:1px solid var(--el-border-color);border-radius:8px;font-size:14px;line-height:1.5;resize:none;', onVnodeMounted(vnode) { const el = vnode.el as HTMLTextAreaElement | null el?.focus() el?.select() } }), options?.fallbackTitle ?? '请手动复制短信内容', { confirmButtonText: '关闭', customClass: 'copy-text-fallback-dialog' } ) }