|
@@ -1,6 +1,7 @@
|
|
|
<template>
|
|
|
<div
|
|
|
class="courserware"
|
|
|
+ ref="courserware"
|
|
|
:style="[
|
|
|
{
|
|
|
backgroundImage: background.background_image_url ? `url(${background.background_image_url})` : '',
|
|
@@ -20,17 +21,29 @@
|
|
|
<div :key="j" :class="['col', `col-${i}-${j}`]" :style="computedColStyle(col)">
|
|
|
<!-- 网格 -->
|
|
|
<template v-for="(grid, k) in col.grid_list">
|
|
|
- <component
|
|
|
- :is="previewComponentList[grid.type]"
|
|
|
- ref="preview"
|
|
|
- :key="k"
|
|
|
- :content="computedColContent(grid.id)"
|
|
|
- :class="[grid.id]"
|
|
|
- :style="{
|
|
|
- gridArea: grid.grid_area,
|
|
|
- height: grid.height,
|
|
|
- }"
|
|
|
- />
|
|
|
+ <div @contextmenu.prevent="handleContextMenu($event, grid.id)" :key="k">
|
|
|
+ <component
|
|
|
+ :is="previewComponentList[grid.type]"
|
|
|
+ ref="preview"
|
|
|
+ :content="computedColContent(grid.id)"
|
|
|
+ :class="[grid.id]"
|
|
|
+ :style="{
|
|
|
+ gridArea: grid.grid_area,
|
|
|
+ height: grid.height,
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="showMenu && componentId === grid.id"
|
|
|
+ class="custom-context-menu"
|
|
|
+ :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }"
|
|
|
+ @click="handleMenuItemClick"
|
|
|
+ :key="'menu' + grid.id + k"
|
|
|
+ >
|
|
|
+ <SvgIcon icon-class="icon_publish" size="24" />
|
|
|
+ 添加批注
|
|
|
+ </div>
|
|
|
</template>
|
|
|
</div>
|
|
|
</template>
|
|
@@ -63,6 +76,10 @@ export default {
|
|
|
type: Array,
|
|
|
required: true,
|
|
|
},
|
|
|
+ canRemark: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
@@ -70,6 +87,21 @@ export default {
|
|
|
bookInfo: {
|
|
|
theme_color: '',
|
|
|
},
|
|
|
+ showMenu: false,
|
|
|
+ divPosition: {
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ }, // courserware盒子原始距离页面顶部和左边的距离
|
|
|
+ menuPosition: { x: 0, y: 0, select_node: '' }, // 用于存储菜单的位置
|
|
|
+ componentId: '', // 添加批注的组件id
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ const element = this.$refs.courserware;
|
|
|
+ const rect = element.getBoundingClientRect();
|
|
|
+ this.divPosition = {
|
|
|
+ left: rect.left,
|
|
|
+ top: rect.top,
|
|
|
};
|
|
|
},
|
|
|
methods: {
|
|
@@ -199,12 +231,42 @@ export default {
|
|
|
gridTemplateRows,
|
|
|
};
|
|
|
},
|
|
|
+ handleContextMenu(event, id) {
|
|
|
+ if (this.canRemark) {
|
|
|
+ event.preventDefault(); // 阻止默认的上下文菜单显示
|
|
|
+ this.menuPosition = {
|
|
|
+ x: event.clientX - this.divPosition.left,
|
|
|
+ y: event.clientY - this.divPosition.top,
|
|
|
+ }; // 设置菜单位置
|
|
|
+ this.componentId = id;
|
|
|
+ this.$emit('computeScroll');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleResult(top, left, select_node) {
|
|
|
+ this.menuPosition = {
|
|
|
+ x: this.menuPosition.x + left,
|
|
|
+ y: this.menuPosition.y + top,
|
|
|
+ select_node: select_node,
|
|
|
+ }; // 设置菜单位置
|
|
|
+ this.showMenu = true; // 显示菜单
|
|
|
+ },
|
|
|
+ handleMenuItemClick() {
|
|
|
+ this.showMenu = false; // 隐藏菜单
|
|
|
+ this.$emit(
|
|
|
+ 'addRemark',
|
|
|
+ this.menuPosition.select_node,
|
|
|
+ this.menuPosition.x,
|
|
|
+ this.menuPosition.y,
|
|
|
+ this.componentId,
|
|
|
+ );
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.courserware {
|
|
|
+ position: relative;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
row-gap: 6px;
|
|
@@ -227,5 +289,15 @@ export default {
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .custom-context-menu {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 999;
|
|
|
+ display: flex;
|
|
|
+ gap: 3px;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|