zydx-plus 1.35.584 → 1.35.586

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.584",
3
+ "version": "1.35.586",
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,51 @@ 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
+ if(!state.selection.node) {
1132
+ this.imageStyle.width = '0px'
1133
+ this.imageStyle.height = '0px'
1134
+ this.imageStyle.top = '0px'
1135
+ this.imageStyle.left = '0px'
1136
+ _this.imgMenuShow = false
1137
+ return false
1138
+ }
1139
+ const imgSrc = state.selection.node.attrs.src;
1140
+ const imgDom = editor.view.dom.querySelector(`img[src="${imgSrc}"]`);
1141
+ this.imageStyle.width = imgDom.offsetWidth + 'px'
1142
+ this.imageStyle.height = imgDom.offsetHeight + 'px'
1143
+ this.imageStyle.top = view.dom.offsetTop + imgDom.offsetTop + 'px'
1144
+ this.imageStyle.left = view.dom.offsetLeft + imgDom.offsetLeft + 'px'
1145
+ // 获取图片宽度百分比
1146
+ const attWidth = state.selection.node? state.selection.node.attrs.width : 100
1147
+ const width = attWidth ? parseInt(attWidth) : 100
1148
+ this.menuTransform = width > 90 ? -80 : 0
1149
+ _this.imgSizeVal = ''
1150
+ _this.selectValue = ''
1151
+ const imgContState = !!ids.includes('imgCont')
1152
+ _this.imgMenuShow = imgContState
1153
+ return imgContState
1154
+ } else {
1155
+ this.imageStyle.width = '0px'
1156
+ this.imageStyle.height = '0px'
1157
+ this.imageStyle.top = '0px'
1158
+ this.imageStyle.left = '0px'
1159
+ _this.imgMenuShow = false
1160
+ return false
1161
+ }
1162
+ },
1163
+ }),
1164
+ BubbleMenu.configure({
1109
1165
  pluginKey: 'bubbleMenu',
1110
1166
  element: document.querySelector('.menu'),
1111
1167
  tippyOptions: {
@@ -1137,10 +1193,7 @@ export default {
1137
1193
  name = item.type.name
1138
1194
  }
1139
1195
  })
1140
- // if(name==='underline'){
1141
- // _this.exegesisType = "check"
1142
- // }
1143
- return false // nameArr.indexOf(name) !== -1
1196
+ return false
1144
1197
  } else {
1145
1198
  return false
1146
1199
  }
@@ -1262,6 +1315,14 @@ export default {
1262
1315
  }
1263
1316
  }
1264
1317
  _this.$emit('changeOutlineMenu', _this.changeOutlineMenu())
1318
+ // 关闭气泡菜单
1319
+ if(_this.imgMenuShow) {
1320
+ this.imageStyle.width = '0px'
1321
+ this.imageStyle.height = '0px'
1322
+ this.imageStyle.top = '0px'
1323
+ this.imageStyle.left = '0px'
1324
+ _this.imgMenuShow = false
1325
+ }
1265
1326
  },
1266
1327
  onTransaction: () => {
1267
1328
  const index = _this.editor.state.selection.$anchor.path[1]
@@ -1330,14 +1391,44 @@ export default {
1330
1391
  this.y = event.clientY - this.top;
1331
1392
  })
1332
1393
  this.templateType = this.htmlJson.templateType
1333
- // this.changeTemplateType()
1334
- // document.addEventListener('click', () => {
1335
- // // if(this.limits) return
1336
- // // this.close()
1337
- // })
1338
1394
  },
1339
1395
  emits: ['confirm', 'enclosure', 'enlDownload', 'enlSee', 'changeOutlineMenu', 'getConfirm'],
1340
1396
  methods: {
1397
+ changePercent(e) {
1398
+ e.stopPropagation()
1399
+ // 1. 先过滤非数字字符
1400
+ this.imgSizeVal = this.imgSizeVal.replace(/[^\d]/g, '');
1401
+ // 2. 去除前导零(如输入"0012"转为"12",但保留"0")
1402
+ if (this.imgSizeVal.length > 1 && this.imgSizeVal[0] === '0') {
1403
+ this.imgSizeVal = this.imgSizeVal.replace(/^0+/, '');
1404
+ // 若去除后为空(如"000"),则保留一个0
1405
+ if (this.imgSizeVal === '') this.imgSizeVal = '0';
1406
+ }
1407
+ // 3. 限制数值范围在0-100之间
1408
+ const value = parseInt(this.imgSizeVal, 10);
1409
+ if (value > 100) {
1410
+ this.imgSizeVal = '100';
1411
+ } else if (value < 0) { // 理论上不会触发,因已过滤非数字
1412
+ this.imgSizeVal = '0';
1413
+ }
1414
+ },
1415
+ debounce(func, delay) {
1416
+ let timer = null; // 用于存储定时器的变量
1417
+ // 返回一个新函数,作为防抖处理后的函数
1418
+ return function (...args) {
1419
+ // 每次触发事件时,先清除之前的定时器
1420
+ if (timer) {
1421
+ clearTimeout(timer);
1422
+ }
1423
+ // 重新设置定时器,延迟执行目标函数
1424
+ timer = setTimeout(() => {
1425
+ // 通过 apply 确保目标函数的 this 指向正确,并传递参数
1426
+ func.apply(this, args);
1427
+ // 执行后清空定时器(非必需,但可减少内存占用)
1428
+ timer = null;
1429
+ }, delay);
1430
+ };
1431
+ },
1341
1432
  showAi() {
1342
1433
  this.isShowAi = !this.isShowAi
1343
1434
  },
@@ -1378,58 +1469,6 @@ export default {
1378
1469
  },
1379
1470
  //修改模板类型
1380
1471
  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
1472
  const htmlFormat = butJson(this.editor, this.menusText)['switchingFormat'].menuKeys
1434
1473
  let oldJson = this.editor.getJSON()
1435
1474
  // 自由排版
@@ -1938,10 +1977,20 @@ export default {
1938
1977
  // 粘贴文本处理
1939
1978
  preventPaste(event) {
1940
1979
  // 删除选中的文本
1980
+ // this.editor.chain().focus().deleteSelection().run()
1981
+ // const text = event.clipboardData.getData('text/plain');
1982
+ // const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
1983
+ // this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
1941
1984
  this.editor.chain().focus().deleteSelection().run()
1942
1985
  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()
1986
+ const textArr = text.split(/[\r\n]/g)
1987
+ textArr.forEach((item,index) => {
1988
+ if(index === 0) {
1989
+ this.editor.chain().focus().insertContentAt(this.selection(), item).run()
1990
+ }else {
1991
+ this.editor.chain().focus().insertContentAt(this.selection(), `<p>${item}</p>`).run()
1992
+ }
1993
+ })
1945
1994
  },
1946
1995
 
1947
1996
  editorContentClick() {
@@ -2015,7 +2064,7 @@ export default {
2015
2064
  enlSee() {
2016
2065
  this.$emit('enlSee', this.encIndex)
2017
2066
  let id = this.encIndex.signId.split('u-').join('')
2018
- console.log('interpositionData',this.interpositionData);
2067
+ console.log('interpositionData', this.interpositionData);
2019
2068
  this.interpositionData.forEach(item => {
2020
2069
  if (item.id === id) {
2021
2070
  item.isShow = true
@@ -2346,45 +2395,7 @@ export default {
2346
2395
  }
2347
2396
  })
2348
2397
  }
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
2398
  }
2386
- menusStyle[`${styleKey}`] = positionNum
2387
- this.menusStyle = menusStyle*/
2388
2399
  })
2389
2400
  }
2390
2401
  for (let i = 0; i < p1.length; i++) {
@@ -2489,15 +2500,6 @@ export default {
2489
2500
  if (this.signMenuShow) {
2490
2501
  data.sign = sign
2491
2502
  }
2492
- // data.push(this.editor.getJSON())
2493
- // if (this.signMenuShow) {
2494
- // data.unshift({
2495
- // node: 'element',
2496
- // tag: 'sign',
2497
- // child: []
2498
- // })
2499
- // }
2500
- // data.push({type: 'interpositionData', data: [...this.interpositionData]})
2501
2503
  this.$emit('confirm', data)
2502
2504
  },
2503
2505
  getConfirm() {
@@ -2514,19 +2516,6 @@ export default {
2514
2516
  if (this.signMenuShow) {
2515
2517
  data.sign = sign
2516
2518
  }
2517
- // let data = []
2518
- // data.push(this.editor.getJSON())
2519
- // if (this.signMenuShow) {
2520
- // data.unshift({
2521
- // node: 'element',
2522
- // tag: 'sign',
2523
- // child: []
2524
- // })
2525
- // }
2526
- // data.push({
2527
- // type: 'interpositionData',
2528
- // data: this.interpositionData
2529
- // })
2530
2519
  return data
2531
2520
  },
2532
2521
  changeOutlineMenu() {
@@ -2595,7 +2584,7 @@ export default {
2595
2584
  fileName: name,
2596
2585
  url: url
2597
2586
  }
2598
- console.log('11111',dataInfo)
2587
+ console.log('11111', dataInfo)
2599
2588
  //linkCourseware
2600
2589
  if (v === 'linkCourseware') {
2601
2590
  let officeInfo = this.getOffice
@@ -2682,35 +2671,6 @@ export default {
2682
2671
  }
2683
2672
  this.interpositionData.push(dataInfo)
2684
2673
  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
2674
  })
2715
2675
  }
2716
2676
  if (v === 'uploadImage') {
@@ -3023,6 +2983,11 @@ export default {
3023
2983
  },
3024
2984
 
3025
2985
  async butTap(data, key, childKey) {
2986
+ // 边距
2987
+ if (data.key === 'pageMargin') {
2988
+ this.isShowPageMargin = true
2989
+ this.menuStast = 'pageMargin'
2990
+ }
3026
2991
  // 标志
3027
2992
  if (data.key === 'signMenu') this.signMenuShow = !this.signMenuShow
3028
2993
  if (!key.key) return
@@ -3189,69 +3154,6 @@ export default {
3189
3154
  if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3190
3155
  return
3191
3156
  }
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
3157
  }
3256
3158
  // 红头文件
3257
3159
  if (data.key === 'redMenu') {
@@ -3323,13 +3225,7 @@ export default {
3323
3225
  if (r === -1) this.editor.chain().focus().insertContentAt(num - 7, html).run()
3324
3226
  return
3325
3227
  }
3326
-
3327
3228
  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
3229
  // 段落
3334
3230
  if (data.key === 'paragraph') {
3335
3231
  this.menuStast = 'paragraph'
@@ -3595,7 +3491,7 @@ export default {
3595
3491
  }
3596
3492
  // 添加图片
3597
3493
  if (key.key === 'group-image') {
3598
- if (childKey.key === 'insertImage') {
3494
+ if (childKey?.key === 'insertImage') {
3599
3495
  this.imgUrl = ''
3600
3496
  this.imgPop = true
3601
3497
  this.imgTitle = '图片地址'
@@ -4388,8 +4284,85 @@ export default {
4388
4284
  }
4389
4285
  }
4390
4286
  </script>
4391
-
4392
4287
  <style scoped>
4288
+ .img-menu {
4289
+ width: 180px;
4290
+ overflow: hidden;
4291
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
4292
+ border-radius: 3px;
4293
+ background-color: #fff;
4294
+ }
4295
+
4296
+ .img-menu-head {
4297
+ width: 100%;
4298
+ height: 24px;
4299
+ background-color: rgba(75, 12, 119, 1);
4300
+ color: #fff;
4301
+ font-size: 12px;
4302
+ line-height: 24px;
4303
+ padding: 0 5px;
4304
+ }
4305
+
4306
+ .img-menu-list {
4307
+ padding: 0 5px;
4308
+ background-color: #fff;
4309
+ }
4310
+
4311
+ .img-menu-item {
4312
+ display: flex;
4313
+ margin: 5px 0;
4314
+ }
4315
+
4316
+ .img-menu-item > span {
4317
+ display: inline-block;
4318
+ width: 60px;
4319
+ line-height: 24px;
4320
+ font-size: 12px;
4321
+ }
4322
+
4323
+ .img-menu-input {
4324
+ width: calc(100% - 60px);
4325
+ position: relative;
4326
+ }
4327
+
4328
+ .img-menu-input > input {
4329
+ width: 100%;
4330
+ border-radius: 3px;
4331
+ border: 1px solid rgba(204, 204, 204, 1);
4332
+ height: 24px;
4333
+ box-sizing: border-box;
4334
+ padding-left: 5px;
4335
+ }
4336
+
4337
+ .select-input {
4338
+ width: 110px;
4339
+ height: 24px;
4340
+ }
4341
+
4342
+ .select-input :deep(input) {
4343
+ height: 24px;
4344
+ padding: 0 25px 0 5px;
4345
+ font-size: 12px;;
4346
+ }
4347
+
4348
+ .select-input select {
4349
+ width: 110px;
4350
+ height: 24px;
4351
+ font-size: 12px;
4352
+ border: 1px solid #ccc;
4353
+ border-radius: 3px
4354
+ }
4355
+
4356
+ .img-menu-input > input {
4357
+ padding-right: 20px;
4358
+ }
4359
+
4360
+ .img-menu-input > i {
4361
+ position: absolute;
4362
+ top: 2px;
4363
+ right: 5px;
4364
+ font-size: 12px;
4365
+ }
4393
4366
 
4394
4367
  :deep(.ProseMirror-separator) {
4395
4368
  display: none !important;
@@ -4537,7 +4510,7 @@ label {
4537
4510
  text-align: right;
4538
4511
  }
4539
4512
 
4540
- .but {
4513
+ .but-ed {
4541
4514
  margin-left: 1px;
4542
4515
  font-size: 12px;
4543
4516
  background-color: transparent;
@@ -4547,6 +4520,7 @@ label {
4547
4520
  cursor: pointer;
4548
4521
  min-width: 60px;
4549
4522
  height: 21px;
4523
+ line-height: 19px;
4550
4524
  }
4551
4525
 
4552
4526
  .editing-header {
@@ -4580,7 +4554,7 @@ label {
4580
4554
  width: 100%;
4581
4555
  }
4582
4556
 
4583
- :deep(.ProseMirror) p.is-editor-empty:first-child::before {
4557
+ :deep(.ProseMirror) p.is-empty::before {
4584
4558
  content: attr(data-placeholder);
4585
4559
  float: left;
4586
4560
  color: #adb5bd;
@@ -4601,7 +4575,7 @@ label {
4601
4575
  }
4602
4576
 
4603
4577
  .editing-cont :deep(img) {
4604
- padding: 5px 0;
4578
+ padding: 3px;
4605
4579
  }
4606
4580
 
4607
4581
  li {
@@ -4878,7 +4852,7 @@ li {
4878
4852
  justify-content: flex-end;
4879
4853
  }
4880
4854
 
4881
- .menu-one-but > .but {
4855
+ .menu-one-but > .but-ed {
4882
4856
  border: none;
4883
4857
  font-size: 12px;
4884
4858
  display: flex;
@@ -5313,4 +5287,9 @@ li {
5313
5287
  font-size: 14px;
5314
5288
  color: #000000;
5315
5289
  }
5290
+ .border-img{
5291
+ border: 3px solid #6F3D92;
5292
+ position: absolute;
5293
+ z-index: 1;
5294
+ }
5316
5295
  </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 {
@@ -89,6 +89,7 @@ export default defineComponent({
89
89
  width: 0
90
90
  }
91
91
  },
92
+ emits: ['update:value', 'select'],
92
93
  methods: {
93
94
  toggleDropDown: function () {
94
95
  const { x, y, width, height } = this.$refs.selectRef.getBoundingClientRect()
@@ -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.584',
92
+ version: '1.35.586',
93
93
  install,
94
94
  Calendar,
95
95
  Message,