|
@@ -12,18 +12,20 @@
|
|
|
/>
|
|
|
<span v-else class="rich-text" @click="handleRichFillClick" v-html="sanitizeHTML(data.content)"></span>
|
|
|
</div>
|
|
|
- <div v-if="data.note_list.length > 0" ref="rightDiv" class="note-list" :style="{ height: divHeight + 'px' }">
|
|
|
- <span>注释</span>
|
|
|
- <ul>
|
|
|
- <li v-for="note in data.note_list" :key="note.id" :ref="note.id">
|
|
|
- <p :style="{ 'background-color': selectedNoteId == note.id ? '#FFF2C9' : '#CCC' }">
|
|
|
- {{ note.selectText }}
|
|
|
- </p>
|
|
|
- <span v-html="sanitizeHTML(note.note)"></span>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- </div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ title=""
|
|
|
+ :visible.sync="noteDialogVisible"
|
|
|
+ width="680px"
|
|
|
+ ref="optimizedDialog"
|
|
|
+ :style="dialogStyle"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ destroy-on-close
|
|
|
+ @close="noteDialogVisible = false"
|
|
|
+ >
|
|
|
+ <span v-html="selectedNote"></span>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -41,10 +43,17 @@ export default {
|
|
|
return {
|
|
|
isEnable,
|
|
|
data: getRichTextData(),
|
|
|
- selectedNoteId: '',
|
|
|
isPreview: true,
|
|
|
divHeight: 'auto',
|
|
|
observer: null,
|
|
|
+ noteDialogVisible: false,
|
|
|
+ selectedNote: '',
|
|
|
+ dialogStyle: {
|
|
|
+ position: 'fixed',
|
|
|
+ top: '0',
|
|
|
+ left: '0',
|
|
|
+ margin: '0',
|
|
|
+ },
|
|
|
};
|
|
|
},
|
|
|
mounted() {
|
|
@@ -62,24 +71,61 @@ export default {
|
|
|
const richFillElement = event.target.closest('.rich-fill');
|
|
|
if (richFillElement) {
|
|
|
// 处理点击事件
|
|
|
- this.selectedNoteId = richFillElement.dataset.annotationId;
|
|
|
-
|
|
|
- const sectionRef = this.$refs[`${this.selectedNoteId}`][0];
|
|
|
- const rightDiv = this.$refs.rightDiv;
|
|
|
-
|
|
|
- // 计算滚动位置
|
|
|
- const rightDivTop = rightDiv.getBoundingClientRect().top;
|
|
|
- const sectionTop = sectionRef.getBoundingClientRect().top;
|
|
|
- const scrollPosition = sectionTop - rightDivTop + rightDiv.scrollTop;
|
|
|
-
|
|
|
- // 平滑滚动
|
|
|
- rightDiv.scrollTo({
|
|
|
- top: scrollPosition,
|
|
|
- behavior: 'smooth',
|
|
|
- });
|
|
|
+ let selectedNoteId = richFillElement.dataset.annotationId;
|
|
|
+ if (this.data.note_list.some((p) => p.id === selectedNoteId)) {
|
|
|
+ this.noteDialogVisible = true;
|
|
|
+ this.selectedNote = this.data.note_list.find((p) => p.id === selectedNoteId).note;
|
|
|
+ }
|
|
|
} else {
|
|
|
- this.selectedNoteId = '';
|
|
|
+ this.selectedNote = '';
|
|
|
+ this.noteDialogVisible = false;
|
|
|
}
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const dialogElement = this.$refs.optimizedDialog;
|
|
|
+ // 确保对话框DOM已渲染
|
|
|
+ if (!dialogElement) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 获取对话框内容区域的DOM元素
|
|
|
+ const dialogContent = dialogElement.$el.querySelector('.el-dialog');
|
|
|
+ if (!dialogContent) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const dialogRect = dialogContent.getBoundingClientRect();
|
|
|
+ const dialogWidth = dialogRect.width;
|
|
|
+ const dialogHeight = dialogRect.height;
|
|
|
+ const padding = 10; // 安全边距
|
|
|
+
|
|
|
+ const clickX = event.clientX;
|
|
|
+ const clickY = event.clientY;
|
|
|
+
|
|
|
+ const windowWidth = window.innerWidth;
|
|
|
+ const windowHeight = window.innerHeight;
|
|
|
+
|
|
|
+ // 水平定位 - 中心对齐
|
|
|
+ let left = clickX - dialogWidth / 2;
|
|
|
+ // 边界检查
|
|
|
+ left = Math.max(padding, Math.min(left, windowWidth - dialogWidth - padding));
|
|
|
+
|
|
|
+ // 垂直定位 - 点击位置作为下边界中心
|
|
|
+ let top = clickY - dialogHeight;
|
|
|
+ // 上方空间不足时,改为向下展开
|
|
|
+ if (top < padding) {
|
|
|
+ top = clickY + padding;
|
|
|
+ // 如果向下展开会超出屏幕,则贴底部显示
|
|
|
+ if (top + dialogHeight > windowHeight - padding) {
|
|
|
+ top = windowHeight - dialogHeight - padding;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.dialogStyle = {
|
|
|
+ position: 'fixed',
|
|
|
+ top: `${top - 20}px`,
|
|
|
+ left: `${left}px`,
|
|
|
+ margin: '0',
|
|
|
+ transform: 'none',
|
|
|
+ };
|
|
|
+ });
|
|
|
},
|
|
|
updateHeight() {
|
|
|
this.$nextTick(() => {
|
|
@@ -101,48 +147,10 @@ export default {
|
|
|
.describe-preview {
|
|
|
@include preview-base;
|
|
|
|
|
|
- .main {
|
|
|
- display: flex;
|
|
|
- column-gap: 10px;
|
|
|
- justify-content: space-between;
|
|
|
-
|
|
|
- .note-list {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- width: 20%;
|
|
|
- min-height: 150px;
|
|
|
- overflow: auto;
|
|
|
-
|
|
|
- > span {
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
-
|
|
|
- li {
|
|
|
- margin-top: 6px;
|
|
|
- border-radius: 8px;
|
|
|
- box-shadow: 1px 3px 2px rgba(0, 0, 0, 10%);
|
|
|
-
|
|
|
- p {
|
|
|
- padding: 4px;
|
|
|
- margin: 0;
|
|
|
- background-color: #ccc;
|
|
|
- border-radius: 8px 8px 0 0;
|
|
|
- }
|
|
|
-
|
|
|
- span {
|
|
|
- display: block;
|
|
|
- padding: 8px;
|
|
|
-
|
|
|
- :deep p {
|
|
|
- margin: 0 !important;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- p {
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
- }
|
|
|
+ :deep .el-dialog {
|
|
|
+ position: fixed;
|
|
|
+ margin: 0 !important;
|
|
|
+ transition: all 0.2s; /* 添加平滑过渡效果 */
|
|
|
}
|
|
|
}
|
|
|
</style>
|