zydx-plus 1.35.613 → 1.35.614

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.
@@ -163,883 +163,883 @@
163
163
  <!-- </div>-->
164
164
  </template>
165
165
  <script>
166
- import Recorder from 'js-audio-recorder'
167
- import {html2json, json2html} from '../../utils/html2json.js'
168
- import {Editor, EditorContent, BubbleMenu} from '@tiptap/vue-3'
169
- import StarterKit from '@tiptap/starter-kit'
170
- import Image from '@tiptap/extension-image'
171
- import TextAlign from '@tiptap/extension-text-align'
172
- import Heading from '@tiptap/extension-heading'
173
- import Placeholder from '@tiptap/extension-placeholder'
174
- import Color from '@tiptap/extension-color'
175
- import textStyle from '@tiptap/extension-text-style'
176
- import {sid} from "./sign-id";
177
- import {FontSize} from "./font-size";
178
- import {titleId} from "./title-id";
179
- import {CustomImage} from "./image-size";
180
- import {Contenteditable} from "./contenteditable";
181
- import svgs from "./level";
182
- import Mess from '../../tipBox/index'
183
- import Paint from '../../paint/src/paint'
184
- import alignmentModeCenter from './img/center.png'
185
- import alignmentModeLeft from './img/left.png'
186
- import alignmentModeRight from './img/right.png'
187
-
188
- import zydxChat from '../../chat/src/chat.vue'
189
-
190
- export default {
191
- name: 'zydx-xiao-editor',
192
- components: {
193
- EditorContent,
194
- BubbleMenu,
195
- svgs,
196
- Paint,
197
- zydxChat
198
- },
199
- data() {
200
- return {
201
- alignmentModeLeft: alignmentModeLeft,
202
- alignmentModeCenter: alignmentModeCenter,
203
- alignmentModeRight: alignmentModeRight,
204
- uploadAttData: [],
205
- editor: null,
206
- heightStyle: {},
207
- heightStyleCont: {},
208
- voiceStatus: false,
209
- showBubble: true,
210
- recorder: null,
211
- ws: null,
212
- audioContext: null,
213
- audioData: [],
214
- vol: 0,
215
- appData: {},
216
- error: false,
217
- time: {},
218
- toolbars: [],
219
- left: 0,
220
- top: 0,
221
- isMove: false,
222
- x: 0,
223
- y: 0,
224
- speech: {},
225
- limits: false,
226
- voiceShows: false,
227
- lock: true,
228
- editorRef: null,
229
- imgSizeVal: '',
230
- currentImgDom: {},
231
- paintShow: false,
232
- isShowAi: false,
233
- lastSelectedText: '',
234
- updateInit: false,
235
- }
236
- },
237
- beforeUnmount() {
238
- this.editor?.destroy()
239
- this.recorder?.destroy()
240
- this.ws?.send(JSON.stringify({"type":"CANCEL"}))
241
- this.ws?.close()
242
- this.ws = null
243
- // document.removeEventListener('selectstart', this.selectstartfn);
244
- // document.removeEventListener('mouseup', this.getSelectedText)
245
- },
246
- props: {
247
- apiPrefix: {
248
- type: String,
249
- default: 'zydx'
250
- },
251
- isShowWhiteboarde: {
252
- type: Boolean,
253
- default: true
254
- },
255
- isShowAiTool: {
256
- type: Boolean,
257
- default: true
258
- },
259
- titleVertical: {
260
- type: Boolean,
261
- default: false
262
- },
263
- data: {
264
- type: Object,
265
- default: () => {
266
- }
267
- },
268
- toolbar: {
269
- type: Array,
270
- default: () => []
271
- },
272
- title: {
273
- type: String,
274
- default: ''
275
- },
276
- enclosureText: {
277
- type: String,
278
- default: '附件列表:'
279
- },
280
- titleStyle: {
281
- type: Object,
282
- default: {
283
- 'font-size': '16px',
284
- 'font-weight': 'bold',
285
- 'color': '#333'
286
- }
287
- },
288
- enclosureStyle: {
289
- type: Object,
290
- default: {
291
- 'font-size': '16px',
292
- 'font-weight': 'bold',
293
- 'color': '#000',
294
- 'text-indent': '1.9em'
295
- }
296
- },
297
- readOnly: {
298
- type: Boolean,
299
- default: true
300
- },
301
- butText: {
302
- type: String,
303
- default: ''
304
- },
305
- height: {
306
- type: String,
307
- default: '200px'
308
- },
309
- uploadImage: {
310
- type: Object,
311
- default: () => {}
312
- },
313
- uploadAttachment: {
314
- type: Object,
315
- default: () => {}
316
- },
317
- delShow: {
318
- type: Boolean,
319
- default: true
320
- },
321
- titleShow: {
322
- type: Boolean,
323
- default: true
324
- },
325
- uploadType: {
326
- type: Boolean,
327
- default: false
328
- },
329
- info: {
330
- type: String,
331
- default: ''
332
- },
333
- editorShow: {
334
- type: Boolean,
335
- default: true
336
- },
337
- borderShow: {
338
- type: Boolean,
339
- default: true
340
- },
341
- enclosureShow: {
342
- type: Boolean,
343
- default: true
344
- },
345
- downloadShow: {
346
- type: Boolean,
347
- default: true
348
- },
349
- placeholder: {
350
- type: String,
351
- default: '请输入内容'
352
- },
353
- voiceShow: {
354
- type: Boolean,
355
- default: true
356
- },
357
- numberStyle: {
358
- type: Boolean,
359
- default: false
360
- },
361
- disabled: {
362
- type: Boolean,
363
- default: false
364
- },
365
- enclosureButton: {
366
- type: Object,
367
- default: () => {}
368
- },
369
- updateStatus: {
370
- type: Boolean,
371
- default: false
372
- },
373
- downName: {
374
- type: Array,
375
- default: () => []
376
- }
377
- },
378
- emits: ['see', 'del', 'complete', 'update:data', 'enclosureSuccess', 'download', 'updateData', 'syncDel','assets'],
379
- watch: {
380
- // 强制监听data变化
381
- data: {
382
- handler: function (e) {
383
- if(this.updateInit) return
384
- if(this.updateStatus) this.updateInit = true
385
- this.editor?.commands.setContent(json2html({node: "root", child: this.dataChange(e).html}))
386
- this.uploadAttData = this.dataChange(e).enclosure
387
- },
388
- deep: true
389
- },
390
- readOnly: {
391
- handler: function (e) {
392
- this.editor.setOptions({
393
- editable: e
394
- })
395
- },
396
- deep: true
397
- },
398
- toolbar: {
399
- handler: function (e) {
400
- let status = null
401
- let upload = null
402
- let title = null
403
- this.toolbars = []
404
- e.forEach(x => {
405
- if(x.key === 'but') {
406
- status = x
407
- } else if (x.key === 'uploadAtt') {
408
- upload = x
409
- }else if(['h1','h2','h3','h4','h5','h6'].includes(x.key)) {
410
- title = {key: 'h', title: '标题'}
411
- }else {
412
- this.toolbars.push(x)
413
- }
414
- })
415
- if(title) this.toolbars.unshift(title) // 标题
416
- if(this.isShowWhiteboarde) this.toolbars.push({key: 'paint', title: '插入手写'})
417
- if(upload) this.toolbars.push(upload) // 上传附件
418
- if(this.voiceShow) this.toolbars.push({key: 'voice', title: '语音输入'})
419
- if(status) this.toolbars.push(status) // 之定义按钮
420
- if(this.isShowAiTool) this.toolbars.push({key: 'ai', title: 'AI助手'})
421
- console.log(this.toolbars)
422
- },
423
- immediate: true
424
- },
425
- disabled: {
426
- handler: function (e) {
427
- this.editor.setOptions({
428
- editable: this.readOnly ?(!e):this.readOnly
429
- })
430
- },
431
- deep: true
432
- }
433
- },
434
- mounted() {
435
- let _this = this
436
- this.uploadAttData = this.dataChange(this.data).enclosure
437
- this.heightStyle = (this.height === '100%') ? {height: '100%'} : {'min-height': this.height}
438
- const height = this.height.split('px')[0] - 44
439
- this.heightStyleCont = (this.height === '100%') ? {height: 'calc(100% - 44px)'} : {'min-height': `${height}px`}
440
- this.editor = new Editor({
441
- content: json2html({node: "root", child: this.dataChange(this.data).html }),
442
- editable: this.readOnly ?(!this.disabled):this.readOnly ,
443
- enablePasteRules: true,
444
- extensions: [
445
- sid,
446
- textStyle,
447
- FontSize,
448
- titleId,
449
- CustomImage,
450
- Contenteditable,
451
- Heading.configure({
452
- levels: [1, 2, 3], // 启用 h1/h2/h3(按需调整)
453
- // 可选:自定义 H3 的 HTML 属性(如 class)
454
- HTMLAttributes: {
455
- class: 'tiptap-h3' // 给所有标题添加统一类名(方便样式定制)
456
- }
457
- }),
458
- Color.configure({
459
- types: ['textStyle'],
460
- }),
461
- Placeholder.configure({
462
- placeholder: this.placeholder,
463
- }),
464
- TextAlign.configure({
465
- types: ['heading', 'paragraph'],
466
- }),
467
- Image.configure({
468
- inline: true,
469
- HTMLAttributes: {
470
- class: `editor-img`,
471
- }
472
- }),
473
- StarterKit,
474
- ],
475
- onUpdate: ({editor}) => {
476
- _this.$emit('updateData', {
477
- html: html2json(editor.getHTML()).child,
478
- enclosure: this.uploadAttData
479
- })
480
- },
481
- onBlur: () => {
482
- _this.limits = false
483
- _this.close()
484
- },
485
- // 获取焦点
486
- onFocus: () => {
487
- this.limits = true
488
- },
489
- })
490
- document.addEventListener('keydown', function (e) {
491
- if (e.keyCode === 8 || e.keyCode === 46) {
492
- const sid = _this.editor.state.selection.$anchor.parent.attrs.sid
493
- if (sid === 'prohibit') {
494
- _this.editor.setEditable(false);
495
- setTimeout(() => {
496
- _this.editor.setEditable(true);
497
- }, 0);
498
- }
499
- }
500
- })
501
- // 初始化录音
502
- this.recorder = new Recorder({
503
- sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
504
- sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
505
- numChannels: 1, // 声道,支持 1 或 2, 默认是1
506
- })
507
- this.recorder.onprogress = function (params) {
508
- _this.vol = params.vol
509
- }
510
- document.addEventListener('mousemove', (event) => {
511
- if (!this.isMove) return
512
- this.limits = true
513
- this.x = event.clientX - this.left;
514
- this.y = event.clientY - this.top;
515
- })
516
- document.addEventListener('click', () => {
517
- if(this.limits) return
518
- this.close()
519
- })
520
- },
521
- methods: {
522
- dataChange(e) {
523
- if(!e) return {html: [], enclosure: []}
524
- const html = e.html === undefined || e.html === null || e.html === 'null' ? [] : e.html
525
- const enclosure = (e.enclosure === undefined || e.enclosure === null || e.enclosure === 'null') ? [] : this.enclosureAction(e.enclosure)
526
- return {html: html, enclosure: enclosure}
527
- },
528
- getSelectedText(e) {
529
- const selection = window.getSelection();
530
- const selectedText = selection.toString()
531
- if (!selectedText || this.lastSelectedText === selectedText) return
532
- this.lastSelectedText = selectedText
533
- },
534
- showAssets() {
535
- this.$emit('assets')
536
- },
537
- showAi() {
538
- this.isShowAi = !this.isShowAi
539
- },
540
- exportImg(e) {
541
- this.uploadFile(e, this.uploadImage).then(r => {
542
- this.paintShow = false
543
- this.imgHtml(r.data)
544
- })
545
- },
546
- paintText() {
547
- return this.toolbar.filter(x => x.key === 'paint')[0]?.title
548
- },
549
- paintCancel() {
550
- this.paintShow = false
551
- },
552
- changeAlign(tag) {
553
- // 图片对齐方式
554
- this.editor.chain().setTextAlign(tag).run()
555
- },
556
- changePercent(e) {
557
- // 改变图片百分比
558
- if(parseInt(e.target.value) > 100) {
559
- this.imgSizeVal = 100
560
- this.editor.chain().setImageWidth('100%').focus().run()
561
- } else if(parseInt(e.target.value) < 10) {
562
-
563
- } else {
564
- if(this.lock) {
565
- this.lock = false
566
- setTimeout(() => {
567
- this.editor.chain().setImageWidth(e.target.value + '%').focus().run()
568
- this.lock = true
569
- }, 500)
570
- }
571
- }
572
- },
573
- shouldShowFn({ editor, view, state, oldState, from, to }) {
574
- // BubbleMenu是否显示
575
- this.$nextTick(() => {
576
- this.showBubble = editor.isActive('image')
577
- if(editor.isActive('image')) {
578
- this.imgSizeVal = parseInt(this.editor.getAttributes('image').width)
579
- } else {
580
- this.imgSizeVal = ''
581
- }
582
- })
583
- return editor.isActive('image')
584
- },
585
- speechDown(e) {
586
- this.speech = {
587
- x: e.clientX - e.offsetX,
588
- y: e.clientY - e.offsetY,
589
- }
590
- },
591
- mousedown(event) {
592
- event.preventDefault()
593
- //鼠标按下事件
594
- this.left = event.offsetX;
595
- this.top = event.offsetY;
596
- this.isMove = true
597
- },
598
- mouseup() {
599
- this.isMove = false
600
- setTimeout(() => {
601
- this.limits = false
602
- },10)
603
- },
604
- // 粘贴文本处理
605
- preventPaste(event) {
606
- if(!this.readOnly) return
607
- // 删除选中的文本
608
- this.editor.chain().focus().deleteSelection().run()
609
- const text = event.clipboardData.getData('text/plain');
610
- // const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
611
- // this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
612
- const textArr = text.split(/[\r\n]/g)
613
- textArr.forEach((item,index) => {
614
- if(index === 0) {
615
- this.editor.chain().focus().insertContentAt(this.selection(), item).run()
616
- }else {
617
- this.editor.chain().focus().insertContentAt(this.selection(), `<p>${item}</p>`).run()
618
- }
619
- })
620
- },
621
- addContent(text) {
622
- const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
623
- this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
624
- },
625
- to16kHz(audioData, sampleRate = 44100) {
626
- const data = new Float32Array(audioData);
627
- const fitCount = Math.round(data.length * (16000 / sampleRate));
628
- const newData = new Float32Array(fitCount);
629
- const springFactor = (data.length - 1) / (fitCount - 1);
630
- newData[0] = data[0];
631
- for (let i = 1; i < fitCount - 1; i++) {
632
- const tmp = i * springFactor;
633
- const before = Math.floor(tmp).toFixed();
634
- const after = Math.ceil(tmp).toFixed();
635
- const atPoint = tmp - before;
636
- newData[i] = data[before] + (data[after] - data[before]) * atPoint;
637
- }
638
- newData[fitCount - 1] = data[data.length - 1];
639
- return newData;
640
- },
641
- to16BitPCM(input) {
642
- const dataLength = input.length * (16 / 8);
643
- const dataBuffer = new ArrayBuffer(dataLength);
644
- const dataView = new DataView(dataBuffer);
645
- let offset = 0;
646
- for (let i = 0; i < input.length; i++, offset += 2) {
647
- const s = Math.max(-1, Math.min(1, input[i]));
648
- dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
649
- }
650
- return dataView;
651
- },
652
- getAudioSuccess() {
653
- let that = this
654
- const mediaStreamSource = that.recorder.audioInput
655
- // 创建一个音频分析对象,采样的缓冲区大小为0(自动适配),输入和输出都是单声道
656
- const scriptProcessor = that.recorder.context.createScriptProcessor(1024, 1, 1);
657
- scriptProcessor.onaudioprocess = (e) => {
658
- // 去处理音频数据
659
- const inputData = e.inputBuffer.getChannelData(0)
660
- const output = that.to16kHz(inputData, that.recorder.context.sampleRate);
661
- const audioData = that.to16BitPCM(output);
662
- that.audioData.push(...new Int8Array(audioData.buffer));
663
- if (that.audioData.length > 10240) {
664
- const audioDataArray = new Int8Array(that.audioData);
665
- that.ws.send(audioDataArray)
666
- that.audioData = [];
667
- }
668
- }
669
- mediaStreamSource.connect(scriptProcessor);
670
- scriptProcessor.connect(that.recorder.context.destination);
671
- },
672
- voice() {
673
- this.voiceStatus = !this.voiceStatus
674
- this.limits = false
675
- if(this.voiceStatus) {
676
- this.recorder.start().then(() => { // 开始录音
677
- this.audioData = []
678
- this.x = this.speech.x - 85
679
- const h = this.height.split('px')[0]
680
- this.y = this.speech.y + ((this.height === '100%') ? 40 : Number(h) - 10)
681
- this.voiceShows = this.voiceStatus
682
- this.appID()
683
- }, () => {
684
- Mess({
685
- type: 'text',
686
- cancelShow: false,
687
- promptContent: '录音失败,请检查麦克风是否可用'
688
- })
689
- });
690
- }else {
691
- this.close()
692
- }
693
- },
694
- close() {
695
- if(this.ws === null) return
696
- // this.toolbar.map(x => {
697
- // if (x.key === 'speech') {
698
- // x.active = false
699
- // }
700
- // return x
701
- // })
702
- this.voiceStatus = false
703
- this.voiceShows = this.voiceStatus
704
- this.ws?.send(JSON.stringify({"type":"CANCEL"}))
705
- this.ws?.close()
706
- this.ws = null
707
- this.recorder.stop() // 停止录音
708
- this.recorder.destroy()
709
- },
710
- webSocketInit() {
711
- const _this = this
712
- this.ws = new WebSocket(`wss://vop.baidu.com/realtime_asr?sn=${this.getRandomCode(15)}`)
713
- this.ws.binaryType = 'arraybuffer'
714
- this.ws.onopen = function () {
715
- _this.error = false
716
- const json = {
717
- type: 'START',
718
- data: {
719
- // 百度实时转译 appid appkey
720
- appid: Number(_this.appData.appId),
721
- appkey: _this.appData.key,
722
- // appid: 101913097,
723
- // appkey: 'xv9715uwu2jqkTmIzlJl8eGx',
724
- dev_pid: 15372,
725
- cuid: _this.appData.secret,
726
- format: 'pcm',
727
- sample: 16000,
728
- }
729
- }
730
- _this.ws.send(JSON.stringify(json))
731
- _this.getAudioSuccess()
732
- }
733
- this.ws.onmessage = function (e) {
734
- const data = JSON.parse(e.data)
735
- if(data.err_no === 0){
736
- const json = _this.editor.getJSON()
737
- const index = _this.editor.state.selection.$anchor.path[1]
738
- if(data.start_time === _this.time.start_time) {
739
- const text = json.content[index].content[0].text
740
- json.content[index].content[0].text = text.slice(0, text.length - _this.time.result.length) + data.result
741
- _this.editor.commands.setContent(json)
742
- }else {
743
- _this.editor.chain().focus().insertContentAt(_this.selection(), data.result).run()
744
- }
745
- _this.time = data
746
- }
747
- }
748
- this.ws.onerror = function () {
749
- // 连接失败重连
750
- setTimeout(() => {
751
- _this.webSocketInit()
752
- }, 5000)
753
- }
754
- },
755
- appID() {
756
- let token = null
757
- let remember = localStorage.getItem('remember')
758
- if(remember === '1') {
759
- token = localStorage.getItem('sessionId')
760
- }else {
761
- token = sessionStorage.getItem('sessionId')
762
- }
763
- const xhr = new XMLHttpRequest()
764
- // xhr.open('GET', 'http://192.168.15.124:8888/zydx/voice/getDesKeyId')
765
- // xhr.setRequestHeader('Authorization', '7a129186-7e51-431d-b965-735dfed8e459')
766
- xhr.open('GET', `/${window.linkApi.apiPrefix?window.linkApi.apiPrefix:'zydx'}/voice/getVoideKey`)
767
- xhr.setRequestHeader('Authorization', token)
768
- this.error = true
769
- xhr.onreadystatechange = () => {
770
- if (xhr.readyState === 4) {
771
- if (xhr.status === 200) {
772
- this.appData = JSON.parse(xhr.responseText).data
773
- this.webSocketInit()
774
- }
775
- }
776
- }
777
- xhr.send()
778
- },
779
- enclosureAction(v) {
780
- return v.map(x => {
781
- x.active = true
782
- return x
783
- })
784
- },
785
- randomId() { // 生成随机id
786
- const id = Math.random().toString(36).substr(2)
787
- return id.replace(/[0-9]/g, '')
788
- },
789
- del(index) {
790
- let that = this
791
- that.data.html = html2json(that.editor.getHTML()).child
792
- if (!this.uploadAttData[index].name) {
793
- that.uploadAttData[index].active = false
794
- that.$emit('del', that.uploadAttData[index], (e) => {
795
- if (!e) {
796
- that.uploadAttData.splice(index, 1)
797
- } else {
798
- if (e) {
799
- that.uploadAttData.splice(index, 1)
800
- } else {
801
- that.uploadAttData[index].active = true
802
- }
803
- }
804
- })
805
- } else {
806
- this.$emit('syncDel', {syncDel: true, index: index, data: that.uploadAttData[index] }) // 为了同步当前组件和父组件附件的数据(新加的syncDel,使用原来的del怕有问题)
807
- that.uploadAttData.splice(index, 1)
808
- }
809
- },
810
- see(index) {
811
- this.$emit('see', this.uploadAttData[index])
812
- },
813
- uploadFile(file, data) {
814
- return new Promise((rl) => {
815
- const meta = data.meta ? Object.keys(data.meta) : []
816
- const param = new FormData()
817
- param.append('file', file)
818
- for (let i = 0; i < meta.length; i++) {
819
- param.append(meta[i], data.meta[meta[i]])
820
- }
821
- const xhr = new XMLHttpRequest()
822
- xhr.open('POST', data.server)
823
- const headers = Object.keys(data.headers)
824
- for (let i = 0; i < headers.length; i++) {
825
- xhr.setRequestHeader(headers[i], data.headers[headers[i]])
826
- }
827
- xhr.onreadystatechange = () => {
828
- if (xhr.readyState === 4) {
829
- if (xhr.status === 200) {
830
- const text = JSON.parse(xhr.responseText)
831
- if(text.code === '200') {
832
- rl(text)
833
- }else {
834
- Mess({
835
- type: 'text',
836
- cancelShow: false,
837
- promptContent: text.msg
838
- })
839
- }
840
- }
841
- }
842
- }
843
- xhr.send(param)
844
- })
845
- },
846
- upload(e, v) { // 上传文件
847
- const file = e.target.files[0]
848
- if (this.uploadType) {
849
- if (v === 'uploadAtt') {
850
- file.active = true
851
- this.uploadAttData.push(file)
852
- this.$emit('updateData', {
853
- html: html2json(this.editor.getHTML()).child,
854
- enclosure: this.uploadAttData
855
- })
856
- } else {
857
- this.uploadFile(file, this.uploadImage).then(r => {
858
- if (r.code === '200') {
859
- this.imgHtml(r.data)
860
- } else {
861
- this.uploadImage.onFailed(r)
862
- }
863
- })
864
- }
865
- } else {
866
- this.uploadFile(file, (v === 'uploadAtt') ? this.uploadAttachment : this.uploadImage).then(r => {
867
- if (v === 'uploadAtt') {
868
- if (r.data.annex) {
869
- r.data.annex.active = true
870
- this.uploadAttData.push(r.data.annex)
871
- this.$emit('enclosureSuccess', r.data.annex, html2json(this.editor.getHTML()).child)
872
- } else if (r.data) { // 学生端-生问生答-问答=提问详情及回答-实施回答的上传附件返回r.data
873
- r.data.active = true
874
- this.uploadAttData.push(r.data)
875
- this.$emit('enclosureSuccess', r.data, html2json(this.editor.getHTML()).child)
876
- } else {
877
- file.active = true
878
- this.uploadAttData.push(file)
879
- this.$emit('updateData', {
880
- html: html2json(this.editor.getHTML()).child,
881
- enclosure: this.uploadAttData
882
- })
883
- }
884
- } else {
885
- this.imgHtml(r.data)
886
- }
887
- })
888
- }
889
- e.target.value = ''
890
- },
891
- imgHtml(data) { // 插入图片
892
- setTimeout(() => {
893
- const url = this.uploadImage.url + data
894
- const cla = this.randomId()
895
- const html = `<p class="imgCont ${cla}"><img src="${url}" alt="" width=""/></p>`
896
- this.editor.chain().focus().insertContentAt(this.selection(), html).run()
897
- if (this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
898
- if (this.selectionClass(cla)) {
899
- this.editor.chain().focus().insertContentAt(this.selection(), '<p></p>').run()
900
- }
901
- }, 100)
902
- },
903
- // selectImg(cla) {
904
- // this.$nextTick(() => {
905
- // const images = this.$refs.editorRef.rootEl.querySelectorAll('img');
906
- // const claDom = this.$refs.editorRef.rootEl.getElementsByClassName(cla);
907
- // claDom[0].insertAdjacentHTML('beforeend', `<p class="tips ${cla}" style="color: red">新的段落</p>`)
908
- // images.forEach(img => {
909
- // img.addEventListener('mouseenter', this.handleImageClick);
910
- // img.addEventListener('mouseleave', this.handleImageClick);
911
- // });
912
- // });
913
- // },
914
- // handleImageClick(text) {
915
- // console.log('mouseenter==>>>>',text)
916
- // },
917
- insertContent(v) {
918
- for (let i = 0; i < v.length; i++) {
919
- let html = json2html(v[i])
920
- this.editor.chain().focus().insertContentAt(this.selection(), html).run()
921
- }
922
- },
923
- // 查询class
924
- selectionClass(v) {
925
- const json = this.editor.getJSON()
926
- for (let i = 0; i < json.content.length; i++) {
927
- const val = json.content[i].attrs?.titleId?.split(' ')[1]
928
- if (val === v) {
929
- if (json.content[i + 1] === undefined) return true
930
- break
931
- }
932
- }
933
- return false
934
- },
935
- selectionClass2(v) {
936
- const json = this.editor.getJSON()
937
- for (let i = 0; i < json.content.length; i++) {
938
- const val = json.content[i].attrs?.titleId?.split(' ')[1]
939
- if (val === v) {
940
- json.content.splice(i - 1, 1)
941
- this.editor?.commands.setContent(json)
942
- break
943
- }
944
- }
945
- },
946
- enclosureContent(v) {
947
- this.uploadAttData = [...this.uploadAttData, ...this.enclosureAction(v)]
948
- },
949
- download(index) {
950
- this.$emit('download', this.uploadAttData[index])
951
- },
952
- selection() {
953
- const {from} = this.editor.state.selection
954
- return from
955
- },
956
- complete() {
957
- if (this.uploadAttData.length > 0) {
958
- this.$emit('complete', {
959
- html: this.getData(),
960
- enclosure: this.uploadAttData
961
- })
962
- } else {
963
- this.$emit('complete', {html: this.getData()})
964
- }
965
- },
966
- // 获取编辑器内容
967
- getContent(el) {
968
- // 编辑器内容转json
969
- if (this.uploadAttData.length > 0) {
970
- el({
971
- html: this.getData(),
972
- enclosure: this.uploadAttData
973
- })
974
- } else {
975
- el({html: this.getData()})
976
- }
977
- },
978
- getData() {
979
- const html = this.editor.getHTML()
980
- const json = html2json(html)
981
- return json.child
982
- },
983
- toolTap(v) {
984
- // 获取当前选中的节点
985
- const {$anchor} = this.editor.state.selection
986
- if ($anchor.path[3].attrs.titleId === 'source') {
987
- let html = this.editor.getHTML()
988
- html += '<p></p>'
989
- this.editor.commands.setContent(html)
990
- }
991
- if (v === 'add') {
992
- let html = this.editor.getHTML()
993
- html += '<p class="source" style="text-align: right;"></p>'
994
- this.editor.commands.setContent(html)
995
- }
996
- if (v === 'lookUp') {
997
- let html = this.editor.getHTML()
998
- html = '<p class="lookUp" style="text-align: left;"></p>' + html
999
- this.editor.commands.setContent(html)
1000
- this.editor.chain().focus().setTextSelection(0).run()
1001
- }
1002
- // if (v === 'h1') this.editor.chain().focus().setFontSize('18px').setBold().run()
1003
- // if (v === 'h2') this.editor.chain().focus().setFontSize('16px').setBold().run()
1004
- // if (v === 'h3') this.editor.chain().focus().setFontSize('14px').setBold().run()
1005
- if(v === 'h1') this.editor.chain().focus().setBold().setFontSize('18px').run()
1006
- if(v === 'h2') this.editor.chain().focus().setBold().setFontSize('16px').run()
1007
- if(v === 'h3') this.editor.chain().focus().setBold().setFontSize('14px').run()
1008
-
1009
- if (v === 'p') {
1010
- this.editor.chain().focus().setFontSize('14px').unsetBold().run()
1011
- }
1012
- if (v === 'bold') this.editor.chain().focus().toggleBold().run()
1013
- if (v === 'center' || v === 'left' || v === 'right') this.editor.chain().focus().setTextAlign(v).run()
1014
- if (v === 'centerH2') {
1015
- this.editor.chain().focus().setFontSize('16px').setTextAlign('center').run()
1016
- this.editor.chain().focus().setBold().run()
1017
- }
1018
- if (v === 'leftH2') {
1019
- this.editor.chain().focus().setFontSize('16px').setTextAlign('left').run()
1020
- this.editor.chain().focus().setBold().run()
1021
- }
1022
- if (v === 'rightH2') {
1023
- this.editor.chain().focus().setFontSize('16px').setTextAlign('right').run()
1024
- this.editor.chain().focus().setBold().run()
1025
- }
1026
- if(v === 'paint') this.paintShow = true
1027
- },
1028
- getRandomCode(length) {
1029
- if (length > 0) {
1030
- let data = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
1031
- let nums = "";
1032
- for (let i = 0; i < length; i++) {
1033
- let r = parseInt(Math.random() * 61);
1034
- nums += data[r];
1035
- }
1036
- return nums.replace(/(.{4})/g, "$1-");
1037
- } else {
1038
- return false;
1039
- }
1040
- }
1041
- }
1042
- }
166
+ // import Recorder from 'js-audio-recorder'
167
+ // import {html2json, json2html} from '../../utils/html2json.js'
168
+ // import {Editor, EditorContent, BubbleMenu} from '@tiptap/vue-3'
169
+ // import StarterKit from '@tiptap/starter-kit'
170
+ // import Image from '@tiptap/extension-image'
171
+ // import TextAlign from '@tiptap/extension-text-align'
172
+ // import Heading from '@tiptap/extension-heading'
173
+ // import Placeholder from '@tiptap/extension-placeholder'
174
+ // import Color from '@tiptap/extension-color'
175
+ // import textStyle from '@tiptap/extension-text-style'
176
+ // import {sid} from "./sign-id";
177
+ // import {FontSize} from "./font-size";
178
+ // import {titleId} from "./title-id";
179
+ // import {CustomImage} from "./image-size";
180
+ // import {Contenteditable} from "./contenteditable";
181
+ // import svgs from "./level";
182
+ // import Mess from '../../tipBox/index'
183
+ // import Paint from '../../paint/src/paint'
184
+ // import alignmentModeCenter from './img/center.png'
185
+ // import alignmentModeLeft from './img/left.png'
186
+ // import alignmentModeRight from './img/right.png'
187
+ //
188
+ // import zydxChat from '../../chat/src/chat.vue'
189
+ //
190
+ // export default {
191
+ // name: 'zydx-xiao-editor',
192
+ // components: {
193
+ // EditorContent,
194
+ // BubbleMenu,
195
+ // svgs,
196
+ // Paint,
197
+ // zydxChat
198
+ // },
199
+ // data() {
200
+ // return {
201
+ // alignmentModeLeft: alignmentModeLeft,
202
+ // alignmentModeCenter: alignmentModeCenter,
203
+ // alignmentModeRight: alignmentModeRight,
204
+ // uploadAttData: [],
205
+ // editor: null,
206
+ // heightStyle: {},
207
+ // heightStyleCont: {},
208
+ // voiceStatus: false,
209
+ // showBubble: true,
210
+ // recorder: null,
211
+ // ws: null,
212
+ // audioContext: null,
213
+ // audioData: [],
214
+ // vol: 0,
215
+ // appData: {},
216
+ // error: false,
217
+ // time: {},
218
+ // toolbars: [],
219
+ // left: 0,
220
+ // top: 0,
221
+ // isMove: false,
222
+ // x: 0,
223
+ // y: 0,
224
+ // speech: {},
225
+ // limits: false,
226
+ // voiceShows: false,
227
+ // lock: true,
228
+ // editorRef: null,
229
+ // imgSizeVal: '',
230
+ // currentImgDom: {},
231
+ // paintShow: false,
232
+ // isShowAi: false,
233
+ // lastSelectedText: '',
234
+ // updateInit: false,
235
+ // }
236
+ // },
237
+ // beforeUnmount() {
238
+ // this.editor?.destroy()
239
+ // this.recorder?.destroy()
240
+ // this.ws?.send(JSON.stringify({"type":"CANCEL"}))
241
+ // this.ws?.close()
242
+ // this.ws = null
243
+ // // document.removeEventListener('selectstart', this.selectstartfn);
244
+ // // document.removeEventListener('mouseup', this.getSelectedText)
245
+ // },
246
+ // props: {
247
+ // apiPrefix: {
248
+ // type: String,
249
+ // default: 'zydx'
250
+ // },
251
+ // isShowWhiteboarde: {
252
+ // type: Boolean,
253
+ // default: true
254
+ // },
255
+ // isShowAiTool: {
256
+ // type: Boolean,
257
+ // default: true
258
+ // },
259
+ // titleVertical: {
260
+ // type: Boolean,
261
+ // default: false
262
+ // },
263
+ // data: {
264
+ // type: Object,
265
+ // default: () => {
266
+ // }
267
+ // },
268
+ // toolbar: {
269
+ // type: Array,
270
+ // default: () => []
271
+ // },
272
+ // title: {
273
+ // type: String,
274
+ // default: ''
275
+ // },
276
+ // enclosureText: {
277
+ // type: String,
278
+ // default: '附件列表:'
279
+ // },
280
+ // titleStyle: {
281
+ // type: Object,
282
+ // default: {
283
+ // 'font-size': '16px',
284
+ // 'font-weight': 'bold',
285
+ // 'color': '#333'
286
+ // }
287
+ // },
288
+ // enclosureStyle: {
289
+ // type: Object,
290
+ // default: {
291
+ // 'font-size': '16px',
292
+ // 'font-weight': 'bold',
293
+ // 'color': '#000',
294
+ // 'text-indent': '1.9em'
295
+ // }
296
+ // },
297
+ // readOnly: {
298
+ // type: Boolean,
299
+ // default: true
300
+ // },
301
+ // butText: {
302
+ // type: String,
303
+ // default: ''
304
+ // },
305
+ // height: {
306
+ // type: String,
307
+ // default: '200px'
308
+ // },
309
+ // uploadImage: {
310
+ // type: Object,
311
+ // default: () => {}
312
+ // },
313
+ // uploadAttachment: {
314
+ // type: Object,
315
+ // default: () => {}
316
+ // },
317
+ // delShow: {
318
+ // type: Boolean,
319
+ // default: true
320
+ // },
321
+ // titleShow: {
322
+ // type: Boolean,
323
+ // default: true
324
+ // },
325
+ // uploadType: {
326
+ // type: Boolean,
327
+ // default: false
328
+ // },
329
+ // info: {
330
+ // type: String,
331
+ // default: ''
332
+ // },
333
+ // editorShow: {
334
+ // type: Boolean,
335
+ // default: true
336
+ // },
337
+ // borderShow: {
338
+ // type: Boolean,
339
+ // default: true
340
+ // },
341
+ // enclosureShow: {
342
+ // type: Boolean,
343
+ // default: true
344
+ // },
345
+ // downloadShow: {
346
+ // type: Boolean,
347
+ // default: true
348
+ // },
349
+ // placeholder: {
350
+ // type: String,
351
+ // default: '请输入内容'
352
+ // },
353
+ // voiceShow: {
354
+ // type: Boolean,
355
+ // default: true
356
+ // },
357
+ // numberStyle: {
358
+ // type: Boolean,
359
+ // default: false
360
+ // },
361
+ // disabled: {
362
+ // type: Boolean,
363
+ // default: false
364
+ // },
365
+ // enclosureButton: {
366
+ // type: Object,
367
+ // default: () => {}
368
+ // },
369
+ // updateStatus: {
370
+ // type: Boolean,
371
+ // default: false
372
+ // },
373
+ // downName: {
374
+ // type: Array,
375
+ // default: () => []
376
+ // }
377
+ // },
378
+ // emits: ['see', 'del', 'complete', 'update:data', 'enclosureSuccess', 'download', 'updateData', 'syncDel','assets'],
379
+ // watch: {
380
+ // // 强制监听data变化
381
+ // data: {
382
+ // handler: function (e) {
383
+ // if(this.updateInit) return
384
+ // if(this.updateStatus) this.updateInit = true
385
+ // this.editor?.commands.setContent(json2html({node: "root", child: this.dataChange(e).html}))
386
+ // this.uploadAttData = this.dataChange(e).enclosure
387
+ // },
388
+ // deep: true
389
+ // },
390
+ // readOnly: {
391
+ // handler: function (e) {
392
+ // this.editor.setOptions({
393
+ // editable: e
394
+ // })
395
+ // },
396
+ // deep: true
397
+ // },
398
+ // toolbar: {
399
+ // handler: function (e) {
400
+ // let status = null
401
+ // let upload = null
402
+ // let title = null
403
+ // this.toolbars = []
404
+ // e.forEach(x => {
405
+ // if(x.key === 'but') {
406
+ // status = x
407
+ // } else if (x.key === 'uploadAtt') {
408
+ // upload = x
409
+ // }else if(['h1','h2','h3','h4','h5','h6'].includes(x.key)) {
410
+ // title = {key: 'h', title: '标题'}
411
+ // }else {
412
+ // this.toolbars.push(x)
413
+ // }
414
+ // })
415
+ // if(title) this.toolbars.unshift(title) // 标题
416
+ // if(this.isShowWhiteboarde) this.toolbars.push({key: 'paint', title: '插入手写'})
417
+ // if(upload) this.toolbars.push(upload) // 上传附件
418
+ // if(this.voiceShow) this.toolbars.push({key: 'voice', title: '语音输入'})
419
+ // if(status) this.toolbars.push(status) // 之定义按钮
420
+ // if(this.isShowAiTool) this.toolbars.push({key: 'ai', title: 'AI助手'})
421
+ // console.log(this.toolbars)
422
+ // },
423
+ // immediate: true
424
+ // },
425
+ // disabled: {
426
+ // handler: function (e) {
427
+ // this.editor.setOptions({
428
+ // editable: this.readOnly ?(!e):this.readOnly
429
+ // })
430
+ // },
431
+ // deep: true
432
+ // }
433
+ // },
434
+ // mounted() {
435
+ // let _this = this
436
+ // this.uploadAttData = this.dataChange(this.data).enclosure
437
+ // this.heightStyle = (this.height === '100%') ? {height: '100%'} : {'min-height': this.height}
438
+ // const height = this.height.split('px')[0] - 44
439
+ // this.heightStyleCont = (this.height === '100%') ? {height: 'calc(100% - 44px)'} : {'min-height': `${height}px`}
440
+ // this.editor = new Editor({
441
+ // content: json2html({node: "root", child: this.dataChange(this.data).html }),
442
+ // editable: this.readOnly ?(!this.disabled):this.readOnly ,
443
+ // enablePasteRules: true,
444
+ // extensions: [
445
+ // sid,
446
+ // textStyle,
447
+ // FontSize,
448
+ // titleId,
449
+ // CustomImage,
450
+ // Contenteditable,
451
+ // Heading.configure({
452
+ // levels: [1, 2, 3], // 启用 h1/h2/h3(按需调整)
453
+ // // 可选:自定义 H3 的 HTML 属性(如 class)
454
+ // HTMLAttributes: {
455
+ // class: 'tiptap-h3' // 给所有标题添加统一类名(方便样式定制)
456
+ // }
457
+ // }),
458
+ // Color.configure({
459
+ // types: ['textStyle'],
460
+ // }),
461
+ // Placeholder.configure({
462
+ // placeholder: this.placeholder,
463
+ // }),
464
+ // TextAlign.configure({
465
+ // types: ['heading', 'paragraph'],
466
+ // }),
467
+ // Image.configure({
468
+ // inline: true,
469
+ // HTMLAttributes: {
470
+ // class: `editor-img`,
471
+ // }
472
+ // }),
473
+ // StarterKit,
474
+ // ],
475
+ // onUpdate: ({editor}) => {
476
+ // _this.$emit('updateData', {
477
+ // html: html2json(editor.getHTML()).child,
478
+ // enclosure: this.uploadAttData
479
+ // })
480
+ // },
481
+ // onBlur: () => {
482
+ // _this.limits = false
483
+ // _this.close()
484
+ // },
485
+ // // 获取焦点
486
+ // onFocus: () => {
487
+ // this.limits = true
488
+ // },
489
+ // })
490
+ // document.addEventListener('keydown', function (e) {
491
+ // if (e.keyCode === 8 || e.keyCode === 46) {
492
+ // const sid = _this.editor.state.selection.$anchor.parent.attrs.sid
493
+ // if (sid === 'prohibit') {
494
+ // _this.editor.setEditable(false);
495
+ // setTimeout(() => {
496
+ // _this.editor.setEditable(true);
497
+ // }, 0);
498
+ // }
499
+ // }
500
+ // })
501
+ // // 初始化录音
502
+ // this.recorder = new Recorder({
503
+ // sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
504
+ // sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
505
+ // numChannels: 1, // 声道,支持 1 或 2, 默认是1
506
+ // })
507
+ // this.recorder.onprogress = function (params) {
508
+ // _this.vol = params.vol
509
+ // }
510
+ // document.addEventListener('mousemove', (event) => {
511
+ // if (!this.isMove) return
512
+ // this.limits = true
513
+ // this.x = event.clientX - this.left;
514
+ // this.y = event.clientY - this.top;
515
+ // })
516
+ // document.addEventListener('click', () => {
517
+ // if(this.limits) return
518
+ // this.close()
519
+ // })
520
+ // },
521
+ // methods: {
522
+ // dataChange(e) {
523
+ // if(!e) return {html: [], enclosure: []}
524
+ // const html = e.html === undefined || e.html === null || e.html === 'null' ? [] : e.html
525
+ // const enclosure = (e.enclosure === undefined || e.enclosure === null || e.enclosure === 'null') ? [] : this.enclosureAction(e.enclosure)
526
+ // return {html: html, enclosure: enclosure}
527
+ // },
528
+ // getSelectedText(e) {
529
+ // const selection = window.getSelection();
530
+ // const selectedText = selection.toString()
531
+ // if (!selectedText || this.lastSelectedText === selectedText) return
532
+ // this.lastSelectedText = selectedText
533
+ // },
534
+ // showAssets() {
535
+ // this.$emit('assets')
536
+ // },
537
+ // showAi() {
538
+ // this.isShowAi = !this.isShowAi
539
+ // },
540
+ // exportImg(e) {
541
+ // this.uploadFile(e, this.uploadImage).then(r => {
542
+ // this.paintShow = false
543
+ // this.imgHtml(r.data)
544
+ // })
545
+ // },
546
+ // paintText() {
547
+ // return this.toolbar.filter(x => x.key === 'paint')[0]?.title
548
+ // },
549
+ // paintCancel() {
550
+ // this.paintShow = false
551
+ // },
552
+ // changeAlign(tag) {
553
+ // // 图片对齐方式
554
+ // this.editor.chain().setTextAlign(tag).run()
555
+ // },
556
+ // changePercent(e) {
557
+ // // 改变图片百分比
558
+ // if(parseInt(e.target.value) > 100) {
559
+ // this.imgSizeVal = 100
560
+ // this.editor.chain().setImageWidth('100%').focus().run()
561
+ // } else if(parseInt(e.target.value) < 10) {
562
+ //
563
+ // } else {
564
+ // if(this.lock) {
565
+ // this.lock = false
566
+ // setTimeout(() => {
567
+ // this.editor.chain().setImageWidth(e.target.value + '%').focus().run()
568
+ // this.lock = true
569
+ // }, 500)
570
+ // }
571
+ // }
572
+ // },
573
+ // shouldShowFn({ editor, view, state, oldState, from, to }) {
574
+ // // BubbleMenu是否显示
575
+ // this.$nextTick(() => {
576
+ // this.showBubble = editor.isActive('image')
577
+ // if(editor.isActive('image')) {
578
+ // this.imgSizeVal = parseInt(this.editor.getAttributes('image').width)
579
+ // } else {
580
+ // this.imgSizeVal = ''
581
+ // }
582
+ // })
583
+ // return editor.isActive('image')
584
+ // },
585
+ // speechDown(e) {
586
+ // this.speech = {
587
+ // x: e.clientX - e.offsetX,
588
+ // y: e.clientY - e.offsetY,
589
+ // }
590
+ // },
591
+ // mousedown(event) {
592
+ // event.preventDefault()
593
+ // //鼠标按下事件
594
+ // this.left = event.offsetX;
595
+ // this.top = event.offsetY;
596
+ // this.isMove = true
597
+ // },
598
+ // mouseup() {
599
+ // this.isMove = false
600
+ // setTimeout(() => {
601
+ // this.limits = false
602
+ // },10)
603
+ // },
604
+ // // 粘贴文本处理
605
+ // preventPaste(event) {
606
+ // if(!this.readOnly) return
607
+ // // 删除选中的文本
608
+ // this.editor.chain().focus().deleteSelection().run()
609
+ // const text = event.clipboardData.getData('text/plain');
610
+ // // const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
611
+ // // this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
612
+ // const textArr = text.split(/[\r\n]/g)
613
+ // textArr.forEach((item,index) => {
614
+ // if(index === 0) {
615
+ // this.editor.chain().focus().insertContentAt(this.selection(), item).run()
616
+ // }else {
617
+ // this.editor.chain().focus().insertContentAt(this.selection(), `<p>${item}</p>`).run()
618
+ // }
619
+ // })
620
+ // },
621
+ // addContent(text) {
622
+ // const text2 = text.replace(/[\r\n]/g, '').replace(/\s*/g, '')
623
+ // this.editor.chain().focus().insertContentAt(this.selection(), text2).run()
624
+ // },
625
+ // to16kHz(audioData, sampleRate = 44100) {
626
+ // const data = new Float32Array(audioData);
627
+ // const fitCount = Math.round(data.length * (16000 / sampleRate));
628
+ // const newData = new Float32Array(fitCount);
629
+ // const springFactor = (data.length - 1) / (fitCount - 1);
630
+ // newData[0] = data[0];
631
+ // for (let i = 1; i < fitCount - 1; i++) {
632
+ // const tmp = i * springFactor;
633
+ // const before = Math.floor(tmp).toFixed();
634
+ // const after = Math.ceil(tmp).toFixed();
635
+ // const atPoint = tmp - before;
636
+ // newData[i] = data[before] + (data[after] - data[before]) * atPoint;
637
+ // }
638
+ // newData[fitCount - 1] = data[data.length - 1];
639
+ // return newData;
640
+ // },
641
+ // to16BitPCM(input) {
642
+ // const dataLength = input.length * (16 / 8);
643
+ // const dataBuffer = new ArrayBuffer(dataLength);
644
+ // const dataView = new DataView(dataBuffer);
645
+ // let offset = 0;
646
+ // for (let i = 0; i < input.length; i++, offset += 2) {
647
+ // const s = Math.max(-1, Math.min(1, input[i]));
648
+ // dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
649
+ // }
650
+ // return dataView;
651
+ // },
652
+ // getAudioSuccess() {
653
+ // let that = this
654
+ // const mediaStreamSource = that.recorder.audioInput
655
+ // // 创建一个音频分析对象,采样的缓冲区大小为0(自动适配),输入和输出都是单声道
656
+ // const scriptProcessor = that.recorder.context.createScriptProcessor(1024, 1, 1);
657
+ // scriptProcessor.onaudioprocess = (e) => {
658
+ // // 去处理音频数据
659
+ // const inputData = e.inputBuffer.getChannelData(0)
660
+ // const output = that.to16kHz(inputData, that.recorder.context.sampleRate);
661
+ // const audioData = that.to16BitPCM(output);
662
+ // that.audioData.push(...new Int8Array(audioData.buffer));
663
+ // if (that.audioData.length > 10240) {
664
+ // const audioDataArray = new Int8Array(that.audioData);
665
+ // that.ws.send(audioDataArray)
666
+ // that.audioData = [];
667
+ // }
668
+ // }
669
+ // mediaStreamSource.connect(scriptProcessor);
670
+ // scriptProcessor.connect(that.recorder.context.destination);
671
+ // },
672
+ // voice() {
673
+ // this.voiceStatus = !this.voiceStatus
674
+ // this.limits = false
675
+ // if(this.voiceStatus) {
676
+ // this.recorder.start().then(() => { // 开始录音
677
+ // this.audioData = []
678
+ // this.x = this.speech.x - 85
679
+ // const h = this.height.split('px')[0]
680
+ // this.y = this.speech.y + ((this.height === '100%') ? 40 : Number(h) - 10)
681
+ // this.voiceShows = this.voiceStatus
682
+ // this.appID()
683
+ // }, () => {
684
+ // Mess({
685
+ // type: 'text',
686
+ // cancelShow: false,
687
+ // promptContent: '录音失败,请检查麦克风是否可用'
688
+ // })
689
+ // });
690
+ // }else {
691
+ // this.close()
692
+ // }
693
+ // },
694
+ // close() {
695
+ // if(this.ws === null) return
696
+ // // this.toolbar.map(x => {
697
+ // // if (x.key === 'speech') {
698
+ // // x.active = false
699
+ // // }
700
+ // // return x
701
+ // // })
702
+ // this.voiceStatus = false
703
+ // this.voiceShows = this.voiceStatus
704
+ // this.ws?.send(JSON.stringify({"type":"CANCEL"}))
705
+ // this.ws?.close()
706
+ // this.ws = null
707
+ // this.recorder.stop() // 停止录音
708
+ // this.recorder.destroy()
709
+ // },
710
+ // webSocketInit() {
711
+ // const _this = this
712
+ // this.ws = new WebSocket(`wss://vop.baidu.com/realtime_asr?sn=${this.getRandomCode(15)}`)
713
+ // this.ws.binaryType = 'arraybuffer'
714
+ // this.ws.onopen = function () {
715
+ // _this.error = false
716
+ // const json = {
717
+ // type: 'START',
718
+ // data: {
719
+ // // 百度实时转译 appid appkey
720
+ // appid: Number(_this.appData.appId),
721
+ // appkey: _this.appData.key,
722
+ // // appid: 101913097,
723
+ // // appkey: 'xv9715uwu2jqkTmIzlJl8eGx',
724
+ // dev_pid: 15372,
725
+ // cuid: _this.appData.secret,
726
+ // format: 'pcm',
727
+ // sample: 16000,
728
+ // }
729
+ // }
730
+ // _this.ws.send(JSON.stringify(json))
731
+ // _this.getAudioSuccess()
732
+ // }
733
+ // this.ws.onmessage = function (e) {
734
+ // const data = JSON.parse(e.data)
735
+ // if(data.err_no === 0){
736
+ // const json = _this.editor.getJSON()
737
+ // const index = _this.editor.state.selection.$anchor.path[1]
738
+ // if(data.start_time === _this.time.start_time) {
739
+ // const text = json.content[index].content[0].text
740
+ // json.content[index].content[0].text = text.slice(0, text.length - _this.time.result.length) + data.result
741
+ // _this.editor.commands.setContent(json)
742
+ // }else {
743
+ // _this.editor.chain().focus().insertContentAt(_this.selection(), data.result).run()
744
+ // }
745
+ // _this.time = data
746
+ // }
747
+ // }
748
+ // this.ws.onerror = function () {
749
+ // // 连接失败重连
750
+ // setTimeout(() => {
751
+ // _this.webSocketInit()
752
+ // }, 5000)
753
+ // }
754
+ // },
755
+ // appID() {
756
+ // let token = null
757
+ // let remember = localStorage.getItem('remember')
758
+ // if(remember === '1') {
759
+ // token = localStorage.getItem('sessionId')
760
+ // }else {
761
+ // token = sessionStorage.getItem('sessionId')
762
+ // }
763
+ // const xhr = new XMLHttpRequest()
764
+ // // xhr.open('GET', 'http://192.168.15.124:8888/zydx/voice/getDesKeyId')
765
+ // // xhr.setRequestHeader('Authorization', '7a129186-7e51-431d-b965-735dfed8e459')
766
+ // xhr.open('GET', `/${window.linkApi.apiPrefix?window.linkApi.apiPrefix:'zydx'}/voice/getVoideKey`)
767
+ // xhr.setRequestHeader('Authorization', token)
768
+ // this.error = true
769
+ // xhr.onreadystatechange = () => {
770
+ // if (xhr.readyState === 4) {
771
+ // if (xhr.status === 200) {
772
+ // this.appData = JSON.parse(xhr.responseText).data
773
+ // this.webSocketInit()
774
+ // }
775
+ // }
776
+ // }
777
+ // xhr.send()
778
+ // },
779
+ // enclosureAction(v) {
780
+ // return v.map(x => {
781
+ // x.active = true
782
+ // return x
783
+ // })
784
+ // },
785
+ // randomId() { // 生成随机id
786
+ // const id = Math.random().toString(36).substr(2)
787
+ // return id.replace(/[0-9]/g, '')
788
+ // },
789
+ // del(index) {
790
+ // let that = this
791
+ // that.data.html = html2json(that.editor.getHTML()).child
792
+ // if (!this.uploadAttData[index].name) {
793
+ // that.uploadAttData[index].active = false
794
+ // that.$emit('del', that.uploadAttData[index], (e) => {
795
+ // if (!e) {
796
+ // that.uploadAttData.splice(index, 1)
797
+ // } else {
798
+ // if (e) {
799
+ // that.uploadAttData.splice(index, 1)
800
+ // } else {
801
+ // that.uploadAttData[index].active = true
802
+ // }
803
+ // }
804
+ // })
805
+ // } else {
806
+ // this.$emit('syncDel', {syncDel: true, index: index, data: that.uploadAttData[index] }) // 为了同步当前组件和父组件附件的数据(新加的syncDel,使用原来的del怕有问题)
807
+ // that.uploadAttData.splice(index, 1)
808
+ // }
809
+ // },
810
+ // see(index) {
811
+ // this.$emit('see', this.uploadAttData[index])
812
+ // },
813
+ // uploadFile(file, data) {
814
+ // return new Promise((rl) => {
815
+ // const meta = data.meta ? Object.keys(data.meta) : []
816
+ // const param = new FormData()
817
+ // param.append('file', file)
818
+ // for (let i = 0; i < meta.length; i++) {
819
+ // param.append(meta[i], data.meta[meta[i]])
820
+ // }
821
+ // const xhr = new XMLHttpRequest()
822
+ // xhr.open('POST', data.server)
823
+ // const headers = Object.keys(data.headers)
824
+ // for (let i = 0; i < headers.length; i++) {
825
+ // xhr.setRequestHeader(headers[i], data.headers[headers[i]])
826
+ // }
827
+ // xhr.onreadystatechange = () => {
828
+ // if (xhr.readyState === 4) {
829
+ // if (xhr.status === 200) {
830
+ // const text = JSON.parse(xhr.responseText)
831
+ // if(text.code === '200') {
832
+ // rl(text)
833
+ // }else {
834
+ // Mess({
835
+ // type: 'text',
836
+ // cancelShow: false,
837
+ // promptContent: text.msg
838
+ // })
839
+ // }
840
+ // }
841
+ // }
842
+ // }
843
+ // xhr.send(param)
844
+ // })
845
+ // },
846
+ // upload(e, v) { // 上传文件
847
+ // const file = e.target.files[0]
848
+ // if (this.uploadType) {
849
+ // if (v === 'uploadAtt') {
850
+ // file.active = true
851
+ // this.uploadAttData.push(file)
852
+ // this.$emit('updateData', {
853
+ // html: html2json(this.editor.getHTML()).child,
854
+ // enclosure: this.uploadAttData
855
+ // })
856
+ // } else {
857
+ // this.uploadFile(file, this.uploadImage).then(r => {
858
+ // if (r.code === '200') {
859
+ // this.imgHtml(r.data)
860
+ // } else {
861
+ // this.uploadImage.onFailed(r)
862
+ // }
863
+ // })
864
+ // }
865
+ // } else {
866
+ // this.uploadFile(file, (v === 'uploadAtt') ? this.uploadAttachment : this.uploadImage).then(r => {
867
+ // if (v === 'uploadAtt') {
868
+ // if (r.data.annex) {
869
+ // r.data.annex.active = true
870
+ // this.uploadAttData.push(r.data.annex)
871
+ // this.$emit('enclosureSuccess', r.data.annex, html2json(this.editor.getHTML()).child)
872
+ // } else if (r.data) { // 学生端-生问生答-问答=提问详情及回答-实施回答的上传附件返回r.data
873
+ // r.data.active = true
874
+ // this.uploadAttData.push(r.data)
875
+ // this.$emit('enclosureSuccess', r.data, html2json(this.editor.getHTML()).child)
876
+ // } else {
877
+ // file.active = true
878
+ // this.uploadAttData.push(file)
879
+ // this.$emit('updateData', {
880
+ // html: html2json(this.editor.getHTML()).child,
881
+ // enclosure: this.uploadAttData
882
+ // })
883
+ // }
884
+ // } else {
885
+ // this.imgHtml(r.data)
886
+ // }
887
+ // })
888
+ // }
889
+ // e.target.value = ''
890
+ // },
891
+ // imgHtml(data) { // 插入图片
892
+ // setTimeout(() => {
893
+ // const url = this.uploadImage.url + data
894
+ // const cla = this.randomId()
895
+ // const html = `<p class="imgCont ${cla}"><img src="${url}" alt="" width=""/></p>`
896
+ // this.editor.chain().focus().insertContentAt(this.selection(), html).run()
897
+ // if (this.selection() <= 6 && this.selection() > 2) this.selectionClass2(cla)
898
+ // if (this.selectionClass(cla)) {
899
+ // this.editor.chain().focus().insertContentAt(this.selection(), '<p></p>').run()
900
+ // }
901
+ // }, 100)
902
+ // },
903
+ // // selectImg(cla) {
904
+ // // this.$nextTick(() => {
905
+ // // const images = this.$refs.editorRef.rootEl.querySelectorAll('img');
906
+ // // const claDom = this.$refs.editorRef.rootEl.getElementsByClassName(cla);
907
+ // // claDom[0].insertAdjacentHTML('beforeend', `<p class="tips ${cla}" style="color: red">新的段落</p>`)
908
+ // // images.forEach(img => {
909
+ // // img.addEventListener('mouseenter', this.handleImageClick);
910
+ // // img.addEventListener('mouseleave', this.handleImageClick);
911
+ // // });
912
+ // // });
913
+ // // },
914
+ // // handleImageClick(text) {
915
+ // // console.log('mouseenter==>>>>',text)
916
+ // // },
917
+ // insertContent(v) {
918
+ // for (let i = 0; i < v.length; i++) {
919
+ // let html = json2html(v[i])
920
+ // this.editor.chain().focus().insertContentAt(this.selection(), html).run()
921
+ // }
922
+ // },
923
+ // // 查询class
924
+ // selectionClass(v) {
925
+ // const json = this.editor.getJSON()
926
+ // for (let i = 0; i < json.content.length; i++) {
927
+ // const val = json.content[i].attrs?.titleId?.split(' ')[1]
928
+ // if (val === v) {
929
+ // if (json.content[i + 1] === undefined) return true
930
+ // break
931
+ // }
932
+ // }
933
+ // return false
934
+ // },
935
+ // selectionClass2(v) {
936
+ // const json = this.editor.getJSON()
937
+ // for (let i = 0; i < json.content.length; i++) {
938
+ // const val = json.content[i].attrs?.titleId?.split(' ')[1]
939
+ // if (val === v) {
940
+ // json.content.splice(i - 1, 1)
941
+ // this.editor?.commands.setContent(json)
942
+ // break
943
+ // }
944
+ // }
945
+ // },
946
+ // enclosureContent(v) {
947
+ // this.uploadAttData = [...this.uploadAttData, ...this.enclosureAction(v)]
948
+ // },
949
+ // download(index) {
950
+ // this.$emit('download', this.uploadAttData[index])
951
+ // },
952
+ // selection() {
953
+ // const {from} = this.editor.state.selection
954
+ // return from
955
+ // },
956
+ // complete() {
957
+ // if (this.uploadAttData.length > 0) {
958
+ // this.$emit('complete', {
959
+ // html: this.getData(),
960
+ // enclosure: this.uploadAttData
961
+ // })
962
+ // } else {
963
+ // this.$emit('complete', {html: this.getData()})
964
+ // }
965
+ // },
966
+ // // 获取编辑器内容
967
+ // getContent(el) {
968
+ // // 编辑器内容转json
969
+ // if (this.uploadAttData.length > 0) {
970
+ // el({
971
+ // html: this.getData(),
972
+ // enclosure: this.uploadAttData
973
+ // })
974
+ // } else {
975
+ // el({html: this.getData()})
976
+ // }
977
+ // },
978
+ // getData() {
979
+ // const html = this.editor.getHTML()
980
+ // const json = html2json(html)
981
+ // return json.child
982
+ // },
983
+ // toolTap(v) {
984
+ // // 获取当前选中的节点
985
+ // const {$anchor} = this.editor.state.selection
986
+ // if ($anchor.path[3].attrs.titleId === 'source') {
987
+ // let html = this.editor.getHTML()
988
+ // html += '<p></p>'
989
+ // this.editor.commands.setContent(html)
990
+ // }
991
+ // if (v === 'add') {
992
+ // let html = this.editor.getHTML()
993
+ // html += '<p class="source" style="text-align: right;"></p>'
994
+ // this.editor.commands.setContent(html)
995
+ // }
996
+ // if (v === 'lookUp') {
997
+ // let html = this.editor.getHTML()
998
+ // html = '<p class="lookUp" style="text-align: left;"></p>' + html
999
+ // this.editor.commands.setContent(html)
1000
+ // this.editor.chain().focus().setTextSelection(0).run()
1001
+ // }
1002
+ // // if (v === 'h1') this.editor.chain().focus().setFontSize('18px').setBold().run()
1003
+ // // if (v === 'h2') this.editor.chain().focus().setFontSize('16px').setBold().run()
1004
+ // // if (v === 'h3') this.editor.chain().focus().setFontSize('14px').setBold().run()
1005
+ // if(v === 'h1') this.editor.chain().focus().setBold().setFontSize('18px').run()
1006
+ // if(v === 'h2') this.editor.chain().focus().setBold().setFontSize('16px').run()
1007
+ // if(v === 'h3') this.editor.chain().focus().setBold().setFontSize('14px').run()
1008
+ //
1009
+ // if (v === 'p') {
1010
+ // this.editor.chain().focus().setFontSize('14px').unsetBold().run()
1011
+ // }
1012
+ // if (v === 'bold') this.editor.chain().focus().toggleBold().run()
1013
+ // if (v === 'center' || v === 'left' || v === 'right') this.editor.chain().focus().setTextAlign(v).run()
1014
+ // if (v === 'centerH2') {
1015
+ // this.editor.chain().focus().setFontSize('16px').setTextAlign('center').run()
1016
+ // this.editor.chain().focus().setBold().run()
1017
+ // }
1018
+ // if (v === 'leftH2') {
1019
+ // this.editor.chain().focus().setFontSize('16px').setTextAlign('left').run()
1020
+ // this.editor.chain().focus().setBold().run()
1021
+ // }
1022
+ // if (v === 'rightH2') {
1023
+ // this.editor.chain().focus().setFontSize('16px').setTextAlign('right').run()
1024
+ // this.editor.chain().focus().setBold().run()
1025
+ // }
1026
+ // if(v === 'paint') this.paintShow = true
1027
+ // },
1028
+ // getRandomCode(length) {
1029
+ // if (length > 0) {
1030
+ // let data = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
1031
+ // let nums = "";
1032
+ // for (let i = 0; i < length; i++) {
1033
+ // let r = parseInt(Math.random() * 61);
1034
+ // nums += data[r];
1035
+ // }
1036
+ // return nums.replace(/(.{4})/g, "$1-");
1037
+ // } else {
1038
+ // return false;
1039
+ // }
1040
+ // }
1041
+ // }
1042
+ // }
1043
1043
 
1044
1044
  </script>
1045
1045