seatonwan9
2025-08-14 a0fc5b1e703769a8936fd8671ec9cdd9adfda20a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
<template>
  <div>
    <div style="width: 100%; height: 220px; border: 1px solid #f2f2f2">
      <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <Editor
        style="height:170px; overflow-y: hidden"
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        :mode="mode"
        @onCreated="handleCreated"
      />
    </div>
  </div>
</template>
<script lang="ts" setup>
import {
  ElNotification,
  ElMessage,
  UploadRawFile,
  UploadRequestOptions,
  genFileId,
} from 'element-plus'
import type {
  FormInstance,
  FormRules,
  UploadInstance,
  UploadProps,
  UploadUserFile,
} from 'element-plus'
import { Refresh } from '@element-plus/icons-vue'
import { IEditorConfig } from '@wangeditor/editor'
import { getImgFlowUrl, getImgFlowUrlT } from '@/utils/fileFlow'
import '@wangeditor/editor/dist/css/style.css'
import { useUserInfo } from '@/stores/modules/userInfo'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import optionService from '@/api/zhongjian/optionApi'
const userInfoStore = useUserInfo()
const state = reactive<any>({
  btnLoading: false,
})
const emit = defineEmits(['updateDataFun','getCurrentData'])
 
// 父组件props传参
interface Props {
  richTextValue?: any // 可选的父组件传参
  indexData: any
  modelData: any
  currentData?: any // 循环使用时使用
 currentIndex?: any // 循环使用时使用
  placeholder?:string
}
 
const props = withDefaults(defineProps<Props>(), {
  richTextValue: '',
  indexData: '',
  modelData: '',
  currentData: '',
  currentIndex: '',
  placeholder:''
})
 
//---------------------------------------
const mode = 'simple'
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref('')
 
const toolbarConfig = {
  toolbarKeys: [
    "headerSelect", // 头部类型选择
    "blockquote", // 引用块
    '|',
    "bold", // 字体加粗
    "underline", // 字体下划线
    "italic", // 字体斜体
    {
      key: 'group-font',
      title: '...',
      menuKeys: ['through', 'code', 'sub', 'clearStyle'], //字体处理的四种方式
    },
 
    "color", // 字体颜色
    "bgColor", // 背景颜色
    "fontSize", // 字体大小
    "fontFamily", // 字体
 
    "lineHeight", // 行间距
    '|', // 分割线
    "bulletedList", // 无序列表
    "numberedList", // 有序列表
    "todo", // 待办事项
    {
      key: 'group-justify',
      title: '对齐',
      iconSvg:
          '<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
      menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'], // 对齐的四种方式
    },
    {
      key: 'group-indent',
      title: '缩进',
      iconSvg:
          '<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>',
      menuKeys: ['indent', 'delIndent'], // 缩进的两种方式
    },
 
    '|',
    // {
    //   key: 'group-image',
    //   title: '上传图片',
    //   iconSvg:
    //       '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
    //   menuKeys: ['uploadImage', 'insertImage'], // 对齐的四种方式
    // },
    'uploadImage',//上传图片
    "redo", // 重做
    "undo", // 撤销
    '|',
 
 
  ]
};
 
 
const editorConfig: Partial<IEditorConfig> = {
  placeholder:props?.placeholder||'请输入内容...',
  MENU_CONF: {},
}
// 组件销毁时,也及时销毁编辑器
// onBeforeUnmount(() => {
//   const editor = editorRef.value;
//   if (editor == null) return;
//   editor.destroy();
// });
onBeforeMount(() => {
  const Biurl = import.meta.env.VITE_BI_URL as any
  const hearderData = ref('')
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prodReplace'|| process.env.NODE_ENV === 'replace') {
    hearderData.value = '/admin'
  } else{
    hearderData.value = '/api'
  }
  //上传图片
  editorConfig.MENU_CONF['uploadImage'] = {
    // server: '/admin/admin/common' + "/fileUpload",
    server: `${hearderData.value}/admin/common/fileUpload`,
    fieldName: 'file',
    // headers: { Authorization: "Bearer " + userInfoStore.getAdminToken},
    headers: {
      // 'Content-Type': 'application/json;charset=UTF-8',
      token: userInfoStore.getAdminToken,
    },
    maxFileSize: 10 * 1024 * 1024,
    base64LimitSize: 5 * 1024,
    maxNumberOfFiles: 1,
    allowedFileTypes: ['image/*'],
    customInsert(res, insertFn) {
      optionService
        .getPicUrlUrl({
          fileId: res.data.fileId,
        })
        .then((res) => {
          console.log('res------', res)
          if (res.code == 200) {
            const url = res.data.fileUrl
            insertFn(url)
          }
        })
 
      // // 预览图片
      // getImgFlowUrlT(res.data.fileId || '').then((res: any) => {
      //   console.log("查看图片-----", res)
      //   // if (window.URL.createObjectURL != undefined) {
      //   //   const myBlob = new window.Blob([res.data], {type: 'image/jpeg'})
      //   //   const url = window.URL.createObjectURL(myBlob)
      //   //
      //   //   console.log('pic---',url)
      //   //
      //   //
      //   // }
      // })
    },
    // onBeforeUpload(file) {
    //   console.log("onBeforeUpload", file);
    //   return file; // will upload this file
    //   // return false // prevent upload
    // },
    // onProgress(progress) {
    //   console.log("onProgress", progress);
    // },
    // onSuccess(file, res) {
    //   console.log("onSuccess", file, res);
    // },
    // onFailed(file, res) {
    //   alert(res.message);
    //   console.log("onFailed", file, res);
    // },
    // onError(file, err, res) {
    //   console.error("onError", file, err.message, res);
    // }
  }
  //插入视频
  editorConfig.MENU_CONF['insertVideo'] = {
    onInsertedVideo(videoNode) {
    },
  }
  //上传视频
  editorConfig.MENU_CONF['uploadVideo'] = {
    // server: '/admin/admin/common' + "/fileUpload",
    server: `${hearderData.value}/admin/common/fileUpload`,
    fieldName: 'file',
    allowedFileTypes: ['video/*'],
    headers: {
      // 'Content-Type': 'application/json;charset=UTF-8',
      token: userInfoStore.getAdminToken,
    },
    maxFileSize: 100 * 1024 * 1024,
    customInsert(res, insertFn) {
      // const videoInfo = res.data[0] || {};
      // const {url} = videoInfo;
      // if (!url) throw new Error(`视频的url为空`);
      // insertFn(url + "#dsffdsfsf");
 
      optionService
        .getPicUrlUrl({
          fileId: res.data.fileId,
        })
        .then((res) => {
          console.log('res------', res)
          if (res.code == 200) {
            const url = res.data.fileUrl
            insertFn(url + '#dsffdsfsf')
          }
        })
    },
    // onBeforeUpload(file) {
    //   console.log("onBeforeUpload", file);
    //   return file; // will upload this file
    //   // return false // prevent upload
    // },
    // onProgress(progress) {
    //   console.log("onProgress", progress);
    // },
    // onSuccess(file, res) {
    //   console.log("onSuccess", file, res);
    // },
    // onFailed(file, res) {
    //   alert(res.message);
    //   console.log("onFailed", file, res);
    // },
    // onError(file, err, res) {
    //   alert(err.message);
    //   console.error("onError", file, err, res);
    // }
  }
})
const handleCreated = (editor) => {
  editorRef.value = editor // 记录 editor 实例,重要!
  // console.log("editorRef------", editorRef.value)
}
 
// 父级调用
const completeFun = () => {
  alert('11')
}
 
// 监听父级传来的
watch(
  () => props.modelData,
  (val: string) => {
    valueHtml.value = val
  },
  {
    immediate: true,
  }
)
 
// 监听传给父级的
watch(
  () => valueHtml.value,
  (val: string) => {
    emit('updateDataFun', val, props.indexData)
    emit('getCurrentData', props.currentData, props.currentIndex)
  },
  {
    immediate: true,
  }
)
watch(
  () => props.curentData,
  (val: string) => {
    emit('getCurrentData', val, props.currentIndex)
  },
  {
    immediate: true,
  }
)
// 将方法暴露给父组件
defineExpose({
  completeFun,
})
</script>
<style scoped lang="scss">
.w-e-textarea-video-container {
  //background-color: #00a0e9 !important;
}
</style>