+
props.useWatermark, (newVal) => {
+ console.log('useWatermark prop changed to:', newVal)
+ }, { immediate: true })
+
+ // 调试:打印所有 props
+ console.log('All props:', props)
+ console.log('useWatermark value:', props.useWatermark)
+
const editorRef = shallowRef()
const valueHtml = ref('')
const toolbarConfig = {}
- const editorConfig = {
- placeholder: '请输入内容...',
- MENU_CONF: {}
- }
- editorConfig.MENU_CONF['uploadImage'] = {
- fieldName: 'file',
- server: basePath + '/fileUploadAndDownload/upload?noSave=1',
- headers: {
- 'x-token': userStore.token,
- },
- customInsert(res, insertFn) {
- if (res.code === 0) {
- const urlPath = getUrl(res.data.file.url)
- insertFn(urlPath, res.data.file.name)
+
+ // 创建自定义上传函数,直接检查当前 props 值
+ const createCustomUpload = () => {
+ return async (file, insertFn) => {
+ // 直接获取当前的 props.useWatermark 值
+ const shouldUseWatermark = props.useWatermark || forceWatermark
+ console.log('customUpload called, useWatermark:', shouldUseWatermark)
+ console.log('props.useWatermark:', props.useWatermark)
+ console.log('forceWatermark:', forceWatermark)
+
+ // 未开启水印则直接上传原图
+ if (!shouldUseWatermark) {
+ console.log('直接上传原图,不加水印')
+ const formData = new FormData()
+ formData.append('file', file)
+ const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', { method: 'POST', body: formData })
+ const res = await resp.json()
+ if (res.code === 0) {
+ const urlPath = getUrl(res.data.file.url)
+ insertFn(urlPath, res.data.file.name)
+ } else {
+ ElMessage.error(res.msg || '上传失败')
+ }
return
}
- ElMessage.error(res.msg)
+ try {
+ console.log('开始添加水印')
+ const watermarkedBlob = await addBottomWatermark(file, {
+ stripRatio: 0.18, // 水印条高度占原图高度比例
+ background: 'rgba(255,255,255,0.96)',
+ text: '老陈机器人',
+ textColor: '#333',
+ fontFamily: 'PingFang SC, Microsoft YaHei, Arial',
+ logo: botLogo
+ })
+ console.log('水印处理完成')
+
+ const newFile = new File([watermarkedBlob], file.name, { type: watermarkedBlob.type || file.type })
+ const formData = new FormData()
+ formData.append('file', newFile)
+ const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', {
+ method: 'POST',
+ body: formData
+ })
+ const res = await resp.json()
+ if (res.code === 0) {
+ const urlPath = getUrl(res.data.file.url)
+ insertFn(urlPath, res.data.file.name)
+ } else {
+ ElMessage.error(res.msg || '上传失败')
+ }
+ } catch {
+ ElMessage.error('处理水印失败')
+ // 降级:直接走原图上传
+ const formData = new FormData()
+ formData.append('file', file)
+ const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', { method: 'POST', body: formData })
+ const res = await resp.json()
+ if (res.code === 0) {
+ const urlPath = getUrl(res.data.file.url)
+ insertFn(urlPath, res.data.file.name)
+ } else {
+ ElMessage.error(res.msg || '上传失败')
+ }
+ }
}
}
+ // 将 editorConfig 改为计算属性,使其响应 props 变化
+ const editorConfig = computed(() => ({
+ placeholder: '请输入内容...',
+ MENU_CONF: {
+ uploadImage: {
+ server: basePath + '/fileUploadAndDownload/upload?noSave=1',
+ fieldName: 'file',
+ maxFileSize: 1024 * 1024 * 10, // 限制图片大小为10MB
+ maxNumberOfFiles: 1,
+ customUpload: createCustomUpload(),
+ customInsert(res, insertFn) {
+ if (res.code === 0) {
+ const urlPath = getUrl(res.data.file.url)
+ insertFn(urlPath, res.data.file.name)
+ return
+ }
+ ElMessage.error(res.msg)
+ }
+ },
+ uploadVideo: {
+ server: basePath + '/fileUploadAndDownload/upload?noSave=1',
+ fieldName: 'file',
+ maxFileSize: 1024 * 1024 * 100, // 限制视频大小为100MB
+ maxNumberOfFiles: 1,
+ customInsert(res, insertFn) {
+ if (res.code === 0) {
+ const urlPath = getUrl(res.data.file.url)
+ insertFn(urlPath, res.data.file.name)
+ return
+ }
+ ElMessage.error(res.msg)
+ }
+ }
+ }
+ }))
+
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
@@ -78,6 +177,33 @@
const handleCreated = (editor) => {
editorRef.value = editor
valueHtml.value = props.modelValue
+
+ // 动态更新上传配置
+ if (editor && editor.getConfig) {
+ const config = editor.getConfig()
+ if (config.MENU_CONF && config.MENU_CONF.uploadImage) {
+ config.MENU_CONF.uploadImage.customUpload = createCustomUpload()
+ console.log('动态更新上传配置,useWatermark:', props.useWatermark)
+ }
+ }
+
+ // 修复点击区域问题
+ setTimeout(() => {
+ const editorContainer = editor.getEditableContainer()
+ if (editorContainer) {
+ // 确保整个编辑器区域都可以点击
+ editorContainer.style.cursor = 'text'
+ editorContainer.style.minHeight = '300px'
+
+ // 添加点击事件监听器
+ editorContainer.addEventListener('click', (e) => {
+ if (e.target === editorContainer) {
+ // 如果点击的是容器本身,聚焦到编辑器
+ editor.focus()
+ }
+ })
+ }
+ }, 100)
}
watch(
@@ -86,8 +212,135 @@
valueHtml.value = props.modelValue
}
)
+
+ // 监听 useWatermark 变化,动态更新编辑器配置
+ watch(
+ () => props.useWatermark,
+ (newVal) => {
+ console.log('useWatermark changed to:', newVal)
+ if (editorRef.value && editorRef.value.getConfig) {
+ const config = editorRef.value.getConfig()
+ if (config.MENU_CONF && config.MENU_CONF.uploadImage) {
+ config.MENU_CONF.uploadImage.customUpload = createCustomUpload()
+ console.log('动态更新上传配置,useWatermark:', newVal)
+ }
+ }
+ }
+ )
+
+ async function addBottomWatermark(file, options) {
+ const { stripRatio = 0.18, background = 'rgba(255,255,255,0.96)', text = '', textColor = '#333', fontFamily = 'Arial', logo } = options || {}
+
+ const img = await fileToImage(file)
+ const width = img.naturalWidth || img.width
+ const height = img.naturalHeight || img.height
+ const stripHeight = Math.max(60, Math.floor(height * stripRatio))
+
+ const canvas = document.createElement('canvas')
+ canvas.width = width
+ canvas.height = height + stripHeight
+ const ctx = canvas.getContext('2d')
+
+ // 原图
+ ctx.drawImage(img, 0, 0, width, height)
+
+ // 底部水印条背景
+ ctx.fillStyle = background
+ ctx.fillRect(0, height, width, stripHeight)
+
+ // 左侧 Logo(可选)
+ let logoSize = Math.floor(stripHeight * 0.6)
+ let logoPadding = Math.floor(stripHeight * 0.2)
+ if (logo) {
+ try {
+ const logoImg = await srcToImage(logo)
+ const ratio = logoImg.width / logoImg.height
+ const drawW = logoSize
+ const drawH = Math.floor(drawW / ratio)
+ const y = height + Math.floor((stripHeight - drawH) / 2)
+ ctx.drawImage(logoImg, logoPadding, y, drawW, drawH)
+ } catch { void 0 }
+ }
+
+ // 右侧文字
+ ctx.fillStyle = textColor
+ const fontSize = Math.floor(stripHeight * 0.38)
+ ctx.font = `${fontSize}px ${fontFamily}`
+ ctx.textBaseline = 'middle'
+ ctx.textAlign = 'right'
+ const textPadding = Math.floor(stripHeight * 0.25)
+ ctx.fillText(text, width - textPadding, height + Math.floor(stripHeight / 2))
+
+ const blob = await canvasToBlob(canvas, file.type || 'image/png')
+ return blob
+ }
+
+ function fileToImage(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onload = () => {
+ const img = new Image()
+ img.onload = () => resolve(img)
+ img.onerror = reject
+ img.src = reader.result
+ }
+ reader.onerror = reject
+ reader.readAsDataURL(file)
+ })
+ }
+
+ function srcToImage(src) {
+ return new Promise((resolve, reject) => {
+ const img = new Image()
+ img.crossOrigin = 'anonymous'
+ img.onload = () => resolve(img)
+ img.onerror = reject
+ img.src = src
+ })
+ }
+
+ function canvasToBlob(canvas, mime) {
+ return new Promise((resolve) => {
+ if (canvas.toBlob) {
+ canvas.toBlob((blob) => resolve(blob), mime, 0.92)
+ } else {
+ // 兼容处理
+ const dataURL = canvas.toDataURL(mime)
+ const arr = dataURL.split(',')
+ const bstr = atob(arr[1])
+ let n = bstr.length
+ const u8arr = new Uint8Array(n)
+ while (n--) u8arr[n] = bstr.charCodeAt(n)
+ resolve(new Blob([u8arr], { type: mime }))
+ }
+ })
+ }
+:deep(.w-e-scroll) {
+ min-height: 300px !important;
+ cursor: text !important;
+}
+
+:deep(.w-e-text-placeholder) {
+ pointer-events: none;
+}
+
+// 确保整个编辑器区域都可以点击
+:deep(.w-e-text-container .w-e-scroll) {
+ cursor: text !important;
+}
+
+// 修复编辑器内容区域的点击问题
+:deep(.w-e-text-container .w-e-scroll .w-e-text) {
+ min-height: 300px !important;
+ cursor: text !important;
+}
+
\ No newline at end of file
diff --git a/src/pathInfo.json b/src/pathInfo.json
index 00a1e2f..a99ac93 100644
--- a/src/pathInfo.json
+++ b/src/pathInfo.json
@@ -12,7 +12,6 @@
"/src/view/dashboard/components/charts.vue": "Charts",
"/src/view/dashboard/components/notice.vue": "Notice",
"/src/view/dashboard/components/pluginTable.vue": "PluginTable",
- "/src/view/dashboard/components/quickLinks.vue": "QuickLinks",
"/src/view/dashboard/components/table.vue": "Table",
"/src/view/dashboard/components/wiki.vue": "Wiki",
"/src/view/dashboard/index.vue": "Dashboard",
diff --git a/src/view/bot/bot/bot.vue b/src/view/bot/bot/bot.vue
index 87e758d..13bc921 100644
--- a/src/view/bot/bot/bot.vue
+++ b/src/view/bot/bot/bot.vue
@@ -56,6 +56,7 @@
[富文本内容]
+
查看
diff --git a/src/view/bot/bot/botForm.vue b/src/view/bot/bot/botForm.vue
index b4773c9..87dad2b 100644
--- a/src/view/bot/bot/botForm.vue
+++ b/src/view/bot/bot/botForm.vue
@@ -7,7 +7,7 @@
-
+
保存
@@ -43,6 +43,7 @@ const router = useRouter()
const btnLoading = ref(false)
const type = ref('')
+const useWatermark = ref(true) // 明确设置为 true
const formData = ref({
keyword: '',
content: '',
diff --git a/src/view/dashboard/components/index.js b/src/view/dashboard/components/index.js
index a59985b..ac8ff34 100644
--- a/src/view/dashboard/components/index.js
+++ b/src/view/dashboard/components/index.js
@@ -3,7 +3,6 @@ import GvaCard from './card.vue'
import GvaChart from './charts.vue'
import GvaTable from './table.vue'
import GvaNotice from './notice.vue'
-import GvaQuickLink from './quickLinks.vue'
import GvaWiki from './wiki.vue'
import GvaPluginTable from './pluginTable.vue'
@@ -13,7 +12,6 @@ export {
GvaChart,
GvaTable,
GvaNotice,
- GvaQuickLink,
GvaWiki,
GvaPluginTable
}
diff --git a/src/view/dashboard/components/quickLinks.vue b/src/view/dashboard/components/quickLinks.vue
deleted file mode 100644
index 5619b88..0000000
--- a/src/view/dashboard/components/quickLinks.vue
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-
-
-
-
- {{ item.title }}
-
-
-
-
-
-
-
-
-
- {{ item.title }}
-
-
-
-
-
-
-
-
diff --git a/src/view/dashboard/index.vue b/src/view/dashboard/index.vue
index 353bca6..c3feb39 100644
--- a/src/view/dashboard/index.vue
+++ b/src/view/dashboard/index.vue
@@ -11,50 +11,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -65,7 +23,6 @@
GvaChart,
GvaWiki,
GvaNotice,
- GvaQuickLink,
GvaCard,
GvaBanner
} from './components'