diff --git a/.gitignore b/.gitignore index 25a15a4..d329e26 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,8 @@ __pycache__/ # OS .DS_Store Thumbs.db + +# Archives +*.zip +*.tar.gz +*.7z diff --git a/admin-web/src/main.js b/admin-web/src/main.js index c3b0713..8814539 100644 --- a/admin-web/src/main.js +++ b/admin-web/src/main.js @@ -5,6 +5,23 @@ import './styles/theme.css' Vue.config.productionTip = false +Vue.config.errorHandler = (err, vm, info) => { + console.error('[vue error]', info, err) +} + +Vue.config.warnHandler = (msg, vm, trace) => { + console.warn('[vue warn]', msg, trace) +} + +window.addEventListener('unhandledrejection', (event) => { + console.warn('[unhandled rejection]', event.reason) + event.preventDefault() +}) + +window.addEventListener('error', (event) => { + console.error('[window error]', event.error || event.message) +}) + new Vue({ router, render: (h) => h(App) diff --git a/admin-web/src/utils/feedback.js b/admin-web/src/utils/feedback.js index 8dc305c..7d4d83b 100644 --- a/admin-web/src/utils/feedback.js +++ b/admin-web/src/utils/feedback.js @@ -57,3 +57,42 @@ export function previewImage(urls, current) { if (!urls || !urls.length) return ensurePreview().open({ urls, current }) } + +export async function copyText(text) { + if (text === undefined || text === null) return false + const value = String(text) + + if (navigator.clipboard && window.isSecureContext) { + try { + await navigator.clipboard.writeText(value) + return true + } catch (err) { + console.warn('[copyText] navigator.clipboard 不可用,回退到 execCommand', err) + } + } + + try { + const textarea = document.createElement('textarea') + textarea.value = value + textarea.setAttribute('readonly', '') + textarea.style.position = 'fixed' + textarea.style.top = '0' + textarea.style.left = '0' + textarea.style.width = '1px' + textarea.style.height = '1px' + textarea.style.opacity = '0' + textarea.style.pointerEvents = 'none' + document.body.appendChild(textarea) + + textarea.focus() + textarea.select() + textarea.setSelectionRange(0, value.length) + + const ok = document.execCommand('copy') + document.body.removeChild(textarea) + return !!ok + } catch (err) { + console.error('[copyText] execCommand 也失败了', err) + return false + } +} diff --git a/admin-web/src/views/Batch.vue b/admin-web/src/views/Batch.vue index 6bbe421..943da5f 100644 --- a/admin-web/src/views/Batch.vue +++ b/admin-web/src/views/Batch.vue @@ -136,7 +136,7 @@