zydx-plus 1.32.248 → 1.32.249

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.
@@ -1,587 +1,631 @@
1
1
  <template>
2
- <div :style="heightStyle" class="edit">
3
- <div class="ed-head">
4
- <div class="ed-title" v-if="titleShow" :style="titleStyle" v-html="title"></div>
5
- <div class="ed-but" v-if="readOnly">
6
- <div class="ed-head-but" v-for="(item,index) in toolbar">
7
- <button v-if="item.key === 'but'" class="buts" @click="item.onClick(item,info)" :style="{color: (item.active)? '#00ff00' :'#000'}">{{ item.title }}</button>
8
- <label v-else-if="item.key === 'upImg' || item.key === 'uploadAtt'">
9
- <input type="file" @change="upload($event,item.key)" :accept="(item.key === 'upImg')?'image/*':'.docx,.pptx,.pdf,.xlsx,.mp3,.mp4'" style="display: none;">
10
- <span class="buts">{{ item.title }}</span>
11
- </label>
12
- <button v-else class="buts" @click="toolTap(item.key)">{{ item.title }}</button>
13
- </div>
14
- </div>
2
+ <div :style="heightStyle" class="edit">
3
+ <div class="ed-head">
4
+ <div class="ed-title" v-if="titleShow" :style="titleStyle" v-html="title"></div>
5
+ <div class="ed-but" v-if="readOnly">
6
+ <div class="ed-head-but" v-for="(item,index) in toolbar">
7
+ <button v-if="item.key === 'but'" class="buts" @click="item.onClick(item,info)"
8
+ :style="{color: (item.active)? '#00ff00' :'#000'}">{{ item.title }}
9
+ </button>
10
+ <label v-else-if="item.key === 'upImg' || item.key === 'uploadAtt'">
11
+ <input type="file" @change="upload($event,item.key)"
12
+ :accept="(item.key === 'upImg')?'image/*':'.docx,.pptx,.pdf,.xlsx,.mp3,.mp4'" style="display: none;">
13
+ <span class="buts">{{ item.title }}</span>
14
+ </label>
15
+ <button v-else class="buts" @click="toolTap(item.key)">{{ item.title }}</button>
15
16
  </div>
16
- <div class="ed-cont" :style="heightStyleCont">
17
- <div :style="{'border': (borderShow)? '1px solid #ccc': '0'}" v-if="editorShow">
18
- <editor-content class="editor" :editor="editor" :style="heightStyleCont" />
19
- </div>
20
- <div class="editor-but" v-if="butText !== '' && readOnly">
21
- <button class="buts" @click="complete">{{ butText }}</button>
22
- </div>
23
- <div class="enclosure" v-if="uploadAttData.length > 0 && enclosureShow">
24
- <p :style="enclosureStyle">{{ enclosureText }}</p>
25
- <div class="enclosure-list" v-for="(item,index) in uploadAttData">
26
- <div class="enclosure-item">
27
- <span v-if="item.name">{{ index + 1 }}. {{ item.name }}</span>
28
- <span v-if="item.annexName">{{ index + 1 }}. {{ item.annexName }}</span>
29
- <span v-if="item.fileName">{{ index + 1 }}. {{ item.fileName }}</span>
30
- </div>
31
- <div class="enclosure-item en-but">
32
- <div style="display: inline-block; height: 21px;">
33
- <button class="buts but-f" v-if="!item.name" @click="see(index)">查看</button>
34
- <button class="buts but-f" v-if="!item.name&&downloadShow" @click="download(index)">下载</button>
35
- <button class="buts but-f" v-if="delShow" @click="del(index)">
36
- <span v-if="item.active">删除</span>
37
- <svg v-else xmlns="http://www.w3.org/2000/svg"
38
- width="14"
39
- height="14"
40
- viewBox="0 0 24 24">
41
- <g fill="none"
42
- stroke="black"
43
- stroke-linecap="round"
44
- stroke-width="2">
45
- <path stroke-dasharray="60"
46
- stroke-dashoffset="60"
47
- stroke-opacity=".3"
48
- d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z">
49
- <animate fill="freeze"
50
- attributeName="stroke-dashoffset"
51
- dur="1.3s"
52
- values="60;0" />
53
- </path>
54
- <path stroke-dasharray="15"
55
- stroke-dashoffset="15"
56
- d="M12 3C16.9706 3 21 7.02944 21 12">
57
- <animate fill="freeze"
58
- attributeName="stroke-dashoffset"
59
- dur="0.3s"
60
- values="15;0" />
61
- <animateTransform attributeName="transform"
62
- dur="1.5s"
63
- repeatCount="indefinite"
64
- type="rotate"
65
- values="0 12 12;360 12 12" />
66
- </path>
67
- </g>
68
- </svg>
69
- </button>
70
- </div>
71
- </div>
72
- </div>
17
+ </div>
18
+ </div>
19
+ <div class="ed-cont" :style="heightStyleCont">
20
+ <div :style="{'border': (borderShow)? '1px solid #ccc': '0'}" v-if="editorShow">
21
+ <editor-content ref="editorRef" class="editor" :editor="editor" :style="heightStyleCont"/>
22
+ </div>
23
+ <div class="editor-but" v-if="butText !== '' && readOnly">
24
+ <button class="buts" @click="complete">{{ butText }}</button>
25
+ </div>
26
+ <div class="enclosure" v-if="uploadAttData.length > 0 && enclosureShow">
27
+ <p :style="enclosureStyle">{{ enclosureText }}</p>
28
+ <div class="enclosure-list" v-for="(item,index) in uploadAttData">
29
+ <div class="enclosure-item">
30
+ <span v-if="item.name">{{ index + 1 }}. {{ item.name }}</span>
31
+ <span v-if="item.annexName">{{ index + 1 }}. {{ item.annexName }}</span>
32
+ <span v-if="item.fileName">{{ index + 1 }}. {{ item.fileName }}</span>
33
+ </div>
34
+ <div class="enclosure-item en-but">
35
+ <div style="display: inline-block; height: 21px;">
36
+ <button class="buts but-f" v-if="!item.name" @click="see(index)">查看</button>
37
+ <button class="buts but-f" v-if="!item.name&&downloadShow" @click="download(index)">下载</button>
38
+ <button class="buts but-f" v-if="delShow" @click="del(index)">
39
+ <span v-if="item.active">删除</span>
40
+ <svg v-else xmlns="http://www.w3.org/2000/svg"
41
+ width="14"
42
+ height="14"
43
+ viewBox="0 0 24 24">
44
+ <g fill="none"
45
+ stroke="black"
46
+ stroke-linecap="round"
47
+ stroke-width="2">
48
+ <path stroke-dasharray="60"
49
+ stroke-dashoffset="60"
50
+ stroke-opacity=".3"
51
+ d="M12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3Z">
52
+ <animate fill="freeze"
53
+ attributeName="stroke-dashoffset"
54
+ dur="1.3s"
55
+ values="60;0"/>
56
+ </path>
57
+ <path stroke-dasharray="15"
58
+ stroke-dashoffset="15"
59
+ d="M12 3C16.9706 3 21 7.02944 21 12">
60
+ <animate fill="freeze"
61
+ attributeName="stroke-dashoffset"
62
+ dur="0.3s"
63
+ values="15;0"/>
64
+ <animateTransform attributeName="transform"
65
+ dur="1.5s"
66
+ repeatCount="indefinite"
67
+ type="rotate"
68
+ values="0 12 12;360 12 12"/>
69
+ </path>
70
+ </g>
71
+ </svg>
72
+ </button>
73
73
  </div>
74
+ </div>
74
75
  </div>
76
+ </div>
75
77
  </div>
78
+ </div>
76
79
  </template>
77
80
  <script>
78
- import { html2json, json2html } from 'html2json'
79
- import { Editor, EditorContent } from '@tiptap/vue-3'
81
+ import {html2json, json2html} from 'html2json'
82
+ import {Editor, EditorContent} from '@tiptap/vue-3'
80
83
  import StarterKit from '@tiptap/starter-kit'
81
84
  import Image from '@tiptap/extension-image'
82
85
  import TextAlign from '@tiptap/extension-text-align'
83
86
  import Placeholder from '@tiptap/extension-placeholder'
84
87
  import Color from '@tiptap/extension-color'
85
88
  import textStyle from '@tiptap/extension-text-style'
86
- import { sid } from "./sign-id";
87
- import { FontSize } from "./font-size";
88
- import { titleId } from "./title-id";
89
+ import {sid} from "./sign-id";
90
+ import {FontSize} from "./font-size";
91
+ import {titleId} from "./title-id";
92
+
89
93
  export default {
90
- name: 'zydx-xiao-editor',
91
- components: {
92
- EditorContent
93
- },
94
- data() {
95
- return {
96
- uploadAttData: [],
97
- editor: null,
98
- heightStyle: {},
99
- heightStyleCont: {}
100
- };
101
- },
102
- beforeUnmount() {
103
- this.editor.destroy()
104
- },
105
- props: {
106
- data: {
107
- type: Object,
108
- default: () => {}
109
- },
110
- toolbar: {
111
- type: Array,
112
- default: []
113
- },
114
- title: {
115
- type: String,
116
- default: ''
117
- },
118
- enclosureText: {
119
- type: String,
120
- default: '附件列表:'
121
- },
122
- titleStyle: {
123
- type: Object,
124
- default: {
125
- 'font-size': '16px',
126
- 'font-weight': 'bold',
127
- 'color': '#000'
128
- }
129
- },
130
- enclosureStyle: {
131
- type: Object,
132
- default: {
133
- 'font-size': '16px',
134
- 'font-weight': 'bold',
135
- 'color': '#000'
136
- }
137
- },
138
- readOnly: {
139
- type: Boolean,
140
- default: true
141
- },
142
- butText: {
143
- type: String,
144
- default: ''
145
- },
146
- height: {
147
- type: String,
148
- default: '200px'
149
- },
150
- uploadImage: {
151
- type: Object,
152
- default: {}
153
- },
154
- uploadAttachment: {
155
- type: Object,
156
- default: {}
157
- },
158
- delShow: {
159
- type: Boolean,
160
- default: true
161
- },
162
- titleShow: {
163
- type: Boolean,
164
- default: true
165
- },
166
- uploadType: {
167
- type: Boolean,
168
- default: false
169
- },
170
- info: {
171
- type: String,
172
- default: ''
173
- },
174
- editorShow: {
175
- type: Boolean,
176
- default: true
177
- },
178
- borderShow: {
179
- type: Boolean,
180
- default: true
181
- },
182
- enclosureShow: {
183
- type: Boolean,
184
- default: true
185
- },
186
- downloadShow: {
187
- type: Boolean,
188
- default: true
189
- },
190
- placeholder: {
191
- type: String,
192
- default: '请输入内容'
193
- }
94
+ name: 'zydx-xiao-editor',
95
+ components: {
96
+ EditorContent
97
+ },
98
+ data() {
99
+ return {
100
+ uploadAttData: [],
101
+ editor: null,
102
+ heightStyle: {},
103
+ heightStyleCont: {}
104
+ };
105
+ },
106
+ beforeUnmount() {
107
+ this.editor.destroy()
108
+ },
109
+ props: {
110
+ data: {
111
+ type: Object,
112
+ default: () => {
113
+ }
194
114
  },
195
- emits: ['see','del','complete','update:data','enclosureSuccess','download','updateData'],
196
- watch:{
197
- // 强制监听data变化
198
- data: {
199
- handler: function (e, oldVal) {
200
- this.editor?.commands.setContent(json2html({node: "root",child: (e.html === undefined || null)? [] : e.html}))
201
- this.uploadAttData = (e.enclosure === undefined)? [] : this.enclosureAction(e.enclosure)
202
- },
203
- deep: true
204
- },
205
- readOnly: {
206
- handler: function (e, oldVal) {
207
- this.editor.setOptions({
208
- editable: e
209
- })
210
- },
211
- deep: true
212
- }
115
+ toolbar: {
116
+ type: Array,
117
+ default: []
213
118
  },
214
- mounted() {
215
- let _this = this
216
- this.uploadAttData = (this.data.enclosure === undefined)? [] : this.enclosureAction(this.data.enclosure)
217
- this.heightStyle = (this.height === '100%')? {height: '100%'} : {'min-height': this.height}
218
- const height = this.height.split('px')[0] - 44
219
- this.heightStyleCont = (this.height === '100%')? {height: 'calc(100% - 44px)'} : {'min-height': `${height}px`}
220
- this.editor = new Editor({
221
- content: json2html({node: "root",child: (this.data.html === undefined || null)? [] : this.data.html}),
222
- editable: this.readOnly,
223
- extensions: [
224
- sid,
225
- StarterKit,
226
- textStyle,
227
- FontSize,
228
- titleId,
229
- Color.configure({
230
- types: ['textStyle'],
231
- }),
232
- Placeholder.configure({
233
- placeholder: this.placeholder,
234
- }),
235
- TextAlign.configure({
236
- types: ['heading', 'paragraph'],
237
- }),
238
- Image.configure({
239
- inline: true,
240
- HTMLAttributes: {
241
- class: 'editor-img'
242
- }
243
- }),
244
- ],
245
- onUpdate: ({ editor }) => {
246
- this.$emit('updateData', {
247
- html: html2json(editor.getHTML()).child,
248
- enclosure: this.uploadAttData
249
- })
250
- }
119
+ title: {
120
+ type: String,
121
+ default: ''
122
+ },
123
+ enclosureText: {
124
+ type: String,
125
+ default: '附件列表:'
126
+ },
127
+ titleStyle: {
128
+ type: Object,
129
+ default: {
130
+ 'font-size': '16px',
131
+ 'font-weight': 'bold',
132
+ 'color': '#000'
133
+ }
134
+ },
135
+ enclosureStyle: {
136
+ type: Object,
137
+ default: {
138
+ 'font-size': '16px',
139
+ 'font-weight': 'bold',
140
+ 'color': '#000'
141
+ }
142
+ },
143
+ readOnly: {
144
+ type: Boolean,
145
+ default: true
146
+ },
147
+ butText: {
148
+ type: String,
149
+ default: ''
150
+ },
151
+ height: {
152
+ type: String,
153
+ default: '200px'
154
+ },
155
+ uploadImage: {
156
+ type: Object,
157
+ default: {}
158
+ },
159
+ uploadAttachment: {
160
+ type: Object,
161
+ default: {}
162
+ },
163
+ delShow: {
164
+ type: Boolean,
165
+ default: true
166
+ },
167
+ titleShow: {
168
+ type: Boolean,
169
+ default: true
170
+ },
171
+ uploadType: {
172
+ type: Boolean,
173
+ default: false
174
+ },
175
+ info: {
176
+ type: String,
177
+ default: ''
178
+ },
179
+ editorShow: {
180
+ type: Boolean,
181
+ default: true
182
+ },
183
+ borderShow: {
184
+ type: Boolean,
185
+ default: true
186
+ },
187
+ enclosureShow: {
188
+ type: Boolean,
189
+ default: true
190
+ },
191
+ downloadShow: {
192
+ type: Boolean,
193
+ default: true
194
+ },
195
+ placeholder: {
196
+ type: String,
197
+ default: '请输入内容'
198
+ }
199
+ },
200
+ emits: ['see', 'del', 'complete', 'update:data', 'enclosureSuccess', 'download', 'updateData'],
201
+ watch: {
202
+ // 强制监听data变化
203
+ data: {
204
+ handler: function (e, oldVal) {
205
+ this.editor?.commands.setContent(json2html({node: "root", child: (e.html === undefined || null) ? [] : e.html}))
206
+ this.uploadAttData = (e.enclosure === undefined) ? [] : this.enclosureAction(e.enclosure)
207
+ },
208
+ deep: true
209
+ },
210
+ readOnly: {
211
+ handler: function (e, oldVal) {
212
+ this.editor.setOptions({
213
+ editable: e
251
214
  })
252
- document.addEventListener('keydown', function (e) {
253
- if (e.keyCode === 8 || e.keyCode === 46) {
254
- const sid = _this.editor.state.selection.$anchor.parent.attrs.sid
255
- if(sid === 'prohibit') {
256
- _this.editor.setEditable(false);
257
- setTimeout(() => {
258
- _this.editor.setEditable(true);
259
- }, 0);
260
- }
261
- }
215
+ },
216
+ deep: true
217
+ }
218
+ },
219
+ mounted() {
220
+ let _this = this
221
+ this.uploadAttData = (this.data.enclosure === undefined) ? [] : this.enclosureAction(this.data.enclosure)
222
+ this.heightStyle = (this.height === '100%') ? {height: '100%'} : {'min-height': this.height}
223
+ const height = this.height.split('px')[0] - 44
224
+ this.heightStyleCont = (this.height === '100%') ? {height: 'calc(100% - 44px)'} : {'min-height': `${height}px`}
225
+ this.editor = new Editor({
226
+ content: json2html({node: "root", child: (this.data.html === undefined || null) ? [] : this.data.html}),
227
+ editable: this.readOnly,
228
+ extensions: [
229
+ sid,
230
+ StarterKit,
231
+ textStyle,
232
+ FontSize,
233
+ titleId,
234
+ Color.configure({
235
+ types: ['textStyle'],
236
+ }),
237
+ Placeholder.configure({
238
+ placeholder: this.placeholder,
239
+ }),
240
+ TextAlign.configure({
241
+ types: ['heading', 'paragraph'],
242
+ }),
243
+ Image.configure({
244
+ inline: true,
245
+ HTMLAttributes: {
246
+ class: 'editor-img'
247
+ }
248
+ }),
249
+ ],
250
+ onUpdate: ({editor}) => {
251
+ this.$emit('updateData', {
252
+ html: html2json(editor.getHTML()).child,
253
+ enclosure: this.uploadAttData
262
254
  })
255
+ }
256
+ })
257
+ document.addEventListener('keydown', function (e) {
258
+ if (e.keyCode === 8 || e.keyCode === 46) {
259
+ const sid = _this.editor.state.selection.$anchor.parent.attrs.sid
260
+ if (sid === 'prohibit') {
261
+ _this.editor.setEditable(false);
262
+ setTimeout(() => {
263
+ _this.editor.setEditable(true);
264
+ }, 0);
265
+ }
266
+ }
267
+ })
268
+ // 处理粘贴事件
269
+ this.$refs.editorRef.$el.addEventListener('paste', (event) => {
270
+ event.preventDefault();
271
+ const text = event.clipboardData.getData('text/plain');
272
+ const index = this.editor.state.selection.$anchor.path[1]
273
+ this.editor.chain().focus().insertContentAt(this.selection(), `<p>${text}</p>`).run()
274
+ const json = this.editor.getJSON()
275
+ json.content.splice(index, 1)
276
+ this.editor?.commands.setContent(json)
277
+ })
278
+ },
279
+ methods: {
280
+ enclosureAction(v) {
281
+ return v.map(x => {
282
+ x.active = true
283
+ return x
284
+ })
263
285
  },
264
- methods: {
265
- enclosureAction(v) {
266
- return v.map(x => {
267
- x.active = true
268
- return x
269
- })
270
- },
271
- randomId() { // 生成随机id
272
- const id = Math.random().toString(36).substr(2)
273
- return id.replace(/[0-9]/g, '')
274
- },
275
- del(index) {
276
- if(this.uploadAttData[index].name === undefined) {
277
- this.uploadAttData[index].active = false
278
- this.$emit('del', this.uploadAttData[index], (e) => {
279
- if(e === undefined) {
280
- this.uploadAttData.splice(index, 1)
281
- }else {
282
- if(e) {
283
- this.uploadAttData.splice(index, 1)
284
- }else {
285
- this.uploadAttData[index].active = true
286
- }
287
- }
288
- })
289
- }else {
290
- this.uploadAttData.splice(index, 1)
291
- }
292
- },
293
- see(index) {
294
- this.$emit('see', this.uploadAttData[index])
295
- },
296
- uploadFile(file,data) {
297
- return new Promise((rl,re) => {
298
- const meta = data.meta? Object.keys(data.meta): []
299
- const param = new FormData()
300
- param.append('file', file)
301
- for(let i = 0; i < meta.length; i++) {
302
- param.append(meta[i], data.meta[meta[i]])
303
- }
304
- const xhr = new XMLHttpRequest()
305
- xhr.open('POST', data.server)
306
- const headers = Object.keys(data.headers)
307
- for(let i = 0; i < headers.length; i++) {
308
- xhr.setRequestHeader(headers[i], data.headers[headers[i]])
309
- }
310
- xhr.onreadystatechange = () => {
311
- if(xhr.readyState === 4) {
312
- if(xhr.status === 200) {
313
- rl(JSON.parse(xhr.responseText))
314
- }
315
- }
316
- }
317
- xhr.send(param)
318
- })
319
- },
320
- upload(e,v) { // 上传文件
321
- const file = e.target.files[0]
322
- if(this.uploadType) {
323
- if(v === 'uploadAtt') {
324
- file.active = true
325
- this.uploadAttData.push(file)
326
- this.$emit('updateData', {
327
- html: html2json(this.editor.getHTML()).child,
328
- enclosure: this.uploadAttData
329
- })
330
- }else {
331
- this.uploadFile(file,this.uploadImage).then(r => {
332
- if (r.code === '200') {
333
- this.imgHtml(r.data)
334
- }else {
335
- this.uploadImage.onFailed(r)
336
- }
337
- })
338
- }
339
- }else {
340
- this.uploadFile(file,(v === 'uploadAtt')? this.uploadAttachment: this.uploadImage).then(r => {
341
- if(v === 'uploadAtt') {
342
- r.data.annex.active = true
343
- this.uploadAttData.push(r.data.annex)
344
- this.$emit('enclosureSuccess', r.data.annex)
345
- }else {
346
- this.imgHtml(r.data)
347
- }
348
- })
349
- }
350
- e.target.value = ''
351
- },
352
- imgHtml(data) { // 插入图片
353
- const url = this.uploadImage.url + data
354
- const cla = this.randomId()
355
- const html = `<p class="imgCont ${cla}"><img src="${url}" alt="" /></p>`
356
- this.editor.chain().focus().insertContentAt(this.selection(),html).run()
357
- if(this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
358
- if(this.selectionClass(cla)) {
359
- this.editor.chain().focus().insertContentAt(this.selection(), '<p></p>').run()
360
- }
361
- },
362
- insertContent(v) {
363
- for(let i=0; i< v.length; i++) {
364
- let html = json2html(v[i])
365
- this.editor.chain().focus().insertContentAt(this.selection(),html).run()
366
- }
367
- },
368
- // 查询class
369
- selectionClass(v) {
370
- const json = this.editor.getJSON()
371
- for (let i = 0; i < json.content.length; i++) {
372
- const val = json.content[i].attrs?.titleId?.split(' ')[1]
373
- if (val === v) {
374
- if(json.content[i+1] === undefined) return true
375
- break
376
- }
377
- }
378
- return false
379
- },
380
- selectionClass2(v) {
381
- const json = this.editor.getJSON()
382
- for (let i = 0; i < json.content.length; i++) {
383
- const val = json.content[i].attrs?.titleId?.split(' ')[1]
384
- if (val === v) {
385
- json.content.splice(i - 1, 1)
386
- this.editor?.commands.setContent(json)
387
- break
388
- }
389
- }
390
- },
391
- enclosureContent(v) {
392
- this.uploadAttData = [...this.uploadAttData, ...this.enclosureAction(v)]
393
- },
394
- download(index) {
395
- this.$emit('download', this.uploadAttData[index])
396
- },
397
- selection() {
398
- const { from } = this.editor.state.selection
399
- return from
400
- },
401
- complete() {
402
- if(this.uploadAttData.length > 0) {
403
- this.$emit('complete', {
404
- html: this.getData(),
405
- enclosure: this.uploadAttData
406
- })
407
- }else {
408
- this.$emit('complete', {html: this.getData()})
286
+ randomId() { // 生成随机id
287
+ const id = Math.random().toString(36).substr(2)
288
+ return id.replace(/[0-9]/g, '')
289
+ },
290
+ del(index) {
291
+ if (this.uploadAttData[index].name === undefined) {
292
+ this.uploadAttData[index].active = false
293
+ this.$emit('del', this.uploadAttData[index], (e) => {
294
+ if (e === undefined) {
295
+ this.uploadAttData.splice(index, 1)
296
+ } else {
297
+ if (e) {
298
+ this.uploadAttData.splice(index, 1)
299
+ } else {
300
+ this.uploadAttData[index].active = true
409
301
  }
410
- },
411
- // 获取编辑器内容
412
- getContent(el) {
413
- // 编辑器内容转json
414
- if(this.uploadAttData.length > 0) {
415
- el({
416
- html: this.getData(),
417
- enclosure: this.uploadAttData
418
- })
419
- }else {
420
- el({html: this.getData()})
302
+ }
303
+ })
304
+ } else {
305
+ this.uploadAttData.splice(index, 1)
306
+ }
307
+ },
308
+ see(index) {
309
+ this.$emit('see', this.uploadAttData[index])
310
+ },
311
+ uploadFile(file, data) {
312
+ return new Promise((rl, re) => {
313
+ const meta = data.meta ? Object.keys(data.meta) : []
314
+ const param = new FormData()
315
+ param.append('file', file)
316
+ for (let i = 0; i < meta.length; i++) {
317
+ param.append(meta[i], data.meta[meta[i]])
318
+ }
319
+ const xhr = new XMLHttpRequest()
320
+ xhr.open('POST', data.server)
321
+ const headers = Object.keys(data.headers)
322
+ for (let i = 0; i < headers.length; i++) {
323
+ xhr.setRequestHeader(headers[i], data.headers[headers[i]])
324
+ }
325
+ xhr.onreadystatechange = () => {
326
+ if (xhr.readyState === 4) {
327
+ if (xhr.status === 200) {
328
+ rl(JSON.parse(xhr.responseText))
421
329
  }
422
- },
423
- getData() {
424
- const html = this.editor.getHTML()
425
- const json = html2json(html)
426
- return json.child
427
- },
428
- toolTap(v) {
429
- // 获取当前选中的节点
430
- const { $anchor } = this.editor.state.selection
431
- if($anchor.path[3].attrs.titleId === 'source') return
432
- if(v === 'h1') this.editor.chain().focus().setFontSize('18px').setBold().run()
433
- if(v === 'h2') this.editor.chain().focus().setFontSize('16px').setBold().run()
434
- if(v === 'h3') this.editor.chain().focus().setFontSize('14px').setBold().run()
435
- if(v === 'p') this.editor.chain().focus().setParagraph().setFontSize('14px').unsetBold().run()
436
- if(v === 'bold') this.editor.chain().focus().toggleBold().run()
437
- if(v === 'center' || v === 'left' || v === 'right') this.editor.chain().focus().setTextAlign(v).run()
438
- if(v === 'add') {
439
- let html = this.editor.getHTML()
440
- html += '<p class="source" style="text-align: right;"></p>'
441
- this.editor.commands.setContent(html)
330
+ }
331
+ }
332
+ xhr.send(param)
333
+ })
334
+ },
335
+ upload(e, v) { // 上传文件
336
+ const file = e.target.files[0]
337
+ if (this.uploadType) {
338
+ if (v === 'uploadAtt') {
339
+ file.active = true
340
+ this.uploadAttData.push(file)
341
+ this.$emit('updateData', {
342
+ html: html2json(this.editor.getHTML()).child,
343
+ enclosure: this.uploadAttData
344
+ })
345
+ } else {
346
+ this.uploadFile(file, this.uploadImage).then(r => {
347
+ if (r.code === '200') {
348
+ this.imgHtml(r.data)
349
+ } else {
350
+ this.uploadImage.onFailed(r)
442
351
  }
443
- if(v === 'centerH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('center').run()
444
- if(v === 'leftH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('left').run()
445
- if(v === 'rightH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('right').run()
352
+ })
353
+ }
354
+ } else {
355
+ this.uploadFile(file, (v === 'uploadAtt') ? this.uploadAttachment : this.uploadImage).then(r => {
356
+ if (v === 'uploadAtt') {
357
+ r.data.annex.active = true
358
+ this.uploadAttData.push(r.data.annex)
359
+ this.$emit('enclosureSuccess', r.data.annex)
360
+ } else {
361
+ this.imgHtml(r.data)
362
+ }
363
+ })
364
+ }
365
+ e.target.value = ''
366
+ },
367
+ imgHtml(data) { // 插入图片
368
+ const url = this.uploadImage.url + data
369
+ const cla = this.randomId()
370
+ const html = `<p class="imgCont ${cla}"><img src="${url}" alt="" /></p>`
371
+ this.editor.chain().focus().insertContentAt(this.selection(), html).run()
372
+ if (this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
373
+ if (this.selectionClass(cla)) {
374
+ this.editor.chain().focus().insertContentAt(this.selection(), '<p></p>').run()
375
+ }
376
+ },
377
+ insertContent(v) {
378
+ for (let i = 0; i < v.length; i++) {
379
+ let html = json2html(v[i])
380
+ this.editor.chain().focus().insertContentAt(this.selection(), html).run()
381
+ }
382
+ },
383
+ // 查询class
384
+ selectionClass(v) {
385
+ const json = this.editor.getJSON()
386
+ for (let i = 0; i < json.content.length; i++) {
387
+ const val = json.content[i].attrs?.titleId?.split(' ')[1]
388
+ if (val === v) {
389
+ if (json.content[i + 1] === undefined) return true
390
+ break
391
+ }
392
+ }
393
+ return false
394
+ },
395
+ selectionClass2(v) {
396
+ const json = this.editor.getJSON()
397
+ for (let i = 0; i < json.content.length; i++) {
398
+ const val = json.content[i].attrs?.titleId?.split(' ')[1]
399
+ if (val === v) {
400
+ json.content.splice(i - 1, 1)
401
+ this.editor?.commands.setContent(json)
402
+ break
446
403
  }
404
+ }
405
+ },
406
+ enclosureContent(v) {
407
+ this.uploadAttData = [...this.uploadAttData, ...this.enclosureAction(v)]
408
+ },
409
+ download(index) {
410
+ this.$emit('download', this.uploadAttData[index])
411
+ },
412
+ selection() {
413
+ const {from} = this.editor.state.selection
414
+ return from
415
+ },
416
+ complete() {
417
+ if (this.uploadAttData.length > 0) {
418
+ this.$emit('complete', {
419
+ html: this.getData(),
420
+ enclosure: this.uploadAttData
421
+ })
422
+ } else {
423
+ this.$emit('complete', {html: this.getData()})
424
+ }
425
+ },
426
+ // 获取编辑器内容
427
+ getContent(el) {
428
+ // 编辑器内容转json
429
+ if (this.uploadAttData.length > 0) {
430
+ el({
431
+ html: this.getData(),
432
+ enclosure: this.uploadAttData
433
+ })
434
+ } else {
435
+ el({html: this.getData()})
436
+ }
437
+ },
438
+ getData() {
439
+ const html = this.editor.getHTML()
440
+ const json = html2json(html)
441
+ return json.child
442
+ },
443
+ toolTap(v) {
444
+ // 获取当前选中的节点
445
+ const {$anchor} = this.editor.state.selection
446
+ if ($anchor.path[3].attrs.titleId === 'source') return
447
+ if (v === 'h1') this.editor.chain().focus().setFontSize('18px').setBold().run()
448
+ if (v === 'h2') this.editor.chain().focus().setFontSize('16px').setBold().run()
449
+ if (v === 'h3') this.editor.chain().focus().setFontSize('14px').setBold().run()
450
+ if (v === 'p') this.editor.chain().focus().setParagraph().setFontSize('14px').unsetBold().run()
451
+ if (v === 'bold') this.editor.chain().focus().toggleBold().run()
452
+ if (v === 'center' || v === 'left' || v === 'right') this.editor.chain().focus().setTextAlign(v).run()
453
+ if (v === 'add') {
454
+ let html = this.editor.getHTML()
455
+ html += '<p class="source" style="text-align: right;"></p>'
456
+ this.editor.commands.setContent(html)
457
+ }
458
+ if (v === 'centerH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('center').run()
459
+ if (v === 'leftH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('left').run()
460
+ if (v === 'rightH2') this.editor.chain().focus().setFontSize('16px').setBold().setTextAlign('right').run()
447
461
  }
462
+ }
448
463
  }
449
464
 
450
465
  </script>
451
466
 
452
467
  <style scoped>
453
468
  :deep(.imgCont) {
454
- line-height: 0 !important;
469
+ line-height: 0 !important;
455
470
  }
471
+
456
472
  :deep(.ProseMirror-separator) {
457
- display: none !important;
473
+ display: none !important;
458
474
  }
475
+
459
476
  .editor :deep(h1) {
460
- line-height: 24px;
461
- font-size: 18px;
477
+ line-height: 24px;
478
+ font-size: 18px;
462
479
  }
480
+
463
481
  .editor :deep(h2) {
464
- line-height: 24px;
465
- font-size: 16px;
482
+ line-height: 24px;
483
+ font-size: 16px;
466
484
  }
485
+
467
486
  .editor :deep(h3) {
468
- line-height: 24px;
469
- font-size: 14px;
487
+ line-height: 24px;
488
+ font-size: 14px;
470
489
  }
490
+
471
491
  .editor :deep(p) {
472
- font-size: 14px;
473
- line-height: 24px;
492
+ font-size: 14px;
493
+ line-height: 24px;
474
494
  }
495
+
475
496
  :deep(.ProseMirror) p.is-editor-empty:first-child::before {
476
- content: attr(data-placeholder);
477
- float: left;
478
- color: #adb5bd;
479
- pointer-events: none;
480
- height: 0;
497
+ content: attr(data-placeholder);
498
+ float: left;
499
+ color: #adb5bd;
500
+ pointer-events: none;
501
+ height: 0;
481
502
  }
482
- :deep(.source){
483
- color: #333;
503
+
504
+ :deep(.source) {
505
+ color: #333;
484
506
  }
507
+
485
508
  :deep(.source).is-empty::before {
486
- color: #adb5bd;
487
- content: '添加来源';
488
- float: right;
489
- height: 0;
490
- pointer-events: none;
509
+ color: #adb5bd;
510
+ content: '添加来源';
511
+ float: right;
512
+ height: 0;
513
+ pointer-events: none;
491
514
  }
492
- :deep(.editor-img){
493
- max-width: calc(100% - 4em);
494
- padding: 2px 0;
515
+
516
+ :deep(.editor-img) {
517
+ max-width: calc(100% - 4em);
518
+ padding: 2px 0;
495
519
  }
496
- .editor-but{
497
- text-align: right;
498
- margin: 10px 0;
520
+
521
+ .editor-but {
522
+ text-align: right;
523
+ margin: 10px 0;
499
524
  }
500
- .ed-head{
501
- display: flex;
502
- justify-content: center;
525
+
526
+ .ed-head {
527
+ display: flex;
528
+ justify-content: center;
503
529
  }
504
- .ed-head-but{
505
- display: inline-block;
530
+
531
+ .ed-head-but {
532
+ display: inline-block;
533
+ }
534
+
535
+ .ed-head-but label {
536
+ display: inline-block;
537
+ width: 100%;
538
+ height: 100%;
539
+ }
540
+
541
+ .ed-head-but label span {
542
+ line-height: 15px !important;
543
+ }
544
+
545
+ .ed-title {
546
+ flex: 1;
547
+ text-align: left;
548
+ font-size: 16px;
506
549
  }
507
- .ed-head-but label{
508
- display: inline-block;
509
- width: 100%;
510
- height: 100%;
550
+
551
+ .enclosure-list {
552
+ margin: 5px 20px 0 20px;
553
+ height: 22px;
554
+ line-height: 22px;
511
555
  }
512
- .ed-head-but label span{
513
- line-height: 15px !important;
556
+
557
+ .enclosure-list:after {
558
+ content: "";
559
+ clear: left;
560
+ display: block;
514
561
  }
515
- .ed-title{
516
- flex: 1;
517
- text-align: left;
518
- font-size: 16px;
562
+
563
+ .enclosure-item:first-child {
564
+ width: calc(100% - 210px);
519
565
  }
520
- .enclosure-list{
521
- margin: 5px 20px 0 20px;
522
- height: 22px;
523
- line-height: 22px;
566
+
567
+ .enclosure-item:last-child {
568
+ width: 210px;
524
569
  }
525
- .enclosure-list:after{
526
- content: "";
527
- clear: left;
528
- display: block;
570
+
571
+ .enclosure-item {
572
+ height: 22px;
573
+ float: left;
529
574
  }
530
- .enclosure-item:first-child{
531
- width: calc(100% - 210px);
575
+
576
+ .enclosure-item > span {
577
+ display: inline-block;
578
+ overflow: hidden;
579
+ text-overflow: ellipsis;
580
+ white-space: nowrap;
581
+ max-width: 100%;
582
+ box-sizing: border-box;
583
+ padding-right: 20px;
532
584
  }
533
- .enclosure-item:last-child{
534
- width: 210px;
585
+
586
+ .en-but {
587
+ text-align: right;
535
588
  }
536
- .enclosure-item{
537
- height: 22px;
538
- float: left;
589
+
590
+ .enclosure {
591
+ padding: 5px 0;
539
592
  }
540
- .enclosure-item>span{
541
- display: inline-block;
542
- overflow: hidden;
543
- text-overflow: ellipsis;
544
- white-space: nowrap;
545
- max-width: 100%;
546
- box-sizing: border-box;
547
- padding-right: 20px;
593
+
594
+ .ed-cont {
595
+ padding-top: 4px;
596
+ margin-bottom: 14px;
548
597
  }
549
- .en-but{
550
- text-align: right;
598
+
599
+ .editor {
600
+ border-radius: 3px;
601
+ outline: none;
602
+ text-indent: 2em;
551
603
  }
552
- .enclosure{
553
- padding: 5px 0;
604
+
605
+ .editor img {
606
+ max-width: 100%;
554
607
  }
555
- .ed-cont{
556
- padding-top: 4px;
557
- margin-bottom: 14px;
608
+
609
+ .ed-head {
610
+ text-align: right;
558
611
  }
559
- .editor{
560
- border-radius: 3px;
561
- outline: none;
562
- text-indent: 2em;
612
+
613
+ .buts {
614
+ margin-left: 1px;
615
+ font-size: 12px;
616
+ background-color: transparent;
617
+ border: 1px solid #000;
618
+ border-radius: 3px;
619
+ padding: 2px 5px;
620
+ cursor: pointer;
621
+ min-width: 60px;
622
+ height: 20px;
623
+ display: inline-block;
624
+ line-height: 16px;
625
+ box-sizing: border-box;
563
626
  }
564
- .editor img{
565
- max-width: 100%;
627
+
628
+ .but-f {
629
+ float: left;
566
630
  }
567
- .ed-head{
568
- text-align: right;
569
- }
570
- .buts{
571
- margin-left: 1px;
572
- font-size: 12px;
573
- background-color: transparent;
574
- border: 1px solid #000;
575
- border-radius: 3px;
576
- padding: 2px 5px;
577
- cursor: pointer;
578
- min-width: 60px;
579
- height: 20px;
580
- display: inline-block;
581
- line-height: 16px;
582
- box-sizing: border-box;
583
- }
584
- .but-f{
585
- float: left;
586
- }
587
631
  </style>