|
|
@@ -377,47 +377,90 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 右键菜单 -->
|
|
|
+ <!-- 右键菜单 - V2 风格 -->
|
|
|
<div
|
|
|
v-show="contextMenuVisible"
|
|
|
class="context-menu"
|
|
|
:style="{ left: contextMenuPos.x + 'px', top: contextMenuPos.y + 'px' }"
|
|
|
>
|
|
|
- <div class="context-menu-header" v-if="selectedText">
|
|
|
- <span class="selected-preview">"{{ selectedText.slice(0, 20) }}{{ selectedText.length > 20 ? '...' : '' }}"</span>
|
|
|
+ <!-- 基础操作 -->
|
|
|
+ <div class="context-menu-item" @click="execContextAction('copy')">
|
|
|
+ <span class="icon">📋</span>
|
|
|
+ <span>复制</span>
|
|
|
+ <span class="shortcut">Ctrl+C</span>
|
|
|
</div>
|
|
|
- <div class="context-menu-section">标记为实体</div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('person')" :disabled="markingEntity">
|
|
|
- <span class="icon">👤</span>
|
|
|
- <span>人物</span>
|
|
|
+ <div class="context-menu-item" @click="execContextAction('cut')">
|
|
|
+ <span class="icon">✂️</span>
|
|
|
+ <span>剪切</span>
|
|
|
+ <span class="shortcut">Ctrl+X</span>
|
|
|
</div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('org')" :disabled="markingEntity">
|
|
|
- <span class="icon">🏢</span>
|
|
|
- <span>组织机构</span>
|
|
|
+ <div class="context-menu-item" @click="execContextAction('paste')">
|
|
|
+ <span class="icon">📄</span>
|
|
|
+ <span>粘贴</span>
|
|
|
+ <span class="shortcut">Ctrl+V</span>
|
|
|
</div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('location')" :disabled="markingEntity">
|
|
|
- <span class="icon">📍</span>
|
|
|
- <span>地点</span>
|
|
|
- </div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('date')" :disabled="markingEntity">
|
|
|
- <span class="icon">📅</span>
|
|
|
- <span>日期/时间</span>
|
|
|
- </div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('data')" :disabled="markingEntity">
|
|
|
- <span class="icon">📊</span>
|
|
|
- <span>数据/指标</span>
|
|
|
+
|
|
|
+ <div class="context-menu-divider"></div>
|
|
|
+
|
|
|
+ <!-- AI 功能 -->
|
|
|
+ <div class="context-menu-item" @click="execContextAction('polish')">
|
|
|
+ <span class="icon">✨</span>
|
|
|
+ <span>AI 润色</span>
|
|
|
</div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('concept')" :disabled="markingEntity">
|
|
|
- <span class="icon">💡</span>
|
|
|
- <span>概念/技术</span>
|
|
|
+ <div class="context-menu-item" @click="execContextAction('spell')">
|
|
|
+ <span class="icon">📝</span>
|
|
|
+ <span>检查拼写</span>
|
|
|
</div>
|
|
|
- <div class="context-menu-item" @click="markAsVariable('entity')" :disabled="markingEntity">
|
|
|
+
|
|
|
+ <div class="context-menu-divider"></div>
|
|
|
+
|
|
|
+ <!-- 标记和引用 -->
|
|
|
+ <div class="context-menu-item has-submenu" @mouseenter="showEntitySubmenu = true" @mouseleave="showEntitySubmenu = false">
|
|
|
<span class="icon">🏷️</span>
|
|
|
- <span>其他实体</span>
|
|
|
+ <span>标记为要素</span>
|
|
|
+ <span class="submenu-arrow">›</span>
|
|
|
+
|
|
|
+ <!-- 实体类型子菜单 -->
|
|
|
+ <div class="context-submenu" v-show="showEntitySubmenu">
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('person')" :disabled="markingEntity">
|
|
|
+ <span class="icon">👤</span>
|
|
|
+ <span>人物</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('org')" :disabled="markingEntity">
|
|
|
+ <span class="icon">🏢</span>
|
|
|
+ <span>组织机构</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('location')" :disabled="markingEntity">
|
|
|
+ <span class="icon">📍</span>
|
|
|
+ <span>地点</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('date')" :disabled="markingEntity">
|
|
|
+ <span class="icon">📅</span>
|
|
|
+ <span>日期/时间</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('data')" :disabled="markingEntity">
|
|
|
+ <span class="icon">📊</span>
|
|
|
+ <span>数据/指标</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('concept')" :disabled="markingEntity">
|
|
|
+ <span class="icon">💡</span>
|
|
|
+ <span>概念/技术</span>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click.stop="markAsVariable('entity')" :disabled="markingEntity">
|
|
|
+ <span class="icon">🏷️</span>
|
|
|
+ <span>其他</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="context-menu-item" @click="execContextAction('quote')">
|
|
|
+ <span class="icon">💬</span>
|
|
|
+ <span>引用到AI助手</span>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 加载状态 -->
|
|
|
<div class="context-menu-loading" v-if="markingEntity">
|
|
|
<el-icon class="is-loading"><Loading /></el-icon>
|
|
|
- <span>标记中...</span>
|
|
|
+ <span>处理中...</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -1440,6 +1483,7 @@ const variableForm = reactive({
|
|
|
// 右键菜单
|
|
|
const contextMenuVisible = ref(false)
|
|
|
const contextMenuPos = reactive({ x: 0, y: 0 })
|
|
|
+const showEntitySubmenu = ref(false)
|
|
|
const selectedText = ref('')
|
|
|
const selectionRange = ref(null)
|
|
|
|
|
|
@@ -2492,6 +2536,42 @@ function handleContextMenu(event) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 执行右键菜单操作
|
|
|
+ */
|
|
|
+function execContextAction(action) {
|
|
|
+ switch (action) {
|
|
|
+ case 'copy':
|
|
|
+ document.execCommand('copy')
|
|
|
+ ElMessage.success('已复制')
|
|
|
+ break
|
|
|
+ case 'cut':
|
|
|
+ document.execCommand('cut')
|
|
|
+ ElMessage.success('已剪切')
|
|
|
+ break
|
|
|
+ case 'paste':
|
|
|
+ navigator.clipboard.readText().then(text => {
|
|
|
+ document.execCommand('insertText', false, text)
|
|
|
+ }).catch(() => {
|
|
|
+ ElMessage.warning('无法访问剪贴板')
|
|
|
+ })
|
|
|
+ break
|
|
|
+ case 'polish':
|
|
|
+ ElMessage.info('AI 润色功能开发中...')
|
|
|
+ break
|
|
|
+ case 'spell':
|
|
|
+ ElMessage.info('拼写检查功能开发中...')
|
|
|
+ break
|
|
|
+ case 'quote':
|
|
|
+ ElMessage.info('引用到AI助手功能开发中...')
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ contextMenuVisible.value = false
|
|
|
+ showEntitySubmenu.value = false
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* 获取选中文本所在的块信息
|
|
|
*/
|
|
|
@@ -4355,6 +4435,7 @@ onUnmounted(() => {
|
|
|
cursor: pointer;
|
|
|
transition: all 0.15s;
|
|
|
color: var(--text-1);
|
|
|
+ position: relative;
|
|
|
|
|
|
&:hover {
|
|
|
background: var(--primary-light);
|
|
|
@@ -4370,6 +4451,7 @@ onUnmounted(() => {
|
|
|
font-size: 14px;
|
|
|
width: 20px;
|
|
|
text-align: center;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.shortcut {
|
|
|
@@ -4377,6 +4459,41 @@ onUnmounted(() => {
|
|
|
font-size: 11px;
|
|
|
color: var(--text-3);
|
|
|
}
|
|
|
+
|
|
|
+ .submenu-arrow {
|
|
|
+ margin-left: auto;
|
|
|
+ font-size: 14px;
|
|
|
+ color: var(--text-3);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.has-submenu {
|
|
|
+ &:hover .submenu-arrow {
|
|
|
+ color: var(--primary);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 子菜单
|
|
|
+ .context-submenu {
|
|
|
+ position: absolute;
|
|
|
+ left: 100%;
|
|
|
+ top: 0;
|
|
|
+ min-width: 150px;
|
|
|
+ background: var(--white);
|
|
|
+ border-radius: var(--radius-md);
|
|
|
+ box-shadow: var(--shadow-lg);
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .context-menu-item {
|
|
|
+ padding: 8px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .icon {
|
|
|
+ font-size: 12px;
|
|
|
+ width: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.context-menu-divider {
|