zydx-plus 1.35.583 → 1.35.585

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zydx-plus",
3
- "version": "1.35.583",
3
+ "version": "1.35.585",
4
4
  "description": "Vue.js",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -64,14 +64,6 @@
64
64
  <span>AI助手</span>
65
65
  </div>
66
66
  </div>
67
- <!-- <div class="editor-but">
68
- <div class="editor-but-name">
69
- <label>
70
- <input type="file" @change="uploadDoc($event)" accept=".docx" style="display: none;">
71
- <span>上传文档</span>
72
- </label>
73
- </div>
74
- </div>-->
75
67
  </div>
76
68
  <zydx-chat v-model='isShowAi'></zydx-chat>
77
69
  <div :class="[{'editor-content-show': !editableShow}, `editor-content-${refSrc}`]" class="editor-content">
@@ -80,24 +72,50 @@
80
72
  <img :src="menusData('signMenu')?.ico" alt=""/>
81
73
  <span>{{ menusData('signMenu')?.text }}</span>
82
74
  </div>
83
- <editor-content ref="editing-cont" :editor="editor" class="editing-cont" @click.stop="editorContentClick"
75
+ <editor-content ref="editing-cont" id="editingC" :editor="editor" class="editing-cont"
76
+ @click.stop="editorContentClick"
84
77
  @paste.native.capture.prevent="preventPaste"></editor-content>
78
+ <div v-if="imageStyle.width !== '0px'" class="border-img" :style="imageStyle"></div>
85
79
  <div class="menu">
86
- <button v-if="readOnly" class="but" @click="enlSee">查看附件</button>
87
- <button v-if="readOnly" class="but" @click="enlDownload">下载附件</button>
88
- <button v-if="!readOnly" class="but" @click="enlDel">删除附件</button>
80
+ <button v-if="readOnly" class="but-ed" @click="enlSee">查看附件</button>
81
+ <button v-if="readOnly" class="but-ed" @click="enlDownload">下载附件</button>
82
+ <button v-if="!readOnly" class="but-ed" @click="enlDel">删除附件</button>
83
+ </div>
84
+ <div v-show="imgMenuShow" @click.stop="false" class="img-menu" :style="{transform: `translate(${menuTransform}%, 0)`}">
85
+ <div class="img-menu-head">
86
+ <span>图片设置</span>
87
+ </div>
88
+ <div class="img-menu-list">
89
+ <div class="img-menu-item">
90
+ <span>图片缩放:</span>
91
+ <div class="img-menu-input">
92
+ <input type="text" v-model="imgSizeVal" @input="changePercent" placeholder="0-100"/>
93
+ <i>%</i>
94
+ </div>
95
+ </div>
96
+ <div class="img-menu-item">
97
+ <span>图片位置:</span>
98
+ <div class="select-input">
99
+ <select v-model="selectValue" placeholder="选择图片位置">
100
+ <option disabled selected value>选择图片位置</option>
101
+ <option :value="item.value" v-for="item in selectOptions">{{ item.label }}</option>
102
+ </select>
103
+ <!-- <zydxSelect v-model:value="selectValue" :options="selectOptions" placeholder="选择图片位置"></zydxSelect>-->
104
+ </div>
105
+ </div>
106
+ </div>
89
107
  </div>
90
108
  </div>
91
109
  </div>
92
110
 
93
111
  <div v-if="!readOnly && toolbar.length > 0 && butShow" class="complete">
94
- <button v-if="butShow" class="but" @click="confirm">完成</button>
112
+ <button v-if="butShow" class="but-ed" @click="confirm">完成</button>
95
113
  </div>
96
114
 
97
115
  <div v-if="menus&&readOnly" :style="menusStyle" class="menus">
98
- <button v-if="readOnly" class="but" @click="enlSee">查看附件</button>
99
- <button v-if="readOnly" class="but" @click="enlDownload">下载附件</button>
100
- <button v-if="!readOnly" class="but" @click="enlDel">删除附件</button>
116
+ <button v-if="readOnly" class="but-ed" @click="enlSee">查看附件</button>
117
+ <button v-if="readOnly" class="but-ed" @click="enlDownload">下载附件</button>
118
+ <button v-if="!readOnly" class="but-ed" @click="enlDel">删除附件</button>
101
119
  </div>
102
120
 
103
121
  <div v-if="menuOne&&readOnly" ref="bubbleMenuReadOnly" :style="menusStyle" class="menu-one">
@@ -110,7 +128,7 @@
110
128
  </span>
111
129
  </div>
112
130
  <div class="menu-one-but">
113
- <button v-if="bubbleData&&uploadTypeArr.indexOf(bubbleData.type)!==-1 " class="but" @click="isShowFile=true">
131
+ <button v-if="bubbleData&&uploadTypeArr.indexOf(bubbleData.type)!==-1 " class="but-ed" @click="isShowFile=true">
114
132
  <viewSvg style="margin-right: 5px"></viewSvg>
115
133
  查看
116
134
  </button>
@@ -135,8 +153,8 @@
135
153
  <p>{{ imgTitle }}:</p>
136
154
  <input v-model="imgUrl" type="text"/>
137
155
  <div class="img-but">
138
- <button class="but" @click="imgConfirm">确认</button>
139
- <button class="but" @click="imgCancel">取消</button>
156
+ <button class="but-ed" @click="imgConfirm">确认</button>
157
+ <button class="but-ed" @click="imgCancel">取消</button>
140
158
  </div>
141
159
  </div>
142
160
 
@@ -356,7 +374,7 @@
356
374
  </template>
357
375
  </zydx-drag-popup>
358
376
 
359
- <div ref="bubbleMenu" :style="menusStyle" class="menu-one">
377
+ <div :style="menusStyle" class="menu-one">
360
378
  <div v-if="bubbleData&&bubbleData.type === 'taggingMenu'" class="menu-one-title">
361
379
  {{ bubbleData.exegesis }}
362
380
  </div>
@@ -371,16 +389,16 @@
371
389
  </span>
372
390
  </div>
373
391
  <div v-if="!readOnly" class="menu-one-but">
374
- <button v-if="bubbleData&&uploadTypeArr.indexOf(bubbleData.type)!==-1 " class="but"
392
+ <button v-if="bubbleData&&uploadTypeArr.indexOf(bubbleData.type)!==-1 " class="but-ed"
375
393
  @click="isShowFile=true">
376
394
  <viewSvg style="margin-right: 5px"></viewSvg>
377
395
  查看
378
396
  </button>
379
- <button v-else class="but" @click="editAnnotatedLiterature(bubbleData)">
397
+ <button v-else class="but-ed" @click="editAnnotatedLiterature(bubbleData)">
380
398
  <editSvg style="margin-right: 5px"></editSvg>
381
399
  修改
382
400
  </button>
383
- <button class="but" @click="delAnnotatedLiterature(bubbleData.id,bubbleData.type)">
401
+ <button class="but-ed" @click="delAnnotatedLiterature(bubbleData.id,bubbleData.type)">
384
402
  <delSvg style="margin-right: 5px"></delSvg>
385
403
  删除
386
404
  </button>
@@ -571,29 +589,6 @@
571
589
  </zydx-drag-popup>
572
590
  </div>
573
591
 
574
-
575
- <!-- 链接注释-->
576
- <!-- <zydx-drag-popup v-if="isShowUpload" :dragStatus="false" :width="400"
577
- :enlargeShow="false" :minimize="false" :height="200"
578
- :minimizeCir="false" :title="'上传附件'" @close="isShowUpload=false">
579
- <template #content>
580
- <div class="upload-box">
581
- <div class="check-upload">
582
- <label>
583
- <input type="checkbox" v-model="checkboxObj.value" :checked="checkboxObj.checked" @change="checkboxTao(checkboxObj)"/>
584
- <span>{{ checkboxObj.label }}</span>
585
- </label>
586
- </div>
587
- <div >
588
- <label style="border:1px solid #000;border-radius: 3px;padding:2px 5px;">
589
- <input :accept="acceptType['group-upload']" style="display: none;" type="file" @change="upload($event,'group-upload')">
590
- <span v-html="'上传附件'"></span>
591
- </label>
592
- </div>
593
- </div>
594
- </template>
595
- </zydx-drag-popup>-->
596
-
597
592
  </div>
598
593
  <Paint v-if="paintShow" :uploadImage="uploadImage" :url="uploadImage?.url" title="插入白板" @cancel="paintCancel"
599
594
  @exportImg="exportImg"></Paint>
@@ -607,8 +602,8 @@ import {Editor, EditorContent} from '@tiptap/vue-3'
607
602
  import StarterKit from '@tiptap/starter-kit'
608
603
  import Placeholder from '@tiptap/extension-placeholder'
609
604
  import Paragraph from '@tiptap/extension-paragraph'
610
- import TextStyle from '@tiptap/extension-text-style'
611
- import Images from '@tiptap/extension-image'
605
+ import { TextStyle } from '@tiptap/extension-text-style'
606
+ import { FontSize } from "./extend/font-size";
612
607
  import TextAlign from '@tiptap/extension-text-align'
613
608
  import Color from '@tiptap/extension-color'
614
609
  import FontFamily from "@tiptap/extension-font-family";
@@ -617,7 +612,6 @@ import Underline from "@tiptap/extension-underline";
617
612
  import HorizontalRule from "@tiptap/extension-horizontal-rule";
618
613
  import BubbleMenu from '@tiptap/extension-bubble-menu'
619
614
  import Link from "@tiptap/extension-link";
620
- import {FontSize} from "./extend/font-size";
621
615
  import {Margin} from "./extend/margin";
622
616
  import {borderBottom} from "./extend/insertHorizontalLine";
623
617
  import {signId} from "./extend/sign-id";
@@ -626,6 +620,7 @@ import {Contenteditable} from "./extend/contenteditable";
626
620
  import {Highlight} from "@tiptap/extension-highlight";
627
621
  import {titleId} from "./extend/title-id";
628
622
  import {dataUrl} from "./extend/data-url";
623
+ import Images from './extend/extension-image'
629
624
  import Mess from '../../tipBox/index'
630
625
  import svgs from "../../editor2/src/level.vue";
631
626
  import delSvg from "./delete-svg.vue";
@@ -647,11 +642,14 @@ import MarginWide from "../src/margin-wide.vue";
647
642
  import isSelect from "../src/isSelect.vue";
648
643
  import Paint from '../../paint/src/paint'
649
644
  import zydxChat from '../../chat/src/chat.vue'
645
+ import Select from "@/App.vue";
650
646
 
651
647
  const img = require('./image/annotation.png')
648
+
652
649
  export default {
653
650
  name: 'zydx-editor',
654
651
  components: {
652
+ Select,
655
653
  isSelect,
656
654
  MarginWide,
657
655
  MarginStandard,
@@ -665,7 +663,10 @@ export default {
665
663
  zydxDragPopup,
666
664
  zydxSelect,
667
665
  zydxChat,
668
- delSvg, editSvg, viewSvg, Paint
666
+ delSvg,
667
+ editSvg,
668
+ viewSvg,
669
+ Paint,
669
670
  },
670
671
  beforeUnmount() {
671
672
  this.editor.destroy()
@@ -676,7 +677,26 @@ export default {
676
677
  },
677
678
  data() {
678
679
  return {
680
+ menuTransform: 0,
681
+ debounceTimer: null,
682
+ selectValue: '',
683
+ selectOptions: [
684
+ {label: "居左", value: 'left'},
685
+ {label: "居中", value: 'center'},
686
+ {label: "居右", value: 'right'},
687
+ {label: "左侧嵌入", value: 'alignLeft'},
688
+ {label: "右侧嵌入", value: 'alignRight'},
689
+ ],
690
+ imgSizeVal: '',
679
691
  paintShow: false,
692
+ imgMenuShow: false,
693
+ imageStyle: {
694
+ width: '0px',
695
+ height: '0px',
696
+ top: '0px',
697
+ left: '0px'
698
+ },
699
+ imageEl: null,
680
700
  pageMarginSvg: [
681
701
  {
682
702
  iconName: 'MarginStandard',
@@ -938,25 +958,6 @@ export default {
938
958
  // 插入附件到编辑器
939
959
  insertFn(fileName, 'http://192.168.5.213:8888' + filePath)
940
960
  },
941
- // 用户自定义上传
942
- // customUpload(file, insertFn) {
943
- //
944
- // return new Promise(resolve => {
945
- // // 插入一个文件,模拟异步
946
- // setTimeout(() => {
947
- // const src = 'https://www.w3school.com.cn/i/movie.ogg'
948
- // insertFn('名字', 'http://192.168.5.213:8888')
949
- // resolve('ok')
950
- // }, 500)
951
- // })
952
- // },
953
-
954
- // 自定义选择
955
- // customBrowseAndUpload(insertFn) {
956
- // // 自己上传文件
957
- // insertFn(fileName, link)
958
- // },
959
- // 插入到编辑器后的回调
960
961
 
961
962
  onInsertedAttachment(elem) {
962
963
  console.log('回调', elem)
@@ -974,27 +975,45 @@ export default {
974
975
  },
975
976
  },
976
977
  watch: {
978
+ imgSizeVal: {
979
+ handler: function (e) {
980
+ if (this.debounceTimer) {
981
+ clearTimeout(this.debounceTimer);
982
+ }
983
+ // 设置新的定时器,延迟 500ms 执行处理逻辑
984
+ this.debounceTimer = setTimeout(() => {
985
+ if(Number(e) > 0) this.editor.commands.updateAttributes('image', {width: Number(e) + '%'})
986
+ }, 500);
987
+ },
988
+ deep: true
989
+ },
990
+ selectValue: {
991
+ handler: function (v) {
992
+ if(v === '') return
993
+ if(['left','center','right'].includes(v)) {
994
+ this.editor.commands.updateAttributes('image', {align: ''})
995
+ this.editor.chain().focus().setTextAlign(v).run()
996
+ }else {
997
+ this.editor.commands.updateAttributes('image', {align: v === 'alignLeft'? 'left': 'right'})
998
+ }
999
+ },
1000
+ deep: true
1001
+ },
977
1002
  html: {
978
1003
  handler: function (e, oldVal) {
979
1004
  this.init = false
980
1005
  if (e && e.sign?.tag === 'sign') {
981
1006
  this.signMenuShow = true
982
- // e.shift()
983
1007
  }
984
1008
  this.htmlJson = e ? JSON.parse(JSON.stringify(e)) : []
985
1009
  let dataHtml = this.htmlJson.editorJson
986
- // this.editor?.commands.setContent(json2html({node: "root", child: (e === undefined || e === null) ? [] : e}))
987
1010
  this.editor?.commands.setContent(dataHtml)
988
1011
  if (this.readOnly) {
989
- // lxq 25.7.14
990
- // if (this.page) this.editableShow = true
991
- // setTimeout(() => {
992
- if (this.page) {
993
- this.editableShow = false
994
- console.log('editableShow',this.editableShow)
995
- this.readOnlyPage()
996
- }
997
- // }, 300)
1012
+ if (this.page) {
1013
+ this.editableShow = false
1014
+ console.log('editableShow', this.editableShow)
1015
+ this.readOnlyPage()
1016
+ }
998
1017
  }
999
1018
  setTimeout(() => {
1000
1019
  this.init = true
@@ -1007,33 +1026,26 @@ export default {
1007
1026
  },
1008
1027
  readOnly: {
1009
1028
  handler: function (e) {
1010
- // lxq 25.7.14
1011
- // let time = setInterval(() => {
1012
- if (this.editor) { // 没有时间以后 停止定时器
1013
- this.editor.setOptions({editable: !e})
1014
- if (this.page) {
1015
- // setTimeout(() => {
1016
- this.editableShow = !e
1017
- if (e) {
1018
- console.log('readOnlyPage',e)
1019
- this.readOnlyPage() // 只读分页
1020
- }
1021
- // }, 300)
1029
+ if (this.editor) { // 没有时间以后 停止定时器
1030
+ this.editor.setOptions({editable: !e})
1031
+ if (this.page) {
1032
+ this.editableShow = !e
1033
+ if (e) {
1034
+ console.log('readOnlyPage', e)
1035
+ this.readOnlyPage() // 只读分页
1022
1036
  }
1023
- // clearInterval(time) //停止计时器,清除定时器
1024
1037
  }
1025
- // }, 10)
1038
+ }
1026
1039
  },
1027
1040
  deep: true,
1028
1041
  immediate: true
1029
1042
  },
1030
- /*menusText: {
1031
- handler: function () {
1032
- this.organizeButton()
1033
- },
1034
- deep: true,
1035
- immediate: true
1036
- }*/
1043
+ },
1044
+ beforeDestroy() {
1045
+ // 组件销毁前清除定时器,避免内存泄漏
1046
+ if (this.debounceTimer) {
1047
+ clearTimeout(this.debounceTimer);
1048
+ }
1037
1049
  },
1038
1050
  mounted() {
1039
1051
  const _this = this
@@ -1105,7 +1117,41 @@ export default {
1105
1117
  contenteditable: false,
1106
1118
  }
1107
1119
  }),
1108
- BubbleMenu.configure({ // 气泡菜单
1120
+ BubbleMenu.configure({
1121
+ pluginKey: 'imgMenu',
1122
+ element: document.querySelector('.img-menu'),
1123
+ tippyOptions: {
1124
+ placement: 'right-start',
1125
+ },
1126
+ shouldShow: ({editor, view, state, oldState, from, to}) => {
1127
+ const img = editor.isActive('image')
1128
+ const selection = state.selection.$from.parent.attrs
1129
+ const ids = selection?.lineHeightId?.split(' ')
1130
+ if (ids && img) {
1131
+ this.imageStyle.width = view.dom.children[0].children[0].offsetWidth - 5 + 'px'
1132
+ this.imageStyle.height = view.dom.children[0].children[0].offsetHeight - 5 + 'px'
1133
+ this.imageStyle.top = view.dom.offsetTop + 2 + 'px'
1134
+ this.imageStyle.left = view.dom.offsetLeft + 2 + view.dom.children[0].children[0].offsetLeft + 'px'
1135
+ // 获取图片宽度百分比
1136
+ const attWidth = state.selection.node? state.selection.node.attrs.width : 100
1137
+ const width = attWidth ? parseInt(attWidth) : 100
1138
+ this.menuTransform = width > 90 ? -80 : 0
1139
+ _this.imgSizeVal = ''
1140
+ _this.selectValue = ''
1141
+ const imgContState = !!ids.includes('imgCont')
1142
+ _this.imgMenuShow = imgContState
1143
+ return imgContState
1144
+ } else {
1145
+ this.imageStyle.width = '0px'
1146
+ this.imageStyle.height = '0px'
1147
+ this.imageStyle.top = '0px'
1148
+ this.imageStyle.left = '0px'
1149
+ _this.imgMenuShow = false
1150
+ return false
1151
+ }
1152
+ },
1153
+ }),
1154
+ BubbleMenu.configure({
1109
1155
  pluginKey: 'bubbleMenu',
1110
1156
  element: document.querySelector('.menu'),
1111
1157
  tippyOptions: {
@@ -1137,10 +1183,7 @@ export default {
1137
1183
  name = item.type.name
1138
1184
  }
1139
1185
  })
1140
- // if(name==='underline'){
1141
- // _this.exegesisType = "check"
1142
- // }
1143
- return false // nameArr.indexOf(name) !== -1
1186
+ return false
1144
1187
  } else {
1145
1188
  return false
1146
1189
  }
@@ -1262,6 +1305,14 @@ export default {
1262
1305
  }
1263
1306
  }
1264
1307
  _this.$emit('changeOutlineMenu', _this.changeOutlineMenu())
1308
+ // 关闭气泡菜单
1309
+ if(_this.imgMenuShow) {
1310
+ this.imageStyle.width = '0px'
1311
+ this.imageStyle.height = '0px'
1312
+ this.imageStyle.top = '0px'
1313
+ this.imageStyle.left = '0px'
1314
+ _this.imgMenuShow = false
1315
+ }
1265
1316
  },
1266
1317
  onTransaction: () => {
1267
1318
  const index = _this.editor.state.selection.$anchor.path[1]
@@ -1330,14 +1381,44 @@ export default {
1330
1381
  this.y = event.clientY - this.top;
1331
1382
  })
1332
1383
  this.templateType = this.htmlJson.templateType
1333
- // this.changeTemplateType()
1334
- // document.addEventListener('click', () => {
1335
- // // if(this.limits) return
1336
- // // this.close()
1337
- // })
1338
1384
  },
1339
1385
  emits: ['confirm', 'enclosure', 'enlDownload', 'enlSee', 'changeOutlineMenu', 'getConfirm'],
1340
1386
  methods: {
1387
+ changePercent(e) {
1388
+ e.stopPropagation()
1389
+ // 1. 先过滤非数字字符
1390
+ this.imgSizeVal = this.imgSizeVal.replace(/[^\d]/g, '');
1391
+ // 2. 去除前导零(如输入"0012"转为"12",但保留"0")
1392
+ if (this.imgSizeVal.length > 1 && this.imgSizeVal[0] === '0') {
1393
+ this.imgSizeVal = this.imgSizeVal.replace(/^0+/, '');
1394
+ // 若去除后为空(如"000"),则保留一个0
1395
+ if (this.imgSizeVal === '') this.imgSizeVal = '0';
1396
+ }
1397
+ // 3. 限制数值范围在0-100之间
1398
+ const value = parseInt(this.imgSizeVal, 10);
1399
+ if (value > 100) {
1400
+ this.imgSizeVal = '100';
1401
+ } else if (value < 0) { // 理论上不会触发,因已过滤非数字
1402
+ this.imgSizeVal = '0';
1403
+ }
1404
+ },
1405
+ debounce(func, delay) {
1406
+ let timer = null; // 用于存储定时器的变量
1407
+ // 返回一个新函数,作为防抖处理后的函数
1408
+ return function (...args) {
1409
+ // 每次触发事件时,先清除之前的定时器
1410
+ if (timer) {
1411
+ clearTimeout(timer);
1412
+ }
1413
+ // 重新设置定时器,延迟执行目标函数
1414
+ timer = setTimeout(() => {
1415
+ // 通过 apply 确保目标函数的 this 指向正确,并传递参数
1416
+ func.apply(this, args);
1417
+ // 执行后清空定时器(非必需,但可减少内存占用)
1418
+ timer = null;
1419
+ }, delay);
1420
+ };
1421
+ },
1341
1422
  showAi() {
1342
1423
  this.isShowAi = !this.isShowAi
1343
1424
  },
@@ -1378,58 +1459,6 @@ export default {
1378
1459
  },
1379
1460
  //修改模板类型
1380
1461
  async changeTemplateType() {
1381
- /*const oldFormatWriteNewFormat = (oldJson) => {
1382
- let newJson = this.editor.getJSON()
1383
- if (oldJson.content.length === 1 && !oldJson.content[0].content) {
1384
- return
1385
- }
1386
- let oldContent = []
1387
- let signIdArrObj = {
1388
- bookLayout:['text', 'paragraph', 'date', 'subject'],
1389
- officialDocumentFormat: ['red', 'text', 'paragraph', 'date', 'subject'],
1390
- newsFormat: ['text', 'paragraph', 'date', 'subject', 'author'],
1391
- paperFormat: ['text', 'paragraph', 'date', 'subject', 'author']
1392
- }
1393
- let signIdArr = signIdArrObj[this.templateType]
1394
- let newSignIdIndex = -1
1395
- let remainIndex = 0
1396
- for (let i = 0; i < oldJson.content.length; i++) {
1397
- let item = oldJson.content[i]
1398
- if (signIdArr.indexOf(item.attrs.signId) !== -1 || (!!item.attrs.signId && item.attrs.signId.indexOf('title') !== -1)) {
1399
- item.reserve = true
1400
- for (let j = 0; j < newJson.content.length; j++) {
1401
- let newItem = newJson.content[j]
1402
- if (newItem.attrs.signId && item.attrs.signId && item.attrs.signId === newItem.attrs.signId && newSignIdIndex < j) {
1403
- newJson.content[j] = JSON.parse(JSON.stringify(item))
1404
- if(item.attrs.signId==='red'){
1405
- newJson.content[j-1] = JSON.parse(JSON.stringify(oldJson.content[i-1]))
1406
- }
1407
- delete newJson.content[j].reserve
1408
- item.reserve = false
1409
- if (newJson.content[j].attrs.signId === 'subject' && this.templateType === 'officialDocumentFormat') {
1410
- newJson.content[j].attrs.margin = '80px 0 60px'
1411
- } else {
1412
- newJson.content[j].attrs.margin = null
1413
- }
1414
- newSignIdIndex = j
1415
- break
1416
- } else {
1417
- let arr = ['paragraph', 'date']
1418
- if (newSignIdIndex >= 0 && arr.indexOf(newJson.content[newSignIdIndex].attrs.signId) === -1) {
1419
- // 内容有意义但无法替换如新样板,位置起点留存
1420
- remainIndex = newSignIdIndex
1421
- }
1422
- }
1423
- }
1424
- }
1425
- }
1426
- oldContent = oldJson.content.filter(item => item.reserve)
1427
- oldContent.forEach((item, index) => {
1428
- delete item.reserve
1429
- newJson.content.splice(remainIndex + index + 1, 0, item)
1430
- })
1431
- this.editor.chain().setContent(newJson).run()
1432
- }*/
1433
1462
  const htmlFormat = butJson(this.editor, this.menusText)['switchingFormat'].menuKeys
1434
1463
  let oldJson = this.editor.getJSON()
1435
1464
  // 自由排版
@@ -1938,10 +1967,20 @@ export default {
1938
1967
  // 粘贴文本处理
1939
1968
  preventPaste(event) {
1940
1969
  // 删除选中的文本
1970
+ // this.editor.chain().focus().deleteSelection().run()
1971
+ // const text = event.clipboardData.getData('text/plain');
1972
+ // const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
1973
+ // this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
1941
1974
  this.editor.chain().focus().deleteSelection().run()
1942
1975
  const text = event.clipboardData.getData('text/plain');
1943
- const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
1944
- this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
1976
+ const textArr = text.split(/[\r\n]/g)
1977
+ textArr.forEach((item,index) => {
1978
+ if(index === 0) {
1979
+ this.editor.chain().focus().insertContentAt(this.selection(), item).run()
1980
+ }else {
1981
+ this.editor.chain().focus().insertContentAt(this.selection(), `<p>${item}</p>`).run()
1982
+ }
1983
+ })
1945
1984
  },
1946
1985
 
1947
1986
  editorContentClick() {
@@ -2015,7 +2054,7 @@ export default {
2015
2054
  enlSee() {
2016
2055
  this.$emit('enlSee', this.encIndex)
2017
2056
  let id = this.encIndex.signId.split('u-').join('')
2018
- console.log('interpositionData',this.interpositionData);
2057
+ console.log('interpositionData', this.interpositionData);
2019
2058
  this.interpositionData.forEach(item => {
2020
2059
  if (item.id === id) {
2021
2060
  item.isShow = true
@@ -2346,45 +2385,7 @@ export default {
2346
2385
  }
2347
2386
  })
2348
2387
  }
2349
- // bubbleMenu = this.$refs.bubbleMenuReadOnly.getBoundingClientRect()
2350
- }
2351
- //确定注释在编译器的左半还是右半
2352
- /*let styleKey = 'left'
2353
- let positionNum = `-${bubbleMenu.width / 2}px`
2354
- let menusStyle = {
2355
- 'max-width': `${width - 20}px`,
2356
- position: 'absolute',
2357
- 'text-indent': bubbleMenu.width === width ? '2em' : '0em',
2358
- top: this.readOnly ? `${e.clientY - only.top + 10}px` : `${30}px`,
2359
- }
2360
- if (this.readOnly) {
2361
- const left = e.clientX - only.left - (bubbleMenu.width / 2)
2362
- const right = (only.left + only.width) - (e.clientX + (bubbleMenu.width / 2))
2363
- positionNum = `${left}px`
2364
- if (right <= 0) {
2365
- styleKey = 'right'
2366
- positionNum = '30px'
2367
- }
2368
- if (left <= 0) {
2369
- styleKey = 'left'
2370
- positionNum = '30px'
2371
- }
2372
- } else {
2373
- if (only.left + (only.width / 2) < e.clientX) {
2374
- styleKey = 'right'
2375
- if ((e.clientX + (bubbleMenu.width / 2)) > (only.left + only.width - marginRight - 10)) {
2376
- let difference = Math.floor((e.clientX + (bubbleMenu.width / 2)) - (only.left + only.width - marginRight - 10))
2377
- positionNum = `-${(bubbleMenu.width / 2) - difference - 10}px`
2378
- }
2379
- } else {
2380
- if ((e.clientX - (bubbleMenu.width / 2)) < (only.left + 10 + marginLeft)) {
2381
- let difference = Math.floor((only.left + marginLeft + 10) - (e.clientX - (bubbleMenu.width / 2)))
2382
- positionNum = `-${(bubbleMenu.width / 2) - difference - 10}px`
2383
- }
2384
- }
2385
2388
  }
2386
- menusStyle[`${styleKey}`] = positionNum
2387
- this.menusStyle = menusStyle*/
2388
2389
  })
2389
2390
  }
2390
2391
  for (let i = 0; i < p1.length; i++) {
@@ -2595,7 +2596,7 @@ export default {
2595
2596
  fileName: name,
2596
2597
  url: url
2597
2598
  }
2598
- console.log('11111',dataInfo)
2599
+ console.log('11111', dataInfo)
2599
2600
  //linkCourseware
2600
2601
  if (v === 'linkCourseware') {
2601
2602
  let officeInfo = this.getOffice
@@ -2682,42 +2683,13 @@ export default {
2682
2683
  }
2683
2684
  this.interpositionData.push(dataInfo)
2684
2685
  this.documentClick()
2685
- // return
2686
- // }
2687
- /*const num1 = this.upSort(this.editor, 'reference')
2688
- if (t === -1) this.editor.chain().focus().insertContentAt(num1.len - 7, html).run()
2689
- const num = this.upSort(this.editor, 'enclosure')
2690
- const id = new Date().getTime()
2691
- let dataInfo = {
2692
- isShow: false,
2693
- edit: false,
2694
- id: `${id}`,
2695
- type: v,
2696
- exegesis: this.tipTitle,
2697
- fileName: name,
2698
- url: url
2699
- }
2700
- const html2 = `<p contenteditable="false" data-signId="u-${id}" data-url="${url}" class="indent mu"><span>${num.num}. ${name}</span></p>`
2701
- this.editor.chain().focus().insertContentAt(num.len, html2).run()
2702
- const json = this.editor.getJSON()
2703
- for (let i = 0; i < json.content.length; i++) {
2704
- const item = json.content[i]
2705
- if (item.attrs.signId === 'enclosure' && item.content[0].text === '附件列表:') {
2706
- item.attrs.titleId = this.checkbox ? 'indent' : null
2707
- }
2708
- }
2709
- this.editor.chain().setContent(<p></p>).run()
2710
- this.editor.chain().setContent(json).run()
2711
- this.isShowUpload = false
2712
- this.interpositionData.push(dataInfo)
2713
- this.documentClick()*/
2714
2686
  })
2715
2687
  }
2716
2688
  if (v === 'uploadImage') {
2717
2689
  up.customInsert(res, (data) => {
2718
2690
  setTimeout(() => {
2719
2691
  const cla = this.randomId()
2720
- const html = `<p class="imgCont ${cla}"><img src="${data}" alt="" /></p>`
2692
+ const html = `<p contenteditable="false" class="imgCont ${cla}"><img src="${data}" alt="" /></p>`
2721
2693
  this.editor.chain().focus().insertContentAt(this.selection(), html).run()
2722
2694
  if (this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
2723
2695
  if (this.selectionClass(cla)) {
@@ -2813,7 +2785,7 @@ export default {
2813
2785
  if (this.imgUrl === '') return
2814
2786
  if (this.imgPopType === 'insertImage') {
2815
2787
  const cla = this.randomId()
2816
- const html = `<p class="imgCont ${cla}"><img src="${this.imgUrl}" alt="" /></p>`
2788
+ const html = `<p contenteditable="false" class="imgCont ${cla}"><img src="${this.imgUrl}" alt="" /></p>`
2817
2789
  this.editor.chain().focus().insertContentAt(this.selection(), html).run()
2818
2790
  if (this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
2819
2791
  if (this.selectionClass(cla)) {
@@ -3023,6 +2995,11 @@ export default {
3023
2995
  },
3024
2996
 
3025
2997
  async butTap(data, key, childKey) {
2998
+ // 边距
2999
+ if (data.key === 'pageMargin') {
3000
+ this.isShowPageMargin = true
3001
+ this.menuStast = 'pageMargin'
3002
+ }
3026
3003
  // 标志
3027
3004
  if (data.key === 'signMenu') this.signMenuShow = !this.signMenuShow
3028
3005
  if (!key.key) return
@@ -3189,69 +3166,6 @@ export default {
3189
3166
  if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3190
3167
  return
3191
3168
  }
3192
- // 添加落款
3193
- /*if (key.key === 'paragraphMenu') {
3194
- const html = menusHtml.filter(item => item.key == key.key)[0].html
3195
- const last = this.editor.state.selection.$anchor.path[0].content.size
3196
- const r = await this.signIdData('paragraph')//落款
3197
- const b = await this.signIdData('ack')//致谢
3198
- const n = await this.signIdData('enclosure')//附件
3199
- const a = await this.signIdData('reference')//参考文献
3200
- if (b === -1) {
3201
- if (n === -1) {
3202
- if (a === -1) {
3203
- if (r === -1) this.editor.chain().focus().insertContentAt(last, html).run()
3204
- return
3205
- }
3206
- const num = this.selectionPath('reference')
3207
- if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3208
- return
3209
- }
3210
- const num = this.selectionPath('enclosure')
3211
- if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3212
- return
3213
- }
3214
- const num = this.upSort(this.editor, 'ack')
3215
- if (r === -1) this.editor.chain().focus().insertContentAt(num.len - 3, html).run()
3216
- }*/
3217
- // 致谢
3218
- /* if (key.key === 'ackMenu') {
3219
- const html = menusHtml.filter(item => item.key == key.key)[0].html
3220
- const last = this.editor.state.selection.$anchor.path[0].content.size
3221
- const r = await this.signIdData('ack')
3222
- const b = await this.signIdData('enclosure')//附件
3223
- const a = await this.signIdData('reference')//参考文献
3224
- if (b === -1) {
3225
- if (a === -1) {
3226
- if (r === -1) {
3227
- this.editor.chain().focus().insertContentAt(last, html[0]).run()
3228
- this.editor.chain().focus().insertContentAt(last + 3, html[1]).run()
3229
- }
3230
- return
3231
- }
3232
- const num = this.upSort(this.editor, 'reference')
3233
- if (r === -1) {
3234
- this.editor.chain().focus().insertContentAt(num.len - 7, html[0]).run()
3235
- this.editor.chain().focus().insertContentAt(num.len - 3, html[1]).run()
3236
- }
3237
- return
3238
- }
3239
- const num = this.selectionPath('enclosure')
3240
- if (r === -1) {
3241
- this.editor.chain().focus().insertContentAt(num - 7, html[0]).run()
3242
- const ackNum = this.selectionPath('ack')
3243
- this.editor.chain().focus().insertContentAt(ackNum, html[1]).run()
3244
- }
3245
-
3246
- // if(a===-1){
3247
- // if (r === -1) {
3248
- // this.editor.chain().focus().insertContentAt(last, html[0]).run()
3249
- // this.editor.chain().focus().insertContentAt(last + 3, html[1]).run()
3250
- // }
3251
- // }else {
3252
- // // if (r === -1) this.editor.chain().focus().insertContentAt(num.len - 3, html).run()
3253
- // }
3254
- }*/
3255
3169
  }
3256
3170
  // 红头文件
3257
3171
  if (data.key === 'redMenu') {
@@ -3323,13 +3237,7 @@ export default {
3323
3237
  if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3324
3238
  return
3325
3239
  }
3326
-
3327
3240
  if (data.key === 'textMenu' && key === 0 || data.key === 'titleMenu' && key === 0) return
3328
- // 边距
3329
- if (data.key === 'pageMargin') {
3330
- this.isShowPageMargin = true
3331
- this.menuStast = 'pageMargin'
3332
- }
3333
3241
  // 段落
3334
3242
  if (data.key === 'paragraph') {
3335
3243
  this.menuStast = 'paragraph'
@@ -3595,7 +3503,7 @@ export default {
3595
3503
  }
3596
3504
  // 添加图片
3597
3505
  if (key.key === 'group-image') {
3598
- if (childKey.key === 'insertImage') {
3506
+ if (childKey?.key === 'insertImage') {
3599
3507
  this.imgUrl = ''
3600
3508
  this.imgPop = true
3601
3509
  this.imgTitle = '图片地址'
@@ -4388,8 +4296,85 @@ export default {
4388
4296
  }
4389
4297
  }
4390
4298
  </script>
4391
-
4392
4299
  <style scoped>
4300
+ .img-menu {
4301
+ width: 180px;
4302
+ overflow: hidden;
4303
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
4304
+ border-radius: 3px;
4305
+ background-color: #fff;
4306
+ }
4307
+
4308
+ .img-menu-head {
4309
+ width: 100%;
4310
+ height: 24px;
4311
+ background-color: rgba(75, 12, 119, 1);
4312
+ color: #fff;
4313
+ font-size: 12px;
4314
+ line-height: 24px;
4315
+ padding: 0 5px;
4316
+ }
4317
+
4318
+ .img-menu-list {
4319
+ padding: 0 5px;
4320
+ background-color: #fff;
4321
+ }
4322
+
4323
+ .img-menu-item {
4324
+ display: flex;
4325
+ margin: 5px 0;
4326
+ }
4327
+
4328
+ .img-menu-item > span {
4329
+ display: inline-block;
4330
+ width: 60px;
4331
+ line-height: 24px;
4332
+ font-size: 12px;
4333
+ }
4334
+
4335
+ .img-menu-input {
4336
+ width: calc(100% - 60px);
4337
+ position: relative;
4338
+ }
4339
+
4340
+ .img-menu-input > input {
4341
+ width: 100%;
4342
+ border-radius: 3px;
4343
+ border: 1px solid rgba(204, 204, 204, 1);
4344
+ height: 24px;
4345
+ box-sizing: border-box;
4346
+ padding-left: 5px;
4347
+ }
4348
+
4349
+ .select-input {
4350
+ width: 110px;
4351
+ height: 24px;
4352
+ }
4353
+
4354
+ .select-input :deep(input) {
4355
+ height: 24px;
4356
+ padding: 0 25px 0 5px;
4357
+ font-size: 12px;;
4358
+ }
4359
+
4360
+ .select-input select {
4361
+ width: 110px;
4362
+ height: 24px;
4363
+ font-size: 12px;
4364
+ border: 1px solid #ccc;
4365
+ border-radius: 3px
4366
+ }
4367
+
4368
+ .img-menu-input > input {
4369
+ padding-right: 20px;
4370
+ }
4371
+
4372
+ .img-menu-input > i {
4373
+ position: absolute;
4374
+ top: 2px;
4375
+ right: 5px;
4376
+ font-size: 12px;
4377
+ }
4393
4378
 
4394
4379
  :deep(.ProseMirror-separator) {
4395
4380
  display: none !important;
@@ -4537,7 +4522,7 @@ label {
4537
4522
  text-align: right;
4538
4523
  }
4539
4524
 
4540
- .but {
4525
+ .but-ed {
4541
4526
  margin-left: 1px;
4542
4527
  font-size: 12px;
4543
4528
  background-color: transparent;
@@ -4547,6 +4532,7 @@ label {
4547
4532
  cursor: pointer;
4548
4533
  min-width: 60px;
4549
4534
  height: 21px;
4535
+ line-height: 19px;
4550
4536
  }
4551
4537
 
4552
4538
  .editing-header {
@@ -4580,7 +4566,7 @@ label {
4580
4566
  width: 100%;
4581
4567
  }
4582
4568
 
4583
- :deep(.ProseMirror) p.is-editor-empty:first-child::before {
4569
+ :deep(.ProseMirror) p.is-empty::before {
4584
4570
  content: attr(data-placeholder);
4585
4571
  float: left;
4586
4572
  color: #adb5bd;
@@ -4601,7 +4587,7 @@ label {
4601
4587
  }
4602
4588
 
4603
4589
  .editing-cont :deep(img) {
4604
- padding: 5px 0;
4590
+ padding: 5px;
4605
4591
  }
4606
4592
 
4607
4593
  li {
@@ -4878,7 +4864,7 @@ li {
4878
4864
  justify-content: flex-end;
4879
4865
  }
4880
4866
 
4881
- .menu-one-but > .but {
4867
+ .menu-one-but > .but-ed {
4882
4868
  border: none;
4883
4869
  font-size: 12px;
4884
4870
  display: flex;
@@ -5313,4 +5299,9 @@ li {
5313
5299
  font-size: 14px;
5314
5300
  color: #000000;
5315
5301
  }
5302
+ .border-img{
5303
+ border: 3px solid #6F3D92;
5304
+ position: absolute;
5305
+ z-index: 1;
5306
+ }
5316
5307
  </style>
@@ -0,0 +1,86 @@
1
+ import { Node, mergeAttributes, nodeInputRule } from '@tiptap/core';
2
+
3
+ /**
4
+ * Matches an image to a ![image](src "title") on input.
5
+ */
6
+ const inputRegex = /(?:^|\s)(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/;
7
+ /**
8
+ * This extension allows you to insert images.
9
+ * @see https://www.tiptap.dev/api/nodes/image
10
+ */
11
+ const ExtensionImage = Node.create({
12
+ name: 'image',
13
+ addOptions() {
14
+ return {
15
+ inline: false,
16
+ allowBase64: false,
17
+ HTMLAttributes: {},
18
+ };
19
+ },
20
+ inline() {
21
+ return this.options.inline;
22
+ },
23
+ group() {
24
+ return this.options.inline ? 'inline' : 'block';
25
+ },
26
+ draggable: true,
27
+ addAttributes() {
28
+ return {
29
+ src: {
30
+ default: null,
31
+ },
32
+ alt: {
33
+ default: null,
34
+ },
35
+ title: {
36
+ default: null,
37
+ },
38
+ align: {
39
+ default: null,
40
+ },
41
+ width: {
42
+ default: null,
43
+ },
44
+ height: {
45
+ default: null,
46
+ }
47
+ };
48
+ },
49
+ parseHTML() {
50
+ return [
51
+ {
52
+ tag: this.options.allowBase64
53
+ ? 'img[src]'
54
+ : 'img[src]:not([src^="data:"])',
55
+ },
56
+ ];
57
+ },
58
+ renderHTML({ HTMLAttributes }) {
59
+ return ['img', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
60
+ },
61
+ addCommands() {
62
+ return {
63
+ setImage: options => ({ commands }) => {
64
+ return commands.insertContent({
65
+ type: this.name,
66
+ attrs: options,
67
+ });
68
+ },
69
+ };
70
+ },
71
+ addInputRules() {
72
+ return [
73
+ nodeInputRule({
74
+ find: inputRegex,
75
+ type: this.type,
76
+ getAttributes: match => {
77
+ const [, , alt, src, title, align, width, height] = match;
78
+ return { src, alt, title, align, width, height };
79
+ },
80
+ }),
81
+ ];
82
+ },
83
+ });
84
+
85
+ export { ExtensionImage, ExtensionImage as default, inputRegex };
86
+ //# sourceMappingURL=extension-image.js.map
@@ -1051,21 +1051,25 @@ export default {
1051
1051
  .editor :deep(h1) {
1052
1052
  line-height: 24px;
1053
1053
  font-size: 18px;
1054
+ text-align: justify;
1054
1055
  }
1055
1056
 
1056
1057
  .editor :deep(h2) {
1057
1058
  line-height: 24px;
1058
1059
  font-size: 16px;
1060
+ text-align: justify;
1059
1061
  }
1060
1062
 
1061
1063
  .editor :deep(h3) {
1062
1064
  line-height: 24px;
1063
1065
  font-size: 14px;
1066
+ text-align: justify;
1064
1067
  }
1065
1068
 
1066
1069
  .editor :deep(p) {
1067
1070
  font-size: 14px;
1068
1071
  line-height: 24px;
1072
+ text-align: justify;
1069
1073
  }
1070
1074
 
1071
1075
  :deep(.ProseMirror) p.is-editor-empty:first-child::before {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <onClickOutSide :target="dropdown" :handler="handler">
3
- <div class="wrapper">
3
+ <div class="wrapper" ref="selectRef">
4
4
  <div class="custom-select"
5
5
  :class="{ 'readonly': readonly }">
6
6
  <input type="text"
@@ -10,12 +10,12 @@
10
10
  @click.stop="toggleDropDown"
11
11
  class="select-css" />
12
12
 
13
- <span class="custom-select-icons" v-if="!readonly">
13
+ <span class="custom-select-icons" v-if="!readonly" @click.stop="toggleDropDown">
14
14
  <svg xmlns="http://www.w3.org/2000/svg"
15
15
  width="16"
16
16
  height="16"
17
17
  viewBox="0 0 24 24">
18
- <g :transform="transform">
18
+ <g :transform="transform" >
19
19
  <path fill="#c0c4cc"
20
20
  d="M15.125 21.1L6.7 12.7q-.15-.15-.213-.325T6.425 12q0-.2.062-.375T6.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L9.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z" />
21
21
  </g>
@@ -89,9 +89,10 @@ export default defineComponent({
89
89
  width: 0
90
90
  }
91
91
  },
92
+ emits: ['update:value', 'select'],
92
93
  methods: {
93
- toggleDropDown: function (e) {
94
- const { x, y, width, height } = e.target.getBoundingClientRect()
94
+ toggleDropDown: function () {
95
+ const { x, y, width, height } = this.$refs.selectRef.getBoundingClientRect()
95
96
  this.x = x
96
97
  this.y = y + height
97
98
  this.width = width
@@ -142,7 +143,8 @@ export default defineComponent({
142
143
  const { label } = this.options.find(option => option.value === v) || { label: '' }
143
144
  this.selected = label
144
145
  },
145
- immediate: true
146
+ immediate: true,
147
+ deep: true
146
148
  }
147
149
  }
148
150
  })
package/src/index.js CHANGED
@@ -89,7 +89,7 @@ function install(app) {
89
89
  }
90
90
 
91
91
  export default {
92
- version: '1.35.583',
92
+ version: '1.35.585',
93
93
  install,
94
94
  Calendar,
95
95
  Message,