Просмотр исходного кода

feat: 添加页面大小不匹配确认对话框及多语言支持

添加页面大小不匹配时的确认对话框功能
在导入PPT时增加页面大小检查及用户确认流程
新增多语言翻译字段ssPageSizeMismatch
修改Modal组件默认显示状态
优化CreateCourseDialog的文件名处理逻辑
lsc 6 дней назад
Родитель
Сommit
16f57a1830

+ 1 - 1
src/components/CollapsibleToolbar/componets/aiChat.vue

@@ -308,7 +308,7 @@ const prevChatResult = () => {
 
 const sendQuickAction = (action: string) => {
   inputText.value = action
-  sendMessage()
+  // sendMessage()
 }
 
 import { v4 as uuidv4 } from 'uuid'

+ 96 - 0
src/components/ConfirmDialog2.vue

@@ -0,0 +1,96 @@
+<template>
+  <Modal
+    :visible="visible"
+    :width="width"
+    :contentStyle="{ borderRadius: '15px' }"
+    :closeButton="false"
+    :closeOnClickMask="false"
+    :closeOnEsc="false"
+    @update:visible="handleVisibleChange"
+  >
+    <div class="clear-confirm">
+      <div class="clear-confirm__title">{{ title }}</div>
+      <div class="clear-confirm__content">
+        {{ content }}
+      </div>
+      <div class="clear-confirm__footer">
+        <div class="btn-c" @click="handleCancel">{{ cancelText }}</div>
+        <div class="btn-c confirm" @click="handleConfirm">{{ confirmText }}</div>
+      </div>
+    </div>
+  </Modal>
+</template>
+
+<script lang="ts" setup>
+import Modal from '@/components/Modal.vue'
+
+const props = withDefaults(defineProps<{
+  visible: boolean
+  title?: string
+  content?: string
+  confirmText?: string
+  cancelText?: string
+  width?: number
+}>(), {
+  title: '提示',
+  content: '',
+  confirmText: '确认',
+  cancelText: '取消',
+  width: 400,
+})
+
+const emit = defineEmits<{
+  (event: 'update:visible', payload: boolean): void
+  (event: 'confirm'): void
+  (event: 'cancel'): void
+}>()
+
+const handleVisibleChange = (val: boolean) => {
+  emit('update:visible', val)
+}
+
+const handleConfirm = () => {
+  emit('confirm')
+  emit('update:visible', false)
+}
+
+const handleCancel = () => {
+  emit('cancel')
+  emit('update:visible', false)
+}
+</script>
+
+<style lang="scss" scoped>
+.btn-c {
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  background: #FFF;
+  border: 1px solid #DCDFE6;
+  color: #606266;
+  text-align: center;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  transition: .1s;
+  font-weight: 500;
+  padding: 12px 20px;
+  font-size: 14px;
+  border-radius: 10px;
+
+  +.btn-c {
+    margin-left: 10px;
+  }
+
+  &.confirm {
+    background: #FF9400;
+    color: white;
+    border: 1px solid #FF9400;
+
+    &:hover {
+      background: #FFA500;
+    }
+  }
+}
+</style>

+ 3 - 2
src/components/CreateCourseDialog.vue

@@ -104,6 +104,7 @@ import { lang } from '@/main'
 const emit = defineEmits<{
   (e: 'close'): void
   (e: 'select', option: string): void
+  (e: 'setTitle', title: string): void
 }>()
 
 const { importPPTXFile, exporting } = useImport()
@@ -129,14 +130,14 @@ const handleFileUpload = async (files: FileList) => {
 
   const file = files[0]
   currentFileName.value = file.name
-
+  
   try {
     // 创建AbortController用于取消操作
     parsingAbortController.value = new AbortController()
     const signal = parsingAbortController.value.signal
 
     // 调用importPPTXFile并传入signal
-    await importPPTXFile(files, { signal, onclose: () => emit('close') })
+    await importPPTXFile(files, { signal, onclose: () => {emit('setTitle', file.name.replace(/\.[^/.]+$/, '')); emit('close')} })
   }
   catch (error) {
     if (error instanceof DOMException && error.name === 'AbortError') {

+ 1 - 1
src/components/Modal.vue

@@ -47,7 +47,7 @@ const emit = defineEmits<{
   (event: 'closed'): void
 }>()
 
-const contentVisible = ref(false)
+const contentVisible = ref(true)
 const modalClass = computed(() => props.class)
 
 const contentStyle = computed(() => {

+ 18 - 3
src/hooks/useImport.ts

@@ -1,4 +1,4 @@
-import { ref, nextTick } from 'vue'
+import { ref, nextTick } from 'vue'
 import { storeToRefs } from 'pinia'
 import { parse, type Shape, type Element, type ChartItem, type BaseElement } from 'pptxtojson'
 import { nanoid } from 'nanoid'
@@ -11,6 +11,7 @@ import useSlideHandler from '@/hooks/useSlideHandler'
 import useHistorySnapshot from './useHistorySnapshot'
 import message from '@/utils/message'
 import { getSvgPathRange } from '@/utils/svgPathParser'
+import { showConfirmDialog } from '@/utils/confirmDialog'
 import { EMFJS, WMFJS } from 'rtf.js'
 import * as UTIF from 'utif2'
 
@@ -1666,10 +1667,24 @@ export default () => {
       }
       else {
         const targetViewportSize = width * ratio
+        if (!isNone && targetViewportSize != slidesStore.viewportSize) {
+          const confirmed = await showConfirmDialog({
+            title: lang.ssConfirmOperation,
+            content: lang.ssPageSizeMismatch,
+            confirmText: lang.ssConfirm,
+            cancelText: lang.ssCancel
+          })
+          if (!confirmed) {
+            exporting.value = false
+            imgExporting.value = false
+            onclose?.()
+            return Promise.reject(new Error('用户取消导入'))
+          }
+        }
         if (isNone || targetViewportSize > slidesStore.viewportSize) {
           slidesStore.setViewportSize(targetViewportSize) // 调整画布大小
+          slidesStore.setViewportRatio(viewportRatio)
         }
-        slidesStore.setViewportRatio(viewportRatio)
       }
 
       // 设置主题色
@@ -2468,4 +2483,4 @@ export default () => {
     dataToFile,
     uploadFileToS3
   }
-}
+}

+ 49 - 0
src/utils/confirmDialog.ts

@@ -0,0 +1,49 @@
+import { ref } from 'vue'
+import ConfirmDialog from '@/components/ConfirmDialog2.vue'
+import { createApp } from 'vue'
+
+interface ConfirmDialogOptions {
+  title?: string
+  content: string
+  confirmText?: string
+  cancelText?: string
+  width?: number
+}
+
+export function showConfirmDialog(options: ConfirmDialogOptions): Promise<boolean> {
+  return new Promise((resolve) => {
+    const visible = ref(true)
+    const container = document.createElement('div')
+    document.body.appendChild(container)
+
+    const app = createApp(ConfirmDialog, {
+      visible: visible.value,
+      title: options.title || '提示',
+      content: options.content,
+      confirmText: options.confirmText || '确认',
+      cancelText: options.cancelText || '取消',
+      width: options.width || 400,
+      onConfirm: () => {
+        visible.value = false
+        setTimeout(() => {
+          app.unmount()
+          document.body.removeChild(container)
+          resolve(true)
+        }, 300)
+      },
+      onCancel: () => {
+        visible.value = false
+        setTimeout(() => {
+          app.unmount()
+          document.body.removeChild(container)
+          resolve(false)
+        }, 300)
+      },
+      'onUpdate:visible': (val: boolean) => {
+        visible.value = val
+      }
+    })
+
+    app.mount(container)
+  })
+}

+ 2 - 2
src/views/Editor/index3.vue

@@ -195,7 +195,7 @@
 
   <Modal class="createCourseDialog" :visible="showCreateCourseDialog" :closeOnClickMask="false" :closeOnEsc="false"
     :closeButton="false" @closed="closeCreateCourseDialog()">
-    <CreateCourseDialog @close="closeCreateCourseDialog" @select="handleCreateCourseSelect" />
+    <CreateCourseDialog @close="closeCreateCourseDialog" @select="handleCreateCourseSelect"  @setTitle="setTitle"/>
   </Modal>
 </template>
 
@@ -522,7 +522,7 @@ usePasteEvent()
 }
 
 .course-title-container {
-  margin-bottom: 4px;
+  // margin-bottom: 4px;
 }
 
 .course-title {

+ 2 - 1
src/views/lang/cn.json

@@ -747,5 +747,6 @@
   "ssNotSaved": "未保存",
   "ssPublish": "发布",
   "ssSave": "保存",
-  "ssNewCourse": "新建课程"
+  "ssNewCourse": "新建课程",
+  "ssPageSizeMismatch": "待添加页面与当前页面大小不一致,是否继续?"
 }

+ 2 - 1
src/views/lang/en.json

@@ -747,5 +747,6 @@
   "ssNotSaved": "Not Saved",
   "ssPublish": "Publish",
   "ssSave": "Save",
-  "ssNewCourse": "New Course"
+  "ssNewCourse": "New Course",
+  "ssPageSizeMismatch": "Page size mismatch, continue?"
 }

+ 2 - 1
src/views/lang/hk.json

@@ -747,5 +747,6 @@
   "ssNotSaved": "未保存",
   "ssPublish": "發布",
   "ssSave": "保存",
-  "ssNewCourse": "新建課程"
+  "ssNewCourse": "新建課程",
+  "ssPageSizeMismatch": "頁面大小不一致,是否繼續?"
 }