| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- <template>
- <transition name="fade">
- <div class="markdown-preview-wrapper" v-show="visible" @click.self="closeMarkdownPreview">
- <!-- 顶部信息栏 & 工具栏 -->
- <div class="tip-wrapper" v-if="visible">
- <div class="name" :title="getFileNameComplete(fileInfo)">
- {{ getFileNameComplete(fileInfo) }}
- <span class="un-save" v-show="isModify">(未保存)</span>
- </div>
- <div class="editor-preveiw">在线预览{{ editable ? ' & 编辑' : '' }}</div>
- <div class="tool-wrapper">
- <a
- class="item download-link"
- target="_blank"
- :href="getDownloadFilePath(fileInfo)"
- :download="getFileNameComplete(fileInfo)"
- >
- <download-outlined title="下载" />
- </a>
- <a-tooltip placement="bottom">
- <template #title>
- <div>
- 1. 点击文档以外的区域可退出查看<br />
- 2. 按 Esc 键可退出查看
- </div>
- </template>
- <div class="item text-wrapper">
- <span class="text">操作提示</span>
- <bulb-outlined />
- </div>
- </a-tooltip>
- <close-outlined class="item" title="关闭预览" @click="closeMarkdownPreview" />
- </div>
- </div>
- <!-- mavon-editor 组件,配置项说明文档 https://www.npmjs.com/package/mavon-editor -->
- <a-spin :spinning="markdownLoading">
- <mavonEditor
- ref="mavonEditorRef"
- v-model="markdownText"
- :toolbars="toolbars"
- :editable="editable"
- :toolbarsFlag="toolbarsFlag"
- :externalLink="externalLink"
- :subfield="screenWidth > 768 ? true : false"
- defaultOpen="preview"
- @save="handleModifyFileContent"
- ></mavonEditor>
- </a-spin>
- </div>
- </transition>
- </template>
- <script setup>
- import { ref, computed, watch, nextTick, getCurrentInstance } from 'vue'
- import { mavonEditor } from 'mavon-editor'
- import 'mavon-editor/dist/css/index.css'
- // 代码高亮样式表
- import '@/assets/mavonEditor/css/tomorrow-night.css'
- import '@/assets/mavonEditor/css/github-markdown.css'
- import { useMyResourceStore } from '@/store/myResource.js'
- import { getFilePreview, modifyFileContent } from '@/api/myResource/file.js'
- import { DownloadOutlined, BulbOutlined, CloseOutlined } from '@ant-design/icons-vue'
- import tool from '@/utils/tool'
- // 获取全局变量
- const { proxy } = getCurrentInstance()
- // 获取store
- const myResourceStore = useMyResourceStore()
- // 定义props
- const props = defineProps({
- fileInfo: Object,
- editable: Boolean,
- callback: Function
- })
- // 从proxy中获取$file方法
- const getFileNameComplete = (fileInfo) => {
- return proxy.$file.getFileNameComplete(fileInfo)
- }
- const getDownloadFilePath = (fileInfo) => {
- return proxy.$file.getDownloadFilePath(fileInfo)
- }
- // 响应式数据
- const visible = ref(false)
- const originalMarkdownText = ref('')
- const markdownText = ref('')
- const markdownLoading = ref(false)
- // 暴露visible属性给父组件
- defineExpose({ visible })
- // 工具栏配置
- const toolbars = {
- bold: true, // 粗体
- italic: true, // 斜体
- header: true, // 标题
- underline: true, // 下划线
- strikethrough: true, // 中划线
- mark: true, // 标记
- superscript: true, // 上角标
- subscript: true, // 下角标
- quote: true, // 引用
- ol: true, // 有序列表
- ul: true, // 无序列表
- link: true, // 链接
- imagelink: true, // 图片链接
- code: true, // code
- table: true, // 表格
- fullscreen: true, // 全屏编辑
- readmodel: true, // 沉浸式阅读
- htmlcode: true, // 展示html源码
- help: true, // 帮助
- /* 1.3.5 */
- undo: true, // 上一步
- redo: true, // 下一步
- trash: true, // 清空
- save: true, // 保存(触发 events 中的 save 事件)
- /* 1.4.2 */
- navigation: true, // 导航目录
- /* 2.1.8 */
- aligncenter: true, // 居中
- alignleft: true, // 左对齐
- alignright: true, // 右对齐
- /* 2.2.1 */
- subfield: true, // 单双栏模式
- preview: true // 预览
- }
- // 计算属性
- // 屏幕宽度
- const screenWidth = computed(() => {
- return myResourceStore.screenWidth
- })
- // 是否修改
- const isModify = computed(() => {
- return originalMarkdownText.value !== markdownText.value
- })
- // 外链 cdn 改为本地引入
- const externalLink = computed(() => {
- let context = process.env.NODE_ENV === 'production' ? '/' : '/'
- return {
- markdown_css: function () {
- // 这是你的markdown css文件路径
- return `${context}mavonEditor/css/github-markdown.css`
- },
- hljs_js: function () {
- // 这是你的hljs文件路径
- return `${context}mavonEditor/js/highlight.min.js`
- },
- hljs_css: function () {
- // 这是你的代码高亮配色文件路径
- return `${context}mavonEditor/css/tomorrow-night.css`
- },
- hljs_lang: function () {
- // 这是你的代码高亮语言解析路径
- return `${context}mavonEditor/js/lang.hljs.js`
- },
- katex_css: function () {
- // 这是你的katex配色方案路径路径
- return `${context}mavonEditor/css/katex.min.css`
- },
- katex_js: function () {
- // 这是你的katex.js路径
- return `${context}mavonEditor/js/katex.min.js`
- }
- }
- })
- // 工具栏是否展示
- const toolbarsFlag = computed(() => {
- return props.editable
- })
- // 监听 markdown 查看组件 显隐状态变化
- watch(visible, (val) => {
- if (val) {
- getMarkdownText()
- // 添加键盘 Esc 事件
- nextTick(() => {
- document.addEventListener('keyup', handleKeyup)
- })
- } else {
- document.removeEventListener('keyup', handleKeyup)
- }
- })
- // 键盘事件处理函数
- const handleKeyup = (e) => {
- if (e.key === 'Escape') {
- closeMarkdownPreview()
- }
- }
- /**
- * 获取 markdown 文本内容
- */
- const getMarkdownText = () => {
- markdownLoading.value = true
- getFilePreview({
- userFileId: props.fileInfo.userFileId,
- isMin: false,
- shareBatchNum: props.fileInfo.shareBatchNum,
- extractionCode: props.fileInfo.extractionCode,
- token: tool.data.get('TOKEN')
- }).then((res) => {
- markdownLoading.value = false
- originalMarkdownText.value = res
- markdownText.value = res
- })
- }
- /**
- * 修改 markdown 文本内容
- */
- const handleModifyFileContent = () => {
- markdownLoading.value = true
- modifyFileContent({
- userFileId: props.fileInfo.userFileId,
- fileContent: markdownText.value
- })
- .then((res) => {
- markdownLoading.value = false
- if (res.success) {
- proxy.$message.success('已保存')
- getMarkdownText()
- } else {
- proxy.$message.error(res.message)
- }
- })
- .catch((err) => {
- markdownLoading.value = false
- proxy.$message.error(err.message)
- })
- }
- /**
- * 关闭 markdown 预览
- */
- const closeMarkdownPreview = () => {
- visible.value = false
- props.callback('cancel')
- }
- </script>
- <style lang="less" scoped>
- @import '@/style/myResource/varibles.less';
- .markdown-preview-wrapper {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- overflow: auto;
- width: 100%;
- height: 100vh;
- z-index: 2;
- text-align: center;
- display: flex;
- align-items: center;
- animation: imgPreviewAnimation 0.3s;
- -webkit-animation: imgPreviewAnimation 0.3s; /* Safari and Chrome */
- animation-iteration-count: 0.3;
- -webkit-animation-iteration-count: 0.3;
- animation-fill-mode: forwards;
- -webkit-animation-fill-mode: forwards; /* Safari 和 Chrome */
- @keyframes imgPreviewAnimation {
- 0% {
- background: transparent;
- }
- 100% {
- background: rgba(0, 0, 0, 0.8);
- }
- }
- @keyframes imgPreviewAnimation {
- 0% {
- background: transparent;
- }
- 100% {
- background: rgba(0, 0, 0, 0.8);
- }
- }
- .tip-wrapper {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 2;
- background: rgba(0, 0, 0, 0.5);
- padding: 0 48px;
- width: 100%;
- height: 48px;
- line-height: 48px;
- color: #fff;
- font-size: 16px;
- display: flex;
- justify-content: space-between;
- .name {
- flex: 1;
- padding-right: 16px;
- text-align: left;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- .un-save {
- color: @Warning;
- font-size: 14px;
- }
- }
- .tool-wrapper {
- flex: 1;
- display: flex;
- justify-content: flex-end;
- .item {
- margin-left: 16px;
- height: 48px;
- line-height: 48px;
- cursor: pointer;
- &:hover {
- opacity: 0.7;
- }
- }
- .save-img {
- margin: 16px 0;
- width: 16px;
- height: 16px;
- }
- .download-link {
- color: inherit;
- font-size: 18px;
- }
- .text-wrapper {
- .text {
- margin-right: 8px;
- }
- }
- }
- }
- :deep(.v-note-wrapper) {
- box-shadow: none !important;
- border: 1px solid @border-base;
- .v-note-op {
- border-bottom-color: @border-base;
- .op-image {
- .dropdown-item:nth-of-type(2) {
- display: none;
- }
- }
- }
- .v-note-navigation-wrapper {
- .v-note-navigation-content {
- h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- color: @primary-text;
- &:hover {
- color: @primary-text;
- }
- }
- }
- }
- }
- :deep(.v-note-wrapper:not(.fullscreen)) {
- margin: 56px auto 0 auto;
- width: 90vw;
- height: calc(100vh - 80px);
- }
- }
- </style>
|