Skip to content

Commit 3ad1a4f

Browse files
committed
feat(tinymce): add image upload #170
1 parent 18ad1bc commit 3ad1a4f

File tree

8 files changed

+133
-37
lines changed

8 files changed

+133
-37
lines changed

CHANGELOG.zh_CN.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- 新增`PageWrapper`组件。并应用于示例页面
1717
- 新增标签页折叠功能
1818
- 兼容旧版浏览器
19+
- tinymce 新增图片上传·
1920

2021
### 🐛 Bug Fixes
2122

@@ -24,6 +25,7 @@
2425
- 修复表格内存溢出问题
2526
- 修复`layout` 收缩展开功能在分割模式下失效
2627
- 修复 modal 高度计算错误
28+
- 修复文件上传错误
2729

2830
### 🎫 Chores
2931

src/components/Tinymce/src/Editor.vue

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<template>
2-
<div class="tinymce-container" :style="{ width: containerWidth }">
2+
<div :class="prefixCls" :style="{ width: containerWidth }">
3+
<ImgUpload
4+
@uploading="handleImageUploading"
5+
@done="handleDone"
6+
v-if="showImageUpload"
7+
v-show="editorRef"
8+
/>
39
<textarea :id="tinymceId" ref="elRef" :style="{ visibility: 'hidden' }"></textarea>
410
</div>
511
</template>
@@ -24,6 +30,8 @@
2430
import { bindHandlers } from './helper';
2531
import lineHeight from './lineHeight';
2632
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
33+
import ImgUpload from './ImgUpload.vue';
34+
import { useDesign } from '/@/hooks/web/useDesign';
2735
2836
const CDN_URL = 'https://cdn.bootcdn.net/ajax/libs/tinymce/5.5.1';
2937
@@ -33,12 +41,15 @@
3341
name: 'Tinymce',
3442
inheritAttrs: false,
3543
props: basicProps,
44+
components: { ImgUpload },
3645
emits: ['change', 'update:modelValue'],
3746
setup(props, { emit, attrs }) {
3847
const editorRef = ref<any>(null);
3948
const tinymceId = ref<string>(snowUuid('tiny-vue'));
4049
const elRef = ref<Nullable<HTMLElement>>(null);
4150
51+
const { prefixCls } = useDesign('tinymce-container');
52+
4253
const tinymceContent = computed(() => {
4354
return props.modelValue;
4455
});
@@ -140,7 +151,7 @@
140151
bindHandlers(e, attrs, unref(editorRef));
141152
}
142153
143-
function setValue(editor: any, val: string, prevVal: string) {
154+
function setValue(editor: Recordable, val: string, prevVal?: string) {
144155
if (
145156
editor &&
146157
typeof val === 'string' &&
@@ -179,45 +190,54 @@
179190
});
180191
}
181192
193+
function handleImageUploading(name: string) {
194+
const editor = unref(editorRef);
195+
if (!editor) return;
196+
const content = editor?.getContent() ?? '';
197+
setValue(editor, `${content}\n${getImgName(name)}`);
198+
}
199+
200+
function handleDone(name: string, url: string) {
201+
const editor = unref(editorRef);
202+
if (!editor) return;
203+
204+
const content = editor?.getContent() ?? '';
205+
const val = content?.replace(getImgName(name), `<img src="${url}"/>`) ?? '';
206+
setValue(editor, val);
207+
}
208+
209+
function getImgName(name: string) {
210+
return `[uploading:${name}]`;
211+
}
212+
182213
return {
214+
prefixCls,
183215
containerWidth,
184216
initOptions,
185217
tinymceContent,
186218
tinymceScriptSrc,
187219
elRef,
188220
tinymceId,
221+
handleImageUploading,
222+
handleDone,
223+
editorRef,
189224
};
190225
},
191226
});
192227
</script>
193228

194-
<style lang="less" scoped>
195-
.tinymce-container {
196-
position: relative;
197-
line-height: normal;
229+
<style lang="less" scoped></style>
198230

199-
.mce-fullscreen {
200-
z-index: 10000;
201-
}
202-
}
231+
<style lang="less">
232+
@prefix-cls: ~'@{namespace}-tinymce-container';
203233
204-
.editor-custom-btn-container {
205-
position: absolute;
206-
top: 6px;
207-
right: 6px;
234+
.@{prefix-cls} {
235+
position: relative;
236+
line-height: normal;
208237
209-
&.fullscreen {
210-
position: fixed;
211-
z-index: 10000;
238+
textarea {
239+
z-index: -1;
240+
visibility: hidden;
212241
}
213242
}
214-
215-
.editor-upload-btn {
216-
display: inline-block;
217-
}
218-
219-
textarea {
220-
z-index: -1;
221-
visibility: hidden;
222-
}
223243
</style>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<template>
2+
<div :class="prefixCls">
3+
<Upload
4+
name="file"
5+
multiple
6+
@change="handleChange"
7+
:action="uploadUrl"
8+
:showUploadList="false"
9+
accept=".jpg,.jpeg,.gif,.png,.webp"
10+
>
11+
<a-button type="primary">{{ t('component.upload.imgUpload') }}</a-button>
12+
</Upload>
13+
</div>
14+
</template>
15+
<script lang="ts">
16+
import { defineComponent } from 'vue';
17+
18+
import { Upload } from 'ant-design-vue';
19+
import { InboxOutlined } from '@ant-design/icons-vue';
20+
import { useDesign } from '/@/hooks/web/useDesign';
21+
import { useGlobSetting } from '/@/hooks/setting';
22+
import { useI18n } from '/@/hooks/web/useI18n';
23+
24+
export default defineComponent({
25+
name: 'TinymceImageUpload',
26+
components: { Upload, InboxOutlined },
27+
emits: ['uploading', 'done', 'error'],
28+
setup(_, { emit }) {
29+
let uploading = false;
30+
31+
const { uploadUrl } = useGlobSetting();
32+
const { t } = useI18n();
33+
const { prefixCls } = useDesign('tinymce-img-upload');
34+
function handleChange(info: Recordable) {
35+
const file = info.file;
36+
const status = file?.status;
37+
38+
const url = file?.response?.url;
39+
const name = file?.name;
40+
if (status === 'uploading') {
41+
if (!uploading) {
42+
emit('uploading', name);
43+
uploading = true;
44+
}
45+
} else if (status === 'done') {
46+
emit('done', name, url);
47+
uploading = false;
48+
} else if (status === 'error') {
49+
emit('error');
50+
uploading = false;
51+
}
52+
}
53+
54+
return {
55+
prefixCls,
56+
handleChange,
57+
uploadUrl,
58+
t,
59+
};
60+
},
61+
});
62+
</script>
63+
<style lang="less" scoped>
64+
@prefix-cls: ~'@{namespace}-tinymce-img-upload';
65+
66+
.@{prefix-cls} {
67+
position: absolute;
68+
top: 4px;
69+
right: 10px;
70+
z-index: 20;
71+
}
72+
</style>
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
import { PropType } from 'vue';
2+
import { propTypes } from '/@/utils/propTypes';
23

34
export const basicProps = {
45
options: {
56
type: Object as PropType<any>,
67
default: {},
78
},
8-
value: {
9-
type: String as PropType<string>,
10-
// default: ''
11-
},
12-
modelValue: {
13-
type: String as PropType<string>,
14-
// default: ''
15-
},
9+
value: propTypes.string,
10+
modelValue: propTypes.string,
1611
// 高度
1712
height: {
1813
type: [Number, String] as PropType<string | number>,
@@ -26,4 +21,5 @@ export const basicProps = {
2621
required: false,
2722
default: 'auto',
2823
},
24+
showImageUpload: propTypes.bool.def(true),
2925
};

src/layouts/default/header/components/user-dropdown/index.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@
99

1010
<template #overlay>
1111
<Menu @click="handleMenuClick">
12-
<MenuItem key="doc" :text="t('layout.header.dropdownItemDoc')" icon="gg:loadbar-doc" />
13-
<MenuDivider v-if="getShowDoc" />
12+
<MenuItem
13+
key="doc"
14+
:text="t('layout.header.dropdownItemDoc')"
15+
icon="gg:loadbar-doc"
16+
v-if="getShowDoc"
17+
/>
18+
<MenuDivider />
1419
<MenuItem
1520
key="loginOut"
1621
:text="t('layout.header.dropdownItemLoginOut')"

src/layouts/default/header/index.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
} from './components';
8585
import { useAppInject } from '/@/hooks/web/useAppInject';
8686
import { useDesign } from '/@/hooks/web/useDesign';
87-
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
8887
8988
export default defineComponent({
9089
name: 'LayoutHeader',

src/locales/lang/en/component/upload.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export default {
22
save: 'Save',
33
upload: 'Upload',
4+
imgUpload: 'ImageUpload',
45
uploaded: 'Uploaded',
56

67
operating: 'Operating',

src/locales/lang/zh_CN/component/upload.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export default {
22
save: '保存',
33
upload: '上传',
4+
imgUpload: '图片上传',
45
uploaded: '已上传',
56

67
operating: '操作',

0 commit comments

Comments
 (0)