Compare commits

..

No commits in common. "8ba67edc18e70eb9e4b60af1139f1e92dcfce6da" and "e65da3ac8f37890fdf724c3daa276156ca2ade4d" have entirely different histories.

14 changed files with 31 additions and 282 deletions

View File

@ -1,10 +1,6 @@
# tool.xpcool.com 变更记录
> 倒序最新在上。格式YYYY-MM-DD | 类型 | 摘要
2026-09-01 | CHG | 全站接入图片预览TDesign ImageViewer新增共享 AppImageViewer 组件 + useImageViewer 组合式函数;接入 9 处——UploadDrop 缩略图、Base64 还原图、图片裁剪结果、图片转 ICO 预览多尺寸成组、OCR 待识别图、二维码结果、图片压缩(原直连 t-image-viewer 重构为共享组件)、代码转图片画布、占位图画布;全局样式新增 .img-previewable
2026-09-01 | CHG | 图片转 ICO 结果区增强:逐尺寸单独 ICO 下载buildIco 新增 singles 字段,复用条目数据零额外编码)+ 多尺寸一键打包 ZIP 下载jszip另修复 pnpm wrapper 中 node 版本路径22.22.2 → 22.22.2-2
2026-08-31 | CHG | 新增「图片转 ICO」工具src/utils/ico.ts纯前端自实现 PNG/BMP DIB/ICO 编码 + 中位切分量化 + 自适应滤波 + 体积上限自动降级src/views/image-to-ico/ImageToIcoView.vue尺寸组合/填充/编码方式/量化/体积限制/预览下载/历史),路由注册于 src/router/tools.tsPillow 独立解码验证通过
2026-08-26 | CFG | CHANGELOG 纳入 git 管理(.gitignore 放行 .workbuddy/memory/CHANGELOG.md中央工作空间迁移至 ../workbuddy.xpcool.com相对路径索引

View File

@ -93,11 +93,3 @@ html[theme-mode='dark'] ::-webkit-scrollbar-thumb {
font-size: 14px;
color: var(--td-text-color-secondary);
}
/* 可点击放大的图片/画布(配合 AppImageViewer 全站共用):手型光标 + hover 高亮 */
.img-previewable {
cursor: zoom-in;
}
.img-previewable:hover {
box-shadow: 0 0 0 2px var(--td-brand-color);
}

View File

@ -1,36 +0,0 @@
<template>
<!-- 全站统一的图片预览器模态展示点遮罩可关ESC 关闭缩放/下载由 TDesign 内置 -->
<t-image-viewer
:visible="visible"
:images="images"
:index="index"
:z-index="3000"
close-on-overlay
@update:visible="emit('update:visible', $event)"
@update:index="emit('update:index', $event)"
/>
</template>
<script setup lang="ts">
import type { PreviewImage } from '@/composables/useImageViewer'
/**
* AppImageViewert-image-viewer 的统一薄封装
* 用法配合 useImageViewer
* <AppImageViewer v-model:visible="visible.value" v-model:index="index.value" :images="images.value" />
* 模板中 ref 自动解包直接写 visible / index 即可
*/
defineProps<{
/** 是否显示v-model:visible */
visible: boolean
/** 预览图片组 */
images: PreviewImage[]
/** 当前下标v-model:index */
index?: number
}>()
const emit = defineEmits<{
'update:visible': [v: boolean]
'update:index': [i: number]
}>()
</script>

View File

@ -33,14 +33,7 @@
<!-- 已选文件列表图片自动生成缩略图回显 -->
<div v-else class="file-list" @click.stop>
<div v-for="(f, i) in props.files" :key="`${f.name}-${f.size}-${i}`" class="file-item">
<img
v-if="previews[i]"
:src="previews[i]"
alt=""
class="thumb thumb-clickable"
title="点击预览大图"
@click.stop="openPreview(i)"
/>
<img v-if="previews[i]" :src="previews[i]" alt="" class="thumb" />
<span v-else class="thumb thumb-icon"><FileIcon /></span>
<span class="meta">
<span class="name" :title="f.name">{{ f.name }}</span>
@ -52,9 +45,6 @@
</div>
<p v-if="props.multiple && props.files.length < props.max" class="add-more">点击可继续添加文件</p>
</div>
<!-- 点击缩略图放大预览TDesign ImageViewer -->
<AppImageViewer v-model:visible="visible" v-model:index="index" :images="images" />
</div>
</template>
@ -62,8 +52,6 @@
import { onBeforeUnmount, ref, watch } from 'vue'
import { DeleteIcon, FileIcon, UploadIcon } from 'tdesign-icons-vue-next'
import { formatBytes } from '@/utils'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { useImageViewer } from '@/composables/useImageViewer'
/**
* 通用拖拽上传组件替代 t-upload 文件模式
@ -97,14 +85,6 @@ const dragging = ref(false)
/** 图片缩略图的对象 URL与 files 一一对应,非图片为空串) */
const previews = ref<string[]>([])
/** 点击缩略图放大预览:图片组取所有非空缩略图,定位到当前点击项 */
const { visible, index, images, open } = useImageViewer()
function openPreview(i: number) {
//
const imgIdx = previews.value.slice(0, i + 1).filter(Boolean).length - 1
open(previews.value.filter(Boolean), imgIdx)
}
// dragleave
let dragDepth = 0
@ -272,14 +252,6 @@ function removeAt(i: number) {
color: var(--td-text-color-placeholder);
background: var(--td-bg-color-secondarycontainer);
}
/* 可点击预览的缩略图 */
.thumb-clickable {
cursor: zoom-in;
transition: transform 0.15s;
}
.thumb-clickable:hover {
transform: scale(1.06);
}
.meta {
flex: 1;
min-width: 0;

View File

@ -1,36 +0,0 @@
import { ref } from 'vue'
/** 可预览的图片URL 字符串或 File 对象TDesign ImageViewer 原生支持两种) */
export type PreviewImage = string | File
/**
*
*
* const { visible, index, images, open } = useImageViewer()
* <AppImageViewer v-model:visible="visible.value" ... /> ref
* open(urls, i)
*/
export function useImageViewer() {
/** 是否显示预览 */
const visible = ref(false)
/** 当前预览的下标 */
const index = ref(0)
/** 预览的图片组(支持左右切换) */
const images = ref<PreviewImage[]>([])
/** 打开预览:传入图片组与起始下标 */
function open(imgs: PreviewImage[], startIndex = 0) {
const list = imgs.filter(Boolean)
if (!list.length) return
images.value = list
index.value = Math.min(Math.max(startIndex, 0), list.length - 1)
visible.value = true
}
/** 关闭预览(一般由组件内部关闭,无需手动调用) */
function close() {
visible.value = false
}
return { visible, index, images, open, close }
}

View File

@ -55,8 +55,6 @@ export interface IcoBuildResult {
quantized: boolean
/** 各尺寸的预览图DataURL供页面回显 */
previews: Array<{ size: number; url: string }>
/** 每个尺寸单独封装的 ICO 文件(与合成包内条目数据一致,用于逐尺寸下载 / 打包 ZIP */
singles: Array<{ size: number; blob: Blob }>
}
/** ICO 内部单条目:尺寸 + 编码后的图像数据 */
@ -729,15 +727,12 @@ export async function buildIco(source: HTMLImageElement, params: IcoBuildParams)
const blob = encodeIco(encoded.images)
const previews = active.map((size) => ({ size, url: imageDataToDataUrl(rendered.get(size) as ImageData) }))
// 单尺寸 ICO 直接复用合成包里已编码的条目数据,只多包一层 6+16 字节的头部,几乎零开销
const singles = encoded.images.map((img) => ({ size: img.size, blob: encodeIco([img]) }))
return {
blob,
entries: encoded.meta,
droppedSizes: sizes.filter((s) => !active.includes(s)),
quantized: quantize,
previews,
singles,
}
}

View File

@ -61,20 +61,11 @@
<ErrorAlert :message="b64Error" @close="b64Error = ''" />
<t-card v-if="imgUrl" class="tool-section" title="转换结果">
<img
:src="imgUrl"
alt="Base64 还原的图片"
class="result-img img-previewable"
title="点击预览大图"
@click="openViewer([imgUrl])"
/>
<img :src="imgUrl" alt="Base64 还原的图片" class="result-img" />
<div class="form-actions">
<DownloadButton :filename="imgFilename" :get-blob="getImgBlob" label="下载图片" />
</div>
</t-card>
<!-- 结果图放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</t-tab-panel>
</t-tabs>
@ -95,8 +86,6 @@ import CopyButton from '@/components/common/CopyButton.vue'
import DownloadButton from '@/components/common/DownloadButton.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { dataUrlToBlob, fileToDataUrl } from '@/utils'
const tab = ref('text')
@ -108,9 +97,6 @@ const error = ref('')
const history = useHistory('base64')
/** 结果图放大预览TDesign ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
/** 编码UTF-8 安全的 base64先转字节再 btoa避免中文报错 */
function encodeText() {
error.value = ''

View File

@ -35,7 +35,7 @@
<t-card v-if="rendered" class="tool-section" title="预览">
<div class="canvas-wrap">
<canvas ref="canvasRef" class="code-canvas img-previewable" title="点击预览大图" @click="previewCanvas" />
<canvas ref="canvasRef" class="code-canvas" />
</div>
<div class="form-actions">
<t-button theme="primary" @click="downloadPng">
@ -44,9 +44,6 @@
</t-button>
</div>
</t-card>
<!-- 生成图放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</div>
</template>
@ -54,9 +51,7 @@
import { ref } from 'vue'
import { DownloadIcon } from 'tdesign-icons-vue-next'
import ErrorAlert from '@/components/common/ErrorAlert.vue'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { downloadDataUrl } from '@/composables/useDownload'
import { useImageViewer } from '@/composables/useImageViewer'
const LANGS = ['javascript', 'typescript', 'python', 'go', 'html', 'css', 'json', 'sql'].map((l) => ({
label: l,
@ -70,13 +65,6 @@ const width = ref(800)
const filename = ref('demo.js')
const error = ref('')
const rendered = ref(false)
/** 点击画布放大预览(把当前画布导出为 PNG 后交给 ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
function previewCanvas() {
const canvas = canvasRef.value
if (canvas) openViewer([canvas.toDataURL('image/png')])
}
const canvasRef = ref<HTMLCanvasElement | null>(null)
const SAMPLE = `// 示例代码

View File

@ -108,8 +108,14 @@
</div>
</t-card>
<!-- 原图 / 压缩图放大预览统一使用共享 AppImageViewer -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
<!-- 原图 / 压缩图放大预览v-if 保证每次打开都从 defaultIndex 开始 -->
<t-image-viewer
v-if="viewerVisible"
v-model="viewerVisible"
:images="viewerImages"
:default-index="viewerIndex"
:close-on-overlay="true"
/>
<HistoryPanel
:items="history.items"
@ -130,9 +136,7 @@ import JSZip from 'jszip'
import UploadDrop from '@/components/common/UploadDrop.vue'
import ErrorAlert from '@/components/common/ErrorAlert.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import { downloadBlob } from '@/composables/useDownload'
import { formatBytes, genFilename } from '@/utils'
@ -184,8 +188,10 @@ const error = ref('')
const doneCount = ref(0)
const results = ref<CompressResult[]>([])
/** 放大预览:统一走共享 useImageViewer展示「原图 + 压缩图」,从点击的那张开始 */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
/** 放大预览状态:展示「原图 + 压缩图」,从点击的那张开始 */
const viewerVisible = ref(false)
const viewerImages = ref<string[]>([])
const viewerIndex = ref(0)
/** 历史记录:保存「张数 | 压缩方式 | 格式 | 尺寸」摘要,点击可恢复压缩参数 */
const history = useHistory('image-compress')
@ -335,7 +341,9 @@ function downloadOne(r: CompressResult) {
/** 放大预览:优先展示「原图 + 压缩图」两张并可左右切换,失败时只有原图 */
function openPreview(r: CompressResult, index: number) {
openViewer(r.outUrl ? [r.sourceUrl, r.outUrl] : [r.sourceUrl], r.outUrl ? index : 0)
viewerImages.value = r.outUrl ? [r.sourceUrl, r.outUrl] : [r.sourceUrl]
viewerIndex.value = r.outUrl ? index : 0
viewerVisible.value = true
}
/** 全部结果打包为 ZIP 下载jszip纯本地生成 */

View File

@ -26,21 +26,12 @@
<ErrorAlert :message="error" @close="error = ''" />
<t-card v-if="outUrl" class="tool-section" title="裁剪结果">
<img
:src="outUrl"
alt="裁剪结果预览"
class="result-img img-previewable"
title="点击预览大图"
@click="openViewer([outUrl])"
/>
<img :src="outUrl" alt="裁剪结果预览" class="result-img" />
<div class="form-actions">
<DownloadButton :filename="outName" :get-blob="getOutBlob" label="下载裁剪图" />
</div>
</t-card>
<!-- 结果图放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
<HistoryPanel
:items="history.items"
@select="onHistorySelect"
@ -59,8 +50,6 @@ import ErrorAlert from '@/components/common/ErrorAlert.vue'
import DownloadButton from '@/components/common/DownloadButton.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { dataUrlToBlob, genFilename } from '@/utils'
/** 比例选项:'free' 表示自由裁剪 */
@ -89,9 +78,6 @@ let cropper: Cropper | null = null
const history = useHistory('image-cropper')
/** 结果图放大预览TDesign ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
const outName = computed(() => genFilename('cropped', outType.value.split('/')[1]))
function ratioValue(v: string): number {

View File

@ -92,14 +92,7 @@
<t-card v-if="result" class="tool-section" title="转换结果">
<div class="result-head">
<div class="ico-preview checker">
<img
v-if="icoUrl"
:src="icoUrl"
alt="ICO 预览"
class="img-previewable"
title="点击预览大图"
@click="openViewer(previewUrls, previewUrls.length - 1)"
/>
<img v-if="icoUrl" :src="icoUrl" alt="ICO 预览" />
</div>
<div class="result-summary">
<p class="summary-line">
@ -117,56 +110,36 @@
</p>
</div>
<div class="result-actions">
<!-- 多个尺寸时支持把每个尺寸的单独 ICO 打包成 ZIP 一键下载 -->
<t-button v-if="result.singles.length > 1" theme="primary" :loading="zipping" @click="downloadAllZip">
打包下载 ZIP
</t-button>
<t-button v-else theme="primary" @click="downloadIco">下载 ICO</t-button>
<t-button theme="primary" @click="downloadIco">下载 ICO</t-button>
</div>
</div>
<t-divider />
<p class="grid-title">各尺寸预览点击图片放大右下角可单独下载 PNG / ICO</p>
<p class="grid-title">各尺寸预览点击右下角可单独下载 PNG</p>
<div class="preview-grid">
<div v-for="(p, pi) in result.previews" :key="p.size" class="preview-cell">
<div v-for="p in result.previews" :key="p.size" class="preview-cell">
<div class="preview-box checker">
<img
:src="p.url"
:alt="`${p.size}px`"
:style="{ width: Math.min(p.size, 96) + 'px' }"
class="img-previewable"
title="点击预览大图"
@click="openViewer(previewUrls, pi)"
/>
<img :src="p.url" :alt="`${p.size}px`" :style="{ width: Math.min(p.size, 96) + 'px' }" />
</div>
<div class="preview-meta">
<div class="preview-size">{{ p.size }}×{{ p.size }}</div>
<div class="preview-btns">
<t-button size="small" variant="text" theme="primary" @click="downloadPng(p)">PNG</t-button>
<t-button size="small" variant="text" theme="primary" @click="downloadSingleIco(p.size)">ICO</t-button>
</div>
<span class="preview-size">{{ p.size }}×{{ p.size }}</span>
<t-button size="small" variant="text" theme="primary" @click="downloadPng(p)">PNG</t-button>
</div>
</div>
</div>
</t-card>
<HistoryPanel :items="history.items" @select="onHistorySelect" @remove="history.remove" @clear="history.clear" />
<!-- 预览图放大查看多尺寸成组可左右切换 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</div>
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, ref } from 'vue'
import JSZip from 'jszip'
import UploadDrop from '@/components/common/UploadDrop.vue'
import ErrorAlert from '@/components/common/ErrorAlert.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import { downloadBlob } from '@/composables/useDownload'
import { dataUrlToBlob, formatBytes } from '@/utils'
import {
@ -217,10 +190,6 @@ const sourceInfo = ref<{ name: string; width: number; height: number; size: numb
/** 历史记录:存「文件名 | 参数摘要」,点击可恢复转换参数 */
const history = useHistory('image-to-ico')
/** 预览图放大查看(各尺寸 PNG DataURL 成组) */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
const previewUrls = computed(() => result.value?.previews.map((p) => p.url) ?? [])
/** 编码方式对应的说明文案 */
const modeHint = computed(() => {
if (mode.value === 'bmp') return 'BMP 兼容性最好,但 128/256 尺寸体积会明显偏大'
@ -297,31 +266,6 @@ function downloadPng(p: { size: number; url: string }) {
downloadBlob(dataUrlToBlob(p.url), `${base}_${p.size}x${p.size}.png`)
}
/** 单独下载某个尺寸的 ICO 文件 */
function downloadSingleIco(size: number) {
const single = result.value?.singles.find((s) => s.size === size)
if (!single) return
const base = (sourceInfo.value?.name ?? 'icon').replace(/\.[^.]+$/, '')
downloadBlob(single.blob, `${base}_${size}x${size}.ico`)
}
/** 一键把所有单尺寸 ICO 打包成 ZIP 下载 */
const zipping = ref(false)
async function downloadAllZip() {
const singles = result.value?.singles
if (!singles?.length) return
zipping.value = true
try {
const base = (sourceInfo.value?.name ?? 'icon').replace(/\.[^.]+$/, '')
const zip = new JSZip()
for (const s of singles) zip.file(`${base}_${s.size}x${s.size}.ico`, s.blob)
const blob = await zip.generateAsync({ type: 'blob' })
downloadBlob(blob, `${base}_ico.zip`)
} finally {
zipping.value = false
}
}
/** 点击历史:解析摘要串恢复转换参数 */
function onHistorySelect(text: string) {
const sMatch = /sizes=([\d,]+)/.exec(text)
@ -509,17 +453,12 @@ onBeforeUnmount(() => {
}
.preview-meta {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-content: space-between;
margin-top: 6px;
}
.preview-btns {
display: flex;
align-items: center;
}
.preview-size {
font-size: 13px;
font-size: 12px;
color: var(--td-text-color-secondary);
}
@media (max-width: 767px) {

View File

@ -7,14 +7,7 @@
<t-card class="tool-section" title="上传图片">
<UploadDrop v-model:files="files" accept="image/*" tip="支持中文 / 英文识别" />
<img
v-if="previewUrl"
:src="previewUrl"
alt="待识别图片"
class="preview-img img-previewable"
title="点击预览大图"
@click="openViewer([previewUrl])"
/>
<img v-if="previewUrl" :src="previewUrl" alt="待识别图片" class="preview-img" />
<div class="form-actions">
<t-button theme="primary" :loading="busy" :disabled="!file" @click="recognize">
开始识别
@ -48,9 +41,6 @@
@remove="history.remove"
@clear="history.clear"
/>
<!-- 待识别图放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</div>
</template>
@ -66,8 +56,6 @@ import ErrorAlert from '@/components/common/ErrorAlert.vue'
import CopyButton from '@/components/common/CopyButton.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { downloadText } from '@/composables/useDownload'
import { genFilename } from '@/utils'
@ -84,9 +72,6 @@ type WorkerInstance = Awaited<ReturnType<typeof createWorker>>
const files = ref<File[]>([])
const file = ref<File | null>(null)
const previewUrl = ref('')
/** 待识别图放大预览TDesign ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
const busy = ref(false)
const progress = ref(0)
const progressLabel = ref('')

View File

@ -5,7 +5,7 @@
<t-card class="tool-section">
<div class="preview-wrap">
<canvas ref="canvasRef" class="preview-canvas img-previewable" title="点击预览大图" @click="previewCanvas" />
<canvas ref="canvasRef" class="preview-canvas" />
</div>
<div class="grid-form">
@ -54,9 +54,6 @@
@remove="history.remove"
@clear="history.clear"
/>
<!-- 占位图放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</div>
</template>
@ -65,8 +62,6 @@ import { computed, ref, watch } from 'vue'
import CopyButton from '@/components/common/CopyButton.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { downloadDataUrl } from '@/composables/useDownload'
interface PlaceholderParams {
@ -82,13 +77,6 @@ const history = useHistory('placeholder-image')
const canvasRef = ref<HTMLCanvasElement | null>(null)
const width = ref(400)
const height = ref(300)
/** 点击画布放大预览(把当前画布导出为 PNG 后交给 ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
function previewCanvas() {
const canvas = canvasRef.value
if (canvas) openViewer([canvas.toDataURL('image/png')])
}
const bgColor = ref('#667eea')
const textColor = ref('#ffffff')
const text = ref('400 x 300')

View File

@ -35,13 +35,7 @@
<t-card v-if="qrUrl" class="tool-section" title="生成结果">
<div class="qr-result">
<img
:src="qrUrl"
alt="生成的二维码"
class="qr-img img-previewable"
title="点击预览大图"
@click="openViewer([qrUrl])"
/>
<img :src="qrUrl" alt="生成的二维码" class="qr-img" />
<div class="form-actions">
<DownloadButton :filename="`qrcode_${size}.png`" :get-blob="getQrBlob" label="下载 PNG" />
<CopyButton :text="text" label="复制内容" />
@ -83,9 +77,6 @@
/>
</t-tab-panel>
</t-tabs>
<!-- 二维码放大预览 -->
<AppImageViewer v-model:visible="viewerVisible" v-model:index="viewerIndex" :images="viewerImages" />
</div>
</template>
@ -99,8 +90,6 @@ import CopyButton from '@/components/common/CopyButton.vue'
import DownloadButton from '@/components/common/DownloadButton.vue'
import HistoryPanel from '@/components/common/HistoryPanel.vue'
import { useHistory } from '@/composables/useHistory'
import { useImageViewer } from '@/composables/useImageViewer'
import AppImageViewer from '@/components/common/AppImageViewer.vue'
import { dataUrlToBlob } from '@/utils'
const tab = ref('generate')
@ -118,9 +107,6 @@ const text = ref('')
const size = ref(256)
const level = ref('M')
const dark = ref('#000000')
/** 二维码放大预览TDesign ImageViewer */
const { visible: viewerVisible, index: viewerIndex, images: viewerImages, open: openViewer } = useImageViewer()
const light = ref('#ffffff')
const genBusy = ref(false)
const genError = ref('')