Merge branch 'feature/20231008-tinymce-link-popup'

# Conflicts:
#	src/views/planetDesign/Design/questions/paging/Paging.vue
This commit is contained in:
钱冠学
2023-10-31 13:41:22 +08:00
5 changed files with 103 additions and 17 deletions

View File

@@ -2,7 +2,24 @@
<a-config-provider :autoInsertSpaceInButton="false" :locale="locale"> <a-config-provider :autoInsertSpaceInButton="false" :locale="locale">
<Loading v-if="appLoading" :description="appLoadingDescription"/> <Loading v-if="appLoading" :description="appLoadingDescription"/>
<div class="link-action-wrapper" @click="clickAction">
<router-view /> <router-view />
</div>
<a-modal
centered
:width="700"
:visible="show"
:title="title"
:maskClosable="true"
:closable="true"
wrapClassName="custom-modal"
:footer="null"
>
<template #closeIcon>
<i class="iconfont model-close" @click="show=false">&#xe68b;</i>
</template>
<iframe v-if="show" :src="url" class="iframe"></iframe>
</a-modal>
</a-config-provider> </a-config-provider>
</template> </template>
@@ -23,8 +40,10 @@ export default {
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const store = useStore(); const store = useStore();
const title = ref('');
const show = ref(false);
const url = ref('');
const emitter = useEmitter(); const emitter = useEmitter();
const appLoading = ref(false); const appLoading = ref(false);
const appLoadingDescription = ref('请您稍候~'); const appLoadingDescription = ref('请您稍候~');
emitter.on('app-loading', (evt) => { emitter.on('app-loading', (evt) => {
@@ -64,10 +83,22 @@ export default {
// } // }
// }) // })
// }) // })
const clickAction = (e) => {
if(e.target.getAttribute("data-linkType") === '1'){
show.value = true;
title.value = e.target.innerText;
url.value = e.target.href;
e.preventDefault();
}
}
return { return {
locale, locale,
appLoading, appLoading,
appLoadingDescription, appLoadingDescription,
clickAction,
show,
url,
title,
}; };
}, },
}; };
@@ -154,4 +185,16 @@ strong {
.viewer-container { .viewer-container {
transition: all 0.01s !important; transition: all 0.01s !important;
} }
.iframe {
flex: 1;
width: 100%;
height: 500px;
border: 0;
}
.link-action-wrapper {
width: 100%;
height: 100%;
}
</style> </style>

View File

@@ -29,6 +29,18 @@
<a-form-item label="显示文字"> <a-form-item label="显示文字">
<a-input v-model:value="linkText" placeholder="请输入显示的文字" /> <a-input v-model:value="linkText" placeholder="请输入显示的文字" />
</a-form-item> </a-form-item>
<a-form-item label="打开方式">
<div style="padding-top: 5px">
<a-radio-group class="custom-radio-group" v-model:value="linkType">
<a-radio class="custom-radio" :value="'1'">弹窗</a-radio>
<a-radio class="custom-radio" :value="'2'">新页面</a-radio>
<a-radio class="custom-radio" :value="'3'">当前页面</a-radio>
</a-radio-group>
</div>
<p style="margin-top: 3px;font-size: 13px; color: #979797">{{ `${linkType === '1' ? '链接内容将在当前页面内弹窗显示。' :
linkType === '2' ? '链接内容将在新页签内显示,可切换页面回到问卷答题页。' :
'链接在当前页面打开,覆盖问卷答题页面,建议开启“断点续答”后使用。'}` }}</p>
</a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
<a-modal <a-modal
@@ -372,9 +384,8 @@ export default {
const route = useRoute(); const route = useRoute();
const sn = computed(() => route.query.sn || ""); const sn = computed(() => route.query.sn || "");
const fixation = ref(props.isFixation) const fixation = ref(props.isFixation)
const { linkAddress, linkText, linkDialogVisible, linkDiglogOkHandle } = const { linkAddress, linkText, linkType, linkDialogVisible, linkDiglogOkHandle } =
linkDialog(fixation); linkDialog(fixation);
const { const {
d3Address, d3Address,
d3Width, d3Width,
@@ -417,6 +428,7 @@ export default {
context, context,
linkDialogVisible, linkDialogVisible,
linkAddress, linkAddress,
linkType,
linkText, linkText,
d3DialogVisible, d3DialogVisible,
d3Address, d3Address,
@@ -478,6 +490,7 @@ export default {
editorId, editorId,
linkAddress, linkAddress,
linkText, linkText,
linkType,
init, init,
fileInput, fileInput,
content, content,
@@ -529,6 +542,7 @@ function initTinymce(data) {
linkDialogVisible, linkDialogVisible,
linkAddress, linkAddress,
linkText, linkText,
linkType,
d3DialogVisible, d3DialogVisible,
d3Address, d3Address,
d3Width, d3Width,
@@ -652,6 +666,11 @@ function initTinymce(data) {
tinymce.editors[editor.id].selection.select(wrapperNode, true); tinymce.editors[editor.id].selection.select(wrapperNode, true);
linkText.value = wrapperNode.innerText; linkText.value = wrapperNode.innerText;
linkAddress.value = wrapperNode.href || ""; linkAddress.value = wrapperNode.href || "";
linkType.value = wrapperNode.getAttribute("data-linkType") || "1";
} else {
linkText.value = "";
linkAddress.value = "";
linkType.value = "1";
} }
linkDialogVisible.value = true; linkDialogVisible.value = true;
}, },
@@ -704,6 +723,7 @@ function initTinymce(data) {
paste_data_images: true, paste_data_images: true,
setup: function (editor) { setup: function (editor) {
editorId.value = editor.id; editorId.value = editor.id;
linkType.value = editor.linkType;
editor.ui.registry.addIcon("linkIcon", link); editor.ui.registry.addIcon("linkIcon", link);
editor.ui.registry.addButton("linkButton", { editor.ui.registry.addButton("linkButton", {
icon: "linkIcon", icon: "linkIcon",
@@ -717,6 +737,11 @@ function initTinymce(data) {
tinymce.editors[editor.id].selection.select(wrapperNode, true); tinymce.editors[editor.id].selection.select(wrapperNode, true);
linkText.value = wrapperNode.innerText; linkText.value = wrapperNode.innerText;
linkAddress.value = wrapperNode.href || ""; linkAddress.value = wrapperNode.href || "";
linkType.value = wrapperNode.getAttribute("data-linkType") || "1";
} else {
linkText.value = "";
linkAddress.value = "";
linkType.value = "1";
} }
linkDialogVisible.value = true; linkDialogVisible.value = true;
}, },
@@ -849,6 +874,7 @@ function linkDialog(fixation) {
const linkAddress = ref(""); const linkAddress = ref("");
const linkText = ref(""); // 用于显示 const linkText = ref(""); // 用于显示
const linkDialogVisible = ref(false); const linkDialogVisible = ref(false);
const linkType = ref("1")
const linkDiglogOkHandle = (id) => { const linkDiglogOkHandle = (id) => {
if (!linkAddress.value || !linkText.value) { if (!linkAddress.value || !linkText.value) {
message.info("请输入文字和链接地址"); message.info("请输入文字和链接地址");
@@ -857,29 +883,43 @@ function linkDialog(fixation) {
if (!linkAddress.value.startsWith("http")) { if (!linkAddress.value.startsWith("http")) {
linkAddress.value = `https://${linkAddress.value}`; linkAddress.value = `https://${linkAddress.value}`;
} }
let value = "";
// 插入链接前后加空格 // 插入链接前后加空格
if(fixation.value) { if(fixation.value) {
tinymce.editors[id].execCommand( value = `&nbsp;<a data-linkType="${linkType.value}" href="${linkAddress.value}">${linkText.value}</a>&nbsp;`;
"mceInsertContent", if (linkType.value === '2') {
false, value = `&nbsp;<a data-linkType="${linkType.value}" href="${linkAddress.value}" target="_blank">${linkText.value}</a>&nbsp;`;
`&nbsp;<a href="${linkAddress.value}">${linkText.value}</a>&nbsp;` } else if (linkType.value === '1') {
); value = `&nbsp;<a data-linkType="${linkType.value}" href="${linkAddress.value}">${linkText.value}</a>&nbsp;`;
}else{
tinymce.editors[id].execCommand(
"mceInsertContent",
false,
`<a href="${linkAddress.value}">${linkText.value}</a>`
);
} }
} else {
value = `<a data-linkType="${linkType.value}" href="${linkAddress.value}">${linkText.value}</a>`;
if(linkType.value === '2'){
value = `<a data-linkType="${linkType.value}" target="_blank" href="${linkAddress.value}">${linkText.value}</a>`;
}else if(linkType.value === '1'){
value = `<a data-linkType="${linkType.value}" href="${linkAddress.value}">${linkText.value}</a>`;
}
}
tinymce.editors[id].execCommand(
"mceInsertContent",
false,
`${value}`,
);
linkDialogVisible.value = false; linkDialogVisible.value = false;
linkAddress.value = ""; linkAddress.value = "";
linkText.value = ""; linkText.value = "";
linkType.value = "1";
}; };
const clickOutside = () => {
}
return { return {
linkType,
linkAddress, linkAddress,
linkText, linkText,
linkDialogVisible, linkDialogVisible,
linkDiglogOkHandle, linkDiglogOkHandle,
clickOutside,
}; };
} }
/** /**

View File

@@ -32,6 +32,7 @@ app.use(VXETable);
app.use(VueParticles); app.use(VueParticles);
app.use(NutBig); app.use(NutBig);
app.use(lazyPlugin, {}); app.use(lazyPlugin, {});
app.directive("click-outside", { app.directive("click-outside", {
// 当被绑定的元素挂载到 DOM 中时…… // 当被绑定的元素挂载到 DOM 中时……
mounted(el, binding) { mounted(el, binding) {

View File

@@ -222,6 +222,7 @@
@click.stop="" @click.stop=""
@activePage="pitchOnHandle(element)" @activePage="pitchOnHandle(element)"
@removePage="removePageHandle(index)" @removePage="removePageHandle(index)"
@selectPage="selectPageHandle(index)"
/> />
</div> </div>
<template <template

View File

@@ -10,6 +10,7 @@
<i class="iconfont active-icon" :style="{marginRight: isLastPage ? '0' : '16px'}" <i class="iconfont active-icon" :style="{marginRight: isLastPage ? '0' : '16px'}"
@click="activePage">&#xe86c;</i> @click="activePage">&#xe86c;</i>
<template v-if="!isLastPage"> <template v-if="!isLastPage">
<i class="iconfont" style="margin-right: 16px;" @click="selectPaging">&#xe71b;</i>
<i class="iconfont moverQues" style="margin-right: 16px;">&#xe71b;</i> <i class="iconfont moverQues" style="margin-right: 16px;">&#xe71b;</i>
<i class="iconfont" @click="deleteHandle">&#xe6c5;</i> <i class="iconfont" @click="deleteHandle">&#xe6c5;</i>
</template> </template>
@@ -21,7 +22,6 @@
<script> <script>
import { computed } from "@vue/reactivity"; import { computed } from "@vue/reactivity";
import { useStore } from "vuex"; import { useStore } from "vuex";
export default { export default {
name: "Paging", name: "Paging",
props: { props: {
@@ -49,6 +49,7 @@ export default {
activePage, activePage,
deleteHandle, deleteHandle,
selectPaging,
}; };
}, },
}; };