@ebl-vue/editor-full 1.0.13 → 1.1.2
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/dist/index.d.ts +1 -0
- package/dist/index.mjs +712 -584
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -2
- package/src/components/Editor/Editor.vue +52 -24
- package/src/index.ts +8 -2
- package/src/plugins/imageResizeCrop/ImageTune.ts +900 -0
- package/src/plugins/imageResizeCrop/index.css +234 -0
- package/src/plugins/imageResizeCrop/index.ts +5 -0
- package/src/plugins/imageResizeCrop/types.d.ts +23 -0
- package/src/plugins/imageTool/index.css +1 -1
- package/src/plugins/imageTool/index.ts +30 -11
- package/src/plugins/imageTool/types/types.ts +2 -0
- package/src/plugins/imageTool/ui.ts +3 -2
- package/src/plugins/imageTool/uploader.ts +137 -103
- package/src/plugins/imageTool/utils/index.ts +73 -0
- package/src/utils/AxiosService.ts +87 -0
- package/types/index.d.ts +6 -1
- package/types/plugins/index.d.ts +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import type { AjaxResponse } from '@codexteam/ajax';
|
|
1
|
+
|
|
3
2
|
import isPromise from './utils/isPromise';
|
|
4
3
|
import type { IUploadResponseFormat, UploadOptions } from './types/types';
|
|
5
4
|
import type { UploadResponseFormat, ImageConfig } from './types/types';
|
|
6
|
-
import axios, { AxiosInstance
|
|
5
|
+
import axios, { AxiosInstance } from "axios";
|
|
6
|
+
import { selectFiles } from './utils/index';
|
|
7
7
|
/**
|
|
8
8
|
* Params interface for Uploader constructor
|
|
9
9
|
*/
|
|
@@ -55,8 +55,8 @@ export default class Uploader {
|
|
|
55
55
|
* Fires ajax.transport()
|
|
56
56
|
* @param onPreview - callback fired when preview is ready
|
|
57
57
|
*/
|
|
58
|
-
public async uploadSelectedFile({ onPreview }: UploadOptions) {
|
|
59
|
-
|
|
58
|
+
public async uploadSelectedFile({ onPreview, noSelectedFile }: UploadOptions) {
|
|
59
|
+
|
|
60
60
|
const preparePreview = function (file: File): void {
|
|
61
61
|
const reader = new FileReader();
|
|
62
62
|
|
|
@@ -70,59 +70,70 @@ export default class Uploader {
|
|
|
70
70
|
* Custom uploading
|
|
71
71
|
* or default uploading
|
|
72
72
|
*/
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
let cdn: string = "";
|
|
75
75
|
let objectKey: string = "";
|
|
76
76
|
|
|
77
|
-
// custom uploading
|
|
78
|
-
if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') {
|
|
79
|
-
const uploadByFile = this.config.uploader.uploadByFile;
|
|
80
77
|
|
|
81
|
-
upload = ajax.selectFiles({ accept: this.config.types ?? 'image/*' }).then((files: File[]) => {
|
|
82
|
-
preparePreview(files[0]);
|
|
83
78
|
|
|
84
|
-
|
|
79
|
+
//选获取上传文件的地址
|
|
80
|
+
const files = await selectFiles({ accept: this.config.types ?? 'image/*' });
|
|
85
81
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
if (files && files.length > 0) {
|
|
83
|
+
preparePreview(files[0]);
|
|
84
|
+
} else {
|
|
85
|
+
noSelectedFile();
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
const file = files[0];
|
|
89
|
+
const fileTypes = this.config.types.split(",");
|
|
90
|
+
let suffixIndex = file.name.lastIndexOf(".");
|
|
91
|
+
let suffix = file.name.slice(suffixIndex);
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
if (!fileTypes.includes(suffix.toLowerCase())) {
|
|
94
|
+
this.onError("文件类型不支持");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const file = files[0];
|
|
101
|
-
const uploadBodyRes = await ajax.post({
|
|
102
|
-
url: this.config.endpoints.byFile,
|
|
103
|
-
data: Object.assign({
|
|
104
|
-
"fileName": file.name,
|
|
105
|
-
"contentType": file.type
|
|
106
|
-
}, this.config.additionalRequestData),
|
|
107
|
-
type: ajax.contentType.JSON,
|
|
108
|
-
|
|
109
|
-
});
|
|
110
|
-
const uploadRes = uploadBodyRes.body as IUploadResponseFormat;
|
|
111
|
-
if (!uploadRes.success) {
|
|
112
|
-
this.onError(uploadRes.message!);
|
|
113
|
-
return;
|
|
98
|
+
let headers: Record<string, string> = {};
|
|
99
|
+
if (this.config.userStore) {
|
|
100
|
+
const token = this.config.userStore.token;
|
|
101
|
+
const tokenName = this.config.userStore.tokenName;
|
|
102
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
103
|
+
if (token && tokenName) {
|
|
104
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
114
105
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
122
|
-
upload = axiosInstance.put(uploadRes.data.presignedUrl, file);
|
|
123
|
-
|
|
106
|
+
}
|
|
107
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
108
|
+
timeout: 1800000,
|
|
109
|
+
headers: headers,
|
|
110
|
+
});
|
|
111
|
+
headers["Content-Type"] = "application/json";
|
|
124
112
|
|
|
113
|
+
const uploadBodyRes = await axiosInstance.post(this.config.endpoints.byFile!, {
|
|
114
|
+
"fileName": file.name,
|
|
115
|
+
"contentType": file.type
|
|
116
|
+
})
|
|
117
|
+
if (uploadBodyRes.status !== 200) {
|
|
118
|
+
this.onError(uploadBodyRes.statusText);
|
|
119
|
+
return;
|
|
125
120
|
}
|
|
121
|
+
const uploadRes = uploadBodyRes.data;
|
|
122
|
+
if (!uploadRes.success) {
|
|
123
|
+
this.onError(uploadRes.message!);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
console.log(uploadRes);
|
|
127
|
+
cdn = uploadRes.data.cdn;
|
|
128
|
+
objectKey = uploadRes.data.objectKey;
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
headers["Content-Type"] = file.type;
|
|
132
|
+
|
|
133
|
+
let upload = axiosInstance.put(uploadRes.data.presignedUrl, file);
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
126
137
|
|
|
127
138
|
upload.then((response) => {
|
|
128
139
|
if (response.status === 200) {
|
|
@@ -144,35 +155,46 @@ export default class Uploader {
|
|
|
144
155
|
*/
|
|
145
156
|
public uploadByUrl(url: string): void {
|
|
146
157
|
let upload;
|
|
158
|
+
let headers: Record<string, string> = { "Content-Type": "application/json" };
|
|
159
|
+
if (this.config.userStore) {
|
|
160
|
+
const token = this.config.userStore.token;
|
|
161
|
+
const tokenName = this.config.userStore.tokenName;
|
|
162
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
163
|
+
if (token && tokenName) {
|
|
164
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
168
|
+
timeout: 1800000,
|
|
169
|
+
headers: headers,
|
|
170
|
+
});
|
|
171
|
+
upload = axiosInstance.post(this.config.endpoints.byUrl!, {
|
|
172
|
+
"url": url,
|
|
173
|
+
"accept": ".jpg,.jpeg,.gif,.png,.webp"
|
|
174
|
+
})
|
|
175
|
+
|
|
147
176
|
|
|
148
|
-
/**
|
|
149
|
-
* Custom uploading
|
|
150
|
-
*/
|
|
151
|
-
if (this.config.uploader && typeof this.config.uploader.uploadByUrl === 'function') {
|
|
152
|
-
upload = this.config.uploader.uploadByUrl(url);
|
|
153
177
|
|
|
154
|
-
|
|
155
|
-
|
|
178
|
+
|
|
179
|
+
upload.then((response) => {
|
|
180
|
+
|
|
181
|
+
if(response.status !== 200||response.data.success===false){
|
|
182
|
+
this.onError(response.data.message!);
|
|
183
|
+
return;
|
|
156
184
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*/
|
|
161
|
-
upload = ajax.post({
|
|
162
|
-
url: this.config.endpoints.byUrl,
|
|
163
|
-
data: Object.assign({
|
|
164
|
-
url: url,
|
|
165
|
-
}, this.config.additionalRequestData),
|
|
166
|
-
type: ajax.contentType.JSON,
|
|
167
|
-
headers: this.config.additionalRequestHeaders as Record<string, string>,
|
|
168
|
-
}).then((response: AjaxResponse) => response.body as UploadResponseFormat);
|
|
169
|
-
}
|
|
185
|
+
|
|
186
|
+
let cdn = response.data.data.cdn;
|
|
187
|
+
let objectKey = response.data.data.objectKey;
|
|
170
188
|
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
let res = {
|
|
190
|
+
success: 1,
|
|
191
|
+
file: { url: cdn + objectKey }
|
|
192
|
+
};
|
|
193
|
+
this.onUpload(res);
|
|
173
194
|
}).catch((error: string) => {
|
|
174
195
|
this.onError(error);
|
|
175
196
|
});
|
|
197
|
+
|
|
176
198
|
}
|
|
177
199
|
|
|
178
200
|
/**
|
|
@@ -181,51 +203,63 @@ export default class Uploader {
|
|
|
181
203
|
* @param file - file pasted by drag-n-drop
|
|
182
204
|
* @param onPreview - file pasted by drag-n-drop
|
|
183
205
|
*/
|
|
184
|
-
public uploadByFile(file: Blob, { onPreview }: UploadOptions)
|
|
185
|
-
/**
|
|
186
|
-
* Load file for preview
|
|
187
|
-
*/
|
|
188
|
-
const reader = new FileReader();
|
|
206
|
+
public async uploadByFile(file: Blob, { onPreview }: UploadOptions) {
|
|
189
207
|
|
|
190
|
-
reader.readAsDataURL(file);
|
|
191
|
-
reader.onload = (e) => {
|
|
192
|
-
onPreview((e.target as FileReader).result as string);
|
|
193
|
-
};
|
|
194
208
|
|
|
195
|
-
|
|
209
|
+
const fileTypes = this.config.types.split(",");
|
|
196
210
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*/
|
|
200
|
-
if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') {
|
|
201
|
-
upload = this.config.uploader.uploadByFile(file);
|
|
211
|
+
let suffixIndex = file.name.lastIndexOf(".");
|
|
212
|
+
let suffix = file.name.slice(suffixIndex);
|
|
202
213
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Default uploading
|
|
209
|
-
*/
|
|
210
|
-
const formData = new FormData();
|
|
214
|
+
if (!fileTypes.includes(suffix.toLowerCase())) {
|
|
215
|
+
this.onError("文件类型不支持");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
211
218
|
|
|
212
|
-
formData.append(this.config.field ?? 'image', file);
|
|
213
219
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
|
|
221
|
+
let headers: Record<string, string> = {};
|
|
222
|
+
if (this.config.userStore) {
|
|
223
|
+
const token = this.config.userStore.token;
|
|
224
|
+
const tokenName = this.config.userStore.tokenName;
|
|
225
|
+
const tokenPrefix = this.config.userStore.tokenPrefix;
|
|
226
|
+
if (token && tokenName) {
|
|
227
|
+
headers[tokenName] = tokenPrefix + " " + token
|
|
218
228
|
}
|
|
229
|
+
}
|
|
230
|
+
const axiosInstance: AxiosInstance = axios.create({
|
|
231
|
+
timeout: 1800000,
|
|
232
|
+
headers: headers,
|
|
233
|
+
});
|
|
234
|
+
headers["Content-Type"] = "application/json";
|
|
219
235
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
236
|
+
const uploadBodyRes = await axiosInstance.post(this.config.endpoints.byFile!, {
|
|
237
|
+
"fileName": file.name,
|
|
238
|
+
"contentType": file.type
|
|
239
|
+
})
|
|
240
|
+
if (uploadBodyRes.status !== 200) {
|
|
241
|
+
this.onError(uploadBodyRes.statusText);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const uploadRes = uploadBodyRes.data;
|
|
245
|
+
if (!uploadRes.success) {
|
|
246
|
+
this.onError(uploadRes.message!);
|
|
247
|
+
return;
|
|
226
248
|
}
|
|
249
|
+
console.log(uploadRes);
|
|
250
|
+
let cdn = uploadRes.data.cdn;
|
|
251
|
+
let objectKey = uploadRes.data.objectKey;
|
|
227
252
|
|
|
253
|
+
|
|
254
|
+
headers["Content-Type"] = file.type;
|
|
255
|
+
let upload = axiosInstance.put(uploadRes.data.presignedUrl, file);
|
|
228
256
|
upload.then((response) => {
|
|
257
|
+
if (response.status === 200) {
|
|
258
|
+
response = {
|
|
259
|
+
success: 1,
|
|
260
|
+
file: { url: cdn + objectKey }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
229
263
|
this.onUpload(response);
|
|
230
264
|
}).catch((error: string) => {
|
|
231
265
|
this.onError(error);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
interface IConfig {
|
|
2
|
+
multiple?: boolean;
|
|
3
|
+
accept?: string;
|
|
4
|
+
}
|
|
5
|
+
export function selectFiles(config = {} as IConfig): Promise<File[]> {
|
|
6
|
+
let fileCancle = true;
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
/**
|
|
9
|
+
* Create a new INPUT element
|
|
10
|
+
* @type {HTMLElement}
|
|
11
|
+
*/
|
|
12
|
+
let inputElement = document.createElement('INPUT');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Set a 'FILE' type for this input element
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
inputElement.type = 'file';
|
|
19
|
+
|
|
20
|
+
if (config.multiple) {
|
|
21
|
+
inputElement.setAttribute('multiple', 'multiple');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (config.accept) {
|
|
25
|
+
inputElement.setAttribute('accept', config.accept);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Do not show element
|
|
30
|
+
*/
|
|
31
|
+
inputElement.style.display = 'none';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Append element to the body
|
|
35
|
+
* Fix using module on mobile devices
|
|
36
|
+
*/
|
|
37
|
+
document.body.appendChild(inputElement);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add onchange listener for «choose file» pop-up
|
|
41
|
+
*/
|
|
42
|
+
inputElement.addEventListener('change', event => {
|
|
43
|
+
console.log("选中文件")
|
|
44
|
+
fileCancle = false;
|
|
45
|
+
/**
|
|
46
|
+
* Get files from input field
|
|
47
|
+
*/
|
|
48
|
+
const files = event.target.files;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return ready to be uploaded files array
|
|
52
|
+
*/
|
|
53
|
+
resolve(files);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Remove element from a DOM
|
|
57
|
+
*/
|
|
58
|
+
document.body.removeChild(inputElement);
|
|
59
|
+
}, false);
|
|
60
|
+
window.addEventListener("focus", () => {
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
if (fileCancle) {
|
|
63
|
+
console.log("取消选择文件")
|
|
64
|
+
resolve([]);
|
|
65
|
+
}
|
|
66
|
+
}, 1000)
|
|
67
|
+
},{once: true})
|
|
68
|
+
/**
|
|
69
|
+
* Fire click event on «input file» field
|
|
70
|
+
*/
|
|
71
|
+
inputElement.click();
|
|
72
|
+
});
|
|
73
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from "axios";
|
|
2
|
+
import { ElMessage } from "element-plus"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
interface IAxiosServiceConstructorParams{
|
|
6
|
+
appBaseApi?: string,
|
|
7
|
+
timeout?:number,
|
|
8
|
+
eblStoreUser?: any|undefined
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class AxiosService {
|
|
12
|
+
appBaseApi: string = "";
|
|
13
|
+
timeout: number = 30000;
|
|
14
|
+
eblStoreUser: any|undefined;
|
|
15
|
+
axiosInstance: AxiosInstance | undefined;
|
|
16
|
+
|
|
17
|
+
constructor(params?: IAxiosServiceConstructorParams | undefined ) {
|
|
18
|
+
if (typeof params !== "undefined") {
|
|
19
|
+
if (params.appBaseApi) {
|
|
20
|
+
this.appBaseApi = params.appBaseApi;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (params.timeout) {
|
|
24
|
+
this.timeout = params.timeout;
|
|
25
|
+
}
|
|
26
|
+
if (params.eblStoreUser) {
|
|
27
|
+
this.eblStoreUser = params.eblStoreUser;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
createAxios():AxiosInstance {
|
|
34
|
+
//创建实例
|
|
35
|
+
this.axiosInstance = axios.create({
|
|
36
|
+
baseURL: this.appBaseApi,
|
|
37
|
+
timeout: this.timeout,
|
|
38
|
+
headers: { "Content-Type": "application/json;charset=utf-8" },
|
|
39
|
+
});
|
|
40
|
+
//请求拦截
|
|
41
|
+
this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
|
42
|
+
|
|
43
|
+
if (this.eblStoreUser) {
|
|
44
|
+
const token = this.eblStoreUser.token;
|
|
45
|
+
const tokenName = this.eblStoreUser.tokenName;
|
|
46
|
+
const tokenPrefix = this.eblStoreUser.tokenPrefix;
|
|
47
|
+
if (token && tokenName) {
|
|
48
|
+
config.headers[tokenName] = tokenPrefix + " " + token;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return config;
|
|
52
|
+
}, (error: any) => {
|
|
53
|
+
return Promise.reject(error);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// 响应拦截器
|
|
57
|
+
this.axiosInstance.interceptors.response.use((response: AxiosResponse) => {
|
|
58
|
+
const { code, message } = response.data;
|
|
59
|
+
if (code === 1) {
|
|
60
|
+
return response.data;
|
|
61
|
+
}
|
|
62
|
+
ElMessage.error(message || "系统出错");
|
|
63
|
+
return response.data;
|
|
64
|
+
}, (error: any) => {
|
|
65
|
+
if (error) {
|
|
66
|
+
const { message } = error;
|
|
67
|
+
ElMessage.error(message || "系统出错");
|
|
68
|
+
}
|
|
69
|
+
return Promise.reject(error.message);
|
|
70
|
+
});
|
|
71
|
+
return this.axiosInstance;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static instance(appBaseApi: string|undefined, timeout: number, eblStoreUser?: any) {
|
|
75
|
+
let options:any = { appBaseApi: appBaseApi, timeout: timeout };
|
|
76
|
+
if (eblStoreUser) {
|
|
77
|
+
options.eblStoreUser = eblStoreUser;
|
|
78
|
+
}
|
|
79
|
+
let service = new AxiosService(options);
|
|
80
|
+
return service.createAxios();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
export default AxiosService;
|
|
86
|
+
type IAxiosService = InstanceType<typeof AxiosService>;
|
|
87
|
+
export { IAxiosService }
|
package/types/index.d.ts
CHANGED
|
@@ -4,15 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
import type { INSTALLED_KEY } from '@/constants'
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
declare module 'vue' {
|
|
8
9
|
export interface App {
|
|
9
10
|
[INSTALLED_KEY]?: boolean
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
export interface GlobalComponents {
|
|
13
|
+
EblEditor: typeof import('@ebl-vue/editor-full')['EblEditor'],
|
|
14
|
+
|
|
15
|
+
}
|
|
12
16
|
};
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
export interface IEblEditorSettings{
|
|
16
20
|
fileUploadEndpoint: string;
|
|
17
21
|
urlUploadEndpoint: string;
|
|
22
|
+
userStore: any;
|
|
18
23
|
}
|
package/types/plugins/index.d.ts
DELETED
|
File without changes
|