zydx-plus 1.16.65 → 1.16.66

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.16.65",
3
+ "version": "1.16.66",
4
4
  "description": "Vue.js",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -29,7 +29,10 @@
29
29
  "@wangeditor/plugin-formula": "^1.0.11",
30
30
  "katex": "^0.15.6",
31
31
  "simple-mind-map": "^0.5.8",
32
- "html2json": "^1.0.2"
32
+ "html2json": "^1.0.2",
33
+ "@tiptap/extension-image": "^2.0.3",
34
+ "@tiptap/starter-kit": "^2.0.3",
35
+ "@tiptap/vue-3": "^2.0.3"
33
36
  },
34
37
  "peerDependencies": {
35
38
  "vue": "^3.2.13"
@@ -1,25 +1,32 @@
1
1
  <template>
2
2
  <div class="ed-head">
3
- <div class="ed-head-but" v-for="(item,index) in toolbar">
4
- <button v-if="item.key === 'but'" class="but" @click="item.onClick">{{ item.title }}</button>
5
- <label v-else-if="item.key === 'upImg' || item.key === 'uploadAtt'">
6
- <input type="file" @change="upload($event,item.key)" :accept="(item.key === 'upImg')?'image/*':'application/*'" style="display: none;">
7
- <span class="but">{{ item.title }}</span>
8
- </label>
9
- <button v-else class="but" @click="toolTap(item.key)">{{ item.title }}</button>
3
+ <div class="ed-title">{{ title }}</div>
4
+ <div class="ed-but">
5
+ <div class="ed-head-but" v-for="(item,index) in toolbar">
6
+ <button v-if="item.key === 'but'" class="but" @click="item.onClick" :style="{color: (item.active)? '#00ff00' :'#000'}">{{ item.title }}</button>
7
+
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/*':'application/*'" style="display: none;">
10
+ <span class="but">{{ item.title }}</span>
11
+ </label>
12
+ <button v-else class="but" @click="toolTap(item.key)">{{ item.title }}</button>
13
+ </div>
10
14
  </div>
11
15
  </div>
12
16
  <div class="ed-cont">
13
- <div class="editor" :id="id" contenteditable="true"></div>
17
+ <editor-content class="editor" :style="heightStyle" :editor="editor" />
18
+ <div class="editor-but" v-if="butText !== ''">
19
+ <button class="but" @click="complete">{{ butText }}</button>
20
+ </div>
14
21
  <div class="enclosure" v-if="uploadAttData.length > 0">
15
22
  <p>附件列表:</p>
16
23
  <div class="enclosure-list" v-for="(item,index) in uploadAttData">
17
24
  <div class="enclosure-item">
18
- <span>{{ index + 1 }}. {{ item.name }}</span>
25
+ <span>{{ index + 1 }}. {{ item.fileName }}</span>
19
26
  </div>
20
27
  <div class="enclosure-item en-but">
21
28
  <button class="but" @click="see(index)">查看</button>
22
- <button class="but">下载</button>
29
+ <button class="but" @click="download(index)">下载</button>
23
30
  <button class="but" @click="del(index)">删除</button>
24
31
  </div>
25
32
  </div>
@@ -28,35 +35,76 @@
28
35
  </template>
29
36
  <script>
30
37
  import { html2json, json2html } from 'html2json'
38
+ import { Editor, EditorContent } from '@tiptap/vue-3'
39
+ import StarterKit from '@tiptap/starter-kit'
40
+ import Image from '@tiptap/extension-image'
31
41
  export default {
32
42
  name: 'zydx-xiao-editor',
43
+ components: {
44
+ EditorContent
45
+ },
33
46
  data() {
34
47
  return {
35
48
  uploadAttData: [],
49
+ editor: null,
50
+ heightStyle: {}
36
51
  };
37
52
  },
53
+ beforeUnmount() {
54
+ this.editor.destroy()
55
+ },
38
56
  props: {
39
57
  data: {
40
58
  type: Object,
41
59
  default: () => {}
42
60
  },
43
- ref: {
61
+ toolbar: {
62
+ type: Array,
63
+ default: []
64
+ },
65
+ title: {
44
66
  type: String,
45
- default: 'editor'
67
+ default: ''
46
68
  },
47
- id: {
69
+ readOnly: {
70
+ type: Boolean,
71
+ default: true
72
+ },
73
+ butText: {
48
74
  type: String,
49
- default: 'editor'
75
+ default: ''
50
76
  },
51
- toolbar: {
52
- type: Array,
53
- default: []
77
+ height: {
78
+ type: String,
79
+ default: '200px'
80
+ },
81
+ uploadImage: {
82
+ type: Object,
83
+ default: {}
84
+ },
85
+ uploadAttachment: {
86
+ type: Object,
87
+ default: {}
54
88
  }
55
89
  },
90
+ emits: ['see','complete'],
56
91
  mounted() {
57
92
  if(this.data === undefined) return
58
93
  this.uploadAttData = this.data.enclosure
59
- document.getElementById(this.id).innerHTML = json2html({node: "root",child: this.data.html})
94
+ this.heightStyle = (this.height === '100%')? {height: '100%'} : {'min-height': this.height}
95
+ this.editor = new Editor({
96
+ content: json2html({node: "root",child: this.data.html}),
97
+ editable: this.readOnly,
98
+ extensions: [
99
+ StarterKit,
100
+ Image.configure({
101
+ inline: true,
102
+ HTMLAttributes: {
103
+ width: '100%'
104
+ }
105
+ }),
106
+ ],
107
+ })
60
108
  },
61
109
  methods: {
62
110
  del(index) {
@@ -65,44 +113,109 @@ export default {
65
113
  see(index) {
66
114
  this.$emit('see', this.uploadAttData[index])
67
115
  },
116
+ uploadFile(file) {
117
+ return new Promise((rl,re) => {
118
+ const meta = Object.keys(this.uploadImage.meta)
119
+ const param = new FormData()
120
+ param.append('file', file)
121
+ for(let i = 0; i < meta.length; i++) {
122
+ param.append(meta[i], this.uploadImage.meta[meta[i]])
123
+ }
124
+ const xhr = new XMLHttpRequest()
125
+ xhr.open('POST', this.uploadImage.server)
126
+ const headers = Object.keys(this.uploadImage.headers)
127
+ for(let i = 0; i < headers.length; i++) {
128
+ xhr.setRequestHeader(headers[i], this.uploadImage.headers[headers[i]])
129
+ }
130
+ xhr.onreadystatechange = () => {
131
+ if(xhr.readyState === 4) {
132
+ if(xhr.status === 200) {
133
+ rl(JSON.parse(xhr.responseText))
134
+ }
135
+ }
136
+ }
137
+ xhr.send(param)
138
+ })
139
+ },
68
140
  upload(e,v) {
69
141
  const file = e.target.files[0]
70
- if(v === 'uploadAtt') {
71
- this.uploadAttData.push(file)
72
- }else {
73
- const reader = new FileReader()
74
- reader.readAsDataURL(file)
75
- reader.onload = (es) => {
76
- const img = document.createElement('img')
77
- img.style.width = '100%'
78
- img.style.margin = '3px 0'
79
- img.src = es.target.result
80
- document.getElementById(this.id).appendChild(img)
142
+ this.uploadFile(file).then(r => {
143
+ if(v === 'uploadAtt') {
144
+ this.uploadAttData.push(r.data)
145
+ }else {
146
+ const url = this.uploadImage.url + r.data.filePath
147
+ const html = [
148
+ {
149
+ node: "element",
150
+ tag: "p",
151
+ child: [{
152
+ attr: {
153
+ src: url,
154
+ width:"100%"
155
+ },
156
+ tag: 'img',
157
+ node: "element",
158
+ }]
159
+ }
160
+ ]
161
+ this.insertContent(html)
81
162
  }
82
- }
163
+ })
83
164
  e.target.value = ''
84
165
  },
166
+ insertContent(v) {
167
+ for(let i=0; i< v.length; i++) {
168
+ let html = json2html(v[i])
169
+ this.editor.chain().focus().insertContentAt(this.selection(),html).run()
170
+ }
171
+ },
172
+ download(index) {
173
+ const url = this.uploadImage.url + this.uploadAttData[index].filePath
174
+ let a = document.createElement('a');
175
+ a.style = 'display: none';
176
+ a.download = this.uploadAttData[index].filename;
177
+ a.href = url;
178
+ document.body.appendChild(a);
179
+ a.click();
180
+ document.body.removeChild(a);
181
+ },
182
+ selection() {
183
+ const { from } = this.editor.state.selection
184
+ return from
185
+ },
186
+ complete() {
187
+ this.$emit('complete', this.getData())
188
+ if(this.uploadAttData.length > 0) {
189
+ this.$emit('complete', {
190
+ html: this.getData(),
191
+ enclosure: this.uploadAttData
192
+ })
193
+ }else {
194
+ this.$emit('complete', {html: this.getData()})
195
+ }
196
+ },
85
197
  // 获取编辑器内容
86
198
  getContent(el) {
87
199
  // 编辑器内容转json
88
- const html = document.getElementById(this.id).innerHTML
200
+ if(this.uploadAttData.length > 0) {
201
+ el({
202
+ html: this.getData(),
203
+ enclosure: this.uploadAttData
204
+ })
205
+ }else {
206
+ el({html: this.getData()})
207
+ }
208
+ },
209
+ getData() {
210
+ const html = this.editor.getHTML()
89
211
  const json = html2json(html)
90
- json.child.map(x => {
91
- if(x.tag === undefined) {
92
- x.tag = 'p'
93
- x.node = 'element'
94
- x.child = [{ text: x.text }]
95
- }
96
- if(x.tag === 'div') x.tag = 'p'
97
- return x
98
- })
99
- el({
100
- html: json.child,
101
- enclosure: this.uploadAttData
102
- })
212
+ return json.child
103
213
  },
104
214
  toolTap(v) {
105
- document.execCommand('formatBlock', false, `<${v}>`);
215
+ if(v === 'h1') this.editor.chain().focus().toggleHeading({level:1}).run()
216
+ if(v === 'h2') this.editor.chain().focus().toggleHeading({level:2}).run()
217
+ if(v === 'h3') this.editor.chain().focus().toggleHeading({level:3}).run()
218
+ if(v === 'p') this.editor.chain().focus().setParagraph().run()
106
219
  }
107
220
  }
108
221
  }
@@ -110,9 +223,23 @@ export default {
110
223
  </script>
111
224
 
112
225
  <style scoped>
226
+ .editor-but{
227
+ text-align: right;
228
+ margin: 10px 0;
229
+ }
230
+ .ed-head{
231
+ display: flex;
232
+ justify-content: center;
233
+ }
113
234
  .ed-head-but{
114
235
  display: inline-block;
115
236
  }
237
+ .ed-title{
238
+ flex: 1;
239
+ text-align: left;
240
+ line-height: 22px;
241
+ font-size: 14px;
242
+ }
116
243
  .enclosure-list{
117
244
  display: flex;
118
245
  justify-content: space-between;
@@ -137,7 +264,10 @@ export default {
137
264
  border: 1px solid #ccc;
138
265
  border-radius: 3px;
139
266
  padding: 20px;
140
- min-height: 200px;
267
+ outline: none;
268
+ }
269
+ .editor img{
270
+ max-width: 100%;
141
271
  }
142
272
  .ed-head{
143
273
  text-align: right;
package/src/index.js CHANGED
@@ -51,7 +51,7 @@ function install(app) {
51
51
  }
52
52
 
53
53
  export default {
54
- version: '1.16.65',
54
+ version: '1.16.66',
55
55
  install,
56
56
  Calendar,
57
57
  Message,