Commit 8fa24ad4 by pangchong

feat: 双向对比样式展示

parent 6e6a1181
...@@ -7,6 +7,8 @@ export {} ...@@ -7,6 +7,8 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
GlobalEditor: typeof import('./src/components/GlobalEditor.vue')['default']
GlobalModal: typeof import('./src/components/GlobalModal.vue')['default']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard'] NCard: typeof import('naive-ui')['NCard']
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
...@@ -17,6 +19,9 @@ declare module 'vue' { ...@@ -17,6 +19,9 @@ declare module 'vue' {
NLayoutFooter: typeof import('naive-ui')['NLayoutFooter'] NLayoutFooter: typeof import('naive-ui')['NLayoutFooter']
NLayoutHeader: typeof import('naive-ui')['NLayoutHeader'] NLayoutHeader: typeof import('naive-ui')['NLayoutHeader']
NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NModalProvider: typeof import('naive-ui')['NModalProvider']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin'] NSpin: typeof import('naive-ui')['NSpin']
NTree: typeof import('naive-ui')['NTree'] NTree: typeof import('naive-ui')['NTree']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
......
<template> <template>
<n-config-provider class="w-full h-full" :theme="appStore.theme" :locale="zhCN" :date-locale="dateZhCN" :theme-overrides="themeOverrides"> <n-config-provider class="w-full h-full" :theme="appStore.theme" :locale="zhCN" :date-locale="dateZhCN" :theme-overrides="themeOverrides">
<n-message-provider> <n-message-provider>
<router-view></router-view> <n-modal-provider>
<router-view></router-view>
</n-modal-provider>
</n-message-provider> </n-message-provider>
</n-config-provider> </n-config-provider>
</template> </template>
......
<template>
<div class="z-10 border border-solid border-borderColor w-full h-full">
<!-- 工具栏 -->
<Toolbar :editor="editorRef" :editorId="editorId" class="border-b border-solid border-borderColor" v-if="showToolbar" />
<!-- 编辑器 -->
<Editor
v-model="valueHtml"
:defaultConfig="editorConfig"
:editorId="editorId"
:style="editorStyle"
@on-change="handleChange"
@on-created="handleCreated"
/>
</div>
</template>
<script setup lang="ts">
import { IDomEditor, IEditorConfig } from '@wangeditor/editor'
// @ts-ignore
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { isNumber } from 'lodash'
const ps = defineProps({
modelValue: {
type: String,
default: ''
},
showToolbar: {
type: Boolean,
default: false
},
editorId: {
type: String,
default: 'wangeEditor-1'
},
url: {
type: String,
default: '/infra/file/uploadFile'
},
height: {
type: [String, Number],
default: '100%'
},
editorConfig: {
type: Object,
default: () => {
return undefined
}
},
readonly: {
type: Boolean,
default: false
}
})
const es = defineEmits(['change', 'created', 'update:modelValue', 'handleScrollTop'])
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef<IDomEditor>()
const valueHtml = ref('')
watch(
() => ps.modelValue,
(val: string) => {
if (val === unref(valueHtml)) return
valueHtml.value = val
},
{
immediate: true
}
)
// 监听
watch(
() => valueHtml.value,
(val: string) => {
es('update:modelValue', val)
}
)
const handleCreated = (editor: IDomEditor) => {
editorRef.value = editor
es('created', editor)
//监听滚动事件
const scrollDom = editor.getEditableContainer().querySelector('.w-e-scroll')
scrollDom?.addEventListener('scroll', function (event) {
es('handleScrollTop', event)
})
}
// 编辑器配置
const message = useMessage()
const editorConfig = computed((): IEditorConfig => {
return Object.assign(
{
placeholder: '请输入内容...',
readOnly: ps.readonly,
customAlert: (s: string, t: string) => {
switch (t) {
case 'success':
message.success(s)
break
case 'info':
message.info(s)
break
case 'warning':
message.warning(s)
break
case 'error':
message.error(s)
break
default:
message.info(s)
break
}
},
autoFocus: false,
scroll: true
},
ps.editorConfig || {}
)
})
const editorStyle = computed(() => {
return {
height: isNumber(ps.height) ? `${ps.height}px` : ps.height
}
})
// 回调函数
const handleChange = (editor: IDomEditor) => {
es('change', editor)
}
// 组件销毁时,及时销毁编辑器
onBeforeUnmount(() => {
const editor = unref(editorRef.value)
// 销毁,并移除 editor
editor?.destroy()
})
// 滑动
const handleScrollTop = (top: number) => {
editorRef.value?.getEditableContainer().querySelector('.w-e-scroll')?.scrollTo({ top })
}
defineExpose({
editorRef,
handleScrollTop
})
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<template>
<n-modal v-bind="$attrs" v-model:show="showModal" :preset="preset" :type="type">
<template #title>
<slot name="title"></slot>
</template>
<n-spin class="w-full h-full" content-class="w-full h-full" :show="loading" :description="description">
<slot></slot>
</n-spin>
<template #footer v-if="showFooter && preset == 'card'">
<slot name="footer">
<n-space justify="end">
<n-button ghost :type="type" @click="cancle" v-if="showCancel">{{ cancelText }}</n-button>
<n-button :type="type" @click="confirm" :loading="loading" :disabled="disabled" v-if="showOk">{{ okText }}</n-button>
</n-space>
</slot>
</template>
<template #action v-if="showFooter && preset == 'dialog'">
<slot name="footer">
<n-space justify="end">
<n-button ghost :type="type" @click="cancle" v-if="showCancel">{{ cancelText }}</n-button>
<n-button :type="type" @click="confirm" :loading="loading" :disabled="disabled" v-if="showOk">{{ okText }}</n-button>
</n-space>
</slot>
</template>
</n-modal>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { NModal, NButton, NSpace, NSpin } from 'naive-ui'
interface Props {
preset?: 'dialog' | 'card'
loading?: boolean
description?: string
disabled?: boolean
modelValue?: boolean
showFooter?: boolean
showOk?: boolean
showCancel?: boolean
okText?: string
cancelText?: string
type?: 'error' | 'success' | 'warning' | 'info'
}
const es = defineEmits(['cancel', 'confirm', 'update:modelValue'])
const showModal = computed({
get: () => {
return ps.modelValue
},
set: (value) => {
es('update:modelValue', value)
}
})
const ps = withDefaults(defineProps<Props>(), {
loading: false,
description: '加载中...',
disabled: false,
showFooter: true,
showOk: true,
showCancel: true,
okText: '确 定',
cancelText: '取 消',
type: 'info'
})
const cancle = () => {
showModal.value = false
es('cancel')
}
const confirm = () => {
es('confirm')
}
</script>
<style lang="less" scoped></style>
<template>
<GlobalModal
v-model="showCompare"
content-class="h-full overflow-hidden !p-0"
title="XML对比"
style="width: 99vw; height: 99vh"
preset="card"
:showFooter="false"
>
<div class="flex h-full">
<GlobalEditor
ref="compareLeftRef"
v-model="editorHtml"
editorId="compareLeft"
:editorConfig="{ readOnly: true }"
@handleScrollTop="handleScrollTopLeft"
/>
<GlobalEditor
ref="compareRightRef"
v-model="editorHtml"
editorId="compareRight"
:editorConfig="{ readOnly: true }"
@handleScrollTop="handleScrollTopRight"
/>
</div>
</GlobalModal>
</template>
<script setup lang="ts">
import { editorHtml } from '../constants'
import { showCompare, compareLeftRef, compareRightRef } from '../constants/compare'
import { handleScrollTopLeft, handleScrollTopRight } from '../functions/compare'
</script>
<style lang="less" scoped></style>
export const showCompare = ref(false)
export const compareLeftRef = ref()
export const compareRightRef = ref()
import { compareLeftRef, compareRightRef } from '../constants/compare'
export const handleScrollTopLeft = (event: Event) => {
const scrollTop = (event.target as HTMLInputElement).scrollTop
compareRightRef.value?.handleScrollTop(scrollTop)
}
export const handleScrollTopRight = (event: Event) => {
const scrollTop = (event.target as HTMLInputElement).scrollTop
compareLeftRef.value?.handleScrollTop(scrollTop)
}
...@@ -4,6 +4,7 @@ import { IDomEditor } from '@wangeditor/editor' ...@@ -4,6 +4,7 @@ import { IDomEditor } from '@wangeditor/editor'
import { treeData, treeRef, treeSelectedKeys } from '../constants/tree' import { treeData, treeRef, treeSelectedKeys } from '../constants/tree'
import { dropdownConfig, editorRef, editorHtml } from '../constants' import { dropdownConfig, editorRef, editorHtml } from '../constants'
import { getUUID } from '@/utils' import { getUUID } from '@/utils'
import { showCompare } from '../constants/compare'
export const handleCreated = (editor: IDomEditor) => { export const handleCreated = (editor: IDomEditor) => {
editorRef.value = editor editorRef.value = editor
...@@ -92,3 +93,7 @@ export const uploadXml = async () => { ...@@ -92,3 +93,7 @@ export const uploadXml = async () => {
input.remove() input.remove()
}) })
} }
//xml对比
export const compareXml = () => {
showCompare.value = true
}
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
<div class="flex-1"> <div class="flex-1">
<Toolbar :editor="editorRef" editorId="wangeEditor-1" class="border-b border-solid border-borderColor" /> <Toolbar :editor="editorRef" editorId="wangeEditor-1" class="border-b border-solid border-borderColor" />
</div> </div>
<n-button @click="uploadXml" class="h-full">上传XML</n-button> <n-space class="bg-baseColor">
<n-button @click="uploadXml" class="h-full">上传XML</n-button>
<n-button @click="compareXml" class="h-full">XML对比</n-button>
</n-space>
</div> </div>
<!-- 编辑器 --> <!-- 编辑器 -->
<div class="p-[15px] flex flex-1 overflow-hidden"> <div class="p-[15px] flex flex-1 overflow-hidden">
...@@ -34,6 +37,7 @@ ...@@ -34,6 +37,7 @@
/> />
</n-card> </n-card>
</div> </div>
<Compare />
</div> </div>
</template> </template>
...@@ -45,8 +49,9 @@ import renderElemConf from '@/configs/render-elem' ...@@ -45,8 +49,9 @@ import renderElemConf from '@/configs/render-elem'
import elemToHtmlConf from '@/configs/elem-to-html' import elemToHtmlConf from '@/configs/elem-to-html'
import parseHtmlConf from '@/configs/parse-elem-html' import parseHtmlConf from '@/configs/parse-elem-html'
import { dropdownConfig, editorRef, editorHtml } from './constants/' import { dropdownConfig, editorRef, editorHtml } from './constants/'
import { handleChange, handleClick, handleContextMenu, handleCreated, handleSelect, onClickoutside, uploadXml } from './functions/' import { handleChange, handleClick, handleContextMenu, handleCreated, handleSelect, onClickoutside, uploadXml, compareXml } from './functions/'
import Tree from './components/Tree.vue' import Tree from './components/Tree.vue'
import Compare from './components/Compare.vue'
const module: Partial<IModuleConf> = { const module: Partial<IModuleConf> = {
renderElems: renderElemConf, renderElems: renderElemConf,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment