@ebiz/designer-components 0.1.55 → 0.1.57

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": "@ebiz/designer-components",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,7 +25,9 @@
25
25
  "unplugin-auto-import": "^19.0.0",
26
26
  "unplugin-vue-components": "^28.0.0",
27
27
  "vue": "^3.5.13",
28
- "vue-router": "^4.2.5"
28
+ "vue-router": "^4.2.5",
29
+ "@wangeditor/editor": "^5.1.23",
30
+ "@wangeditor/editor-for-vue": "^5.1.12"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@opentiny/tiny-engine-mock": "^2.1.0",
@@ -92,7 +92,7 @@ interface Employee {
92
92
  interface Props {
93
93
  approverList: (string | number)[] // 选中的审批人ID列表
94
94
  ccList: (string | number)[] // 选中的抄送人ID列表
95
- key: string // 审批流程的唯一标识
95
+ workFlowKey: string // 审批流程的唯一标识
96
96
  id: number // 审批流程的编号
97
97
  required: boolean // 是否必填
98
98
  type?: 'organization' | 'role' | 'all' // 查询类型
@@ -106,7 +106,7 @@ interface Props {
106
106
  const props = withDefaults(defineProps<Props>(), {
107
107
  approverList: () => [],
108
108
  ccList: () => [],
109
- key: '',
109
+ workFlowKey: '',
110
110
  id: 0,
111
111
  required: true,
112
112
  showRootOrg: true,
@@ -120,7 +120,7 @@ const emit = defineEmits(['update:approverList', 'update:ccList', 'change'])
120
120
  const fetchHistory = () => {
121
121
  dataService.fetch({
122
122
  bussinessKey: props.id ? props.id.toString() : null,
123
- type: props.key
123
+ type: props.workFlowKey
124
124
  }, {}, '/tasks/process/detail').then(res => {
125
125
  selectedApprover.value = res?.variables?.form?.approverList ?? [];
126
126
  selectedCC.value = res?.variables?.form?.ccList ?? [];
@@ -244,7 +244,7 @@ const handleAddCC = () => {
244
244
 
245
245
 
246
246
  // 监听查询条件变化
247
- watch([() => props.type, () => props.value, () => props.showRootOrg, () => props.childDeptEnable], () => {
247
+ watch([() => props.type, () => props.value, () => props.showRootOrg, () => props.childDeptEnable,()=>props.workFlowKey], () => {
248
248
  fetchEmployeeList()
249
249
  }, { immediate: true })
250
250
  </script>
@@ -123,7 +123,7 @@
123
123
  <t-avatar v-if="item.avatar" :image="item.avatar" size="small" />
124
124
  <t-avatar v-else size="small">{{ getAvatarText(item.name) }}</t-avatar>
125
125
  </div>
126
- <div style="display: flex; align-items: center; justify-content: space-between; width: 350px;">
126
+ <div style="display: flex; align-items: center; justify-content: space-between; width: 300px;">
127
127
  <div class="employee-info">
128
128
  <div class="employee-code">{{ item.no }} - </div>
129
129
  <div class="employee-name">{{ item.name }}</div>
@@ -150,7 +150,7 @@
150
150
  <t-avatar v-if="item.avatar" :image="item.avatar" size="small" />
151
151
  <t-avatar v-else size="small">{{ getAvatarText(item.name) }}</t-avatar>
152
152
  </div>
153
- <div style="display: flex; align-items: center; justify-content: space-between;width: 350px;">
153
+ <div style="display: flex; align-items: center; justify-content: space-between;width: 300px;">
154
154
  <div class="employee-info">
155
155
  <div class="employee-code">{{ item.no }} - </div>
156
156
  <div class="employee-name">{{ item.name }}</div>
@@ -0,0 +1,276 @@
1
+ <template>
2
+ <div class="ebiz-rich-text-editor" style="border: 1px solid #ccc">
3
+ <Toolbar
4
+ style="border-bottom: 1px solid #ccc"
5
+ :editor="editorRef"
6
+ :defaultConfig="mergedToolbarConfig"
7
+ :mode="mode"
8
+ />
9
+ <Editor
10
+ :style="{height: `${height}px`, overflowY: 'hidden'}"
11
+ v-model="computedModelValue"
12
+ :defaultConfig="mergedEditorConfig"
13
+ :mode="mode"
14
+ @onCreated="handleCreated"
15
+ @onChange="handleChange"
16
+ @onDestroyed="handleDestroyed"
17
+ @onFocus="handleFocus"
18
+ @onBlur="handleBlur"
19
+ @customAlert="handleCustomAlert"
20
+ @customPaste="handleCustomPaste"
21
+ />
22
+ </div>
23
+ </template>
24
+
25
+ <script>
26
+ /**
27
+ * @displayName 富文本编辑器
28
+ * @description 基于WangEditor的富文本编辑器组件,支持图片和视频上传
29
+ * @category 表单组件
30
+ * @name EbizRichTextEditor
31
+ */
32
+ export default {
33
+ name: "EbizRichTextEditor"
34
+ }
35
+ </script>
36
+
37
+ <script setup>
38
+ import '@wangeditor/editor/dist/css/style.css'
39
+ import { defineProps, defineEmits, computed, ref, shallowRef, onBeforeUnmount, onMounted } from 'vue'
40
+ import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
41
+ // import { upload } from '../utils/upload'
42
+
43
+ // 编辑器实例,必须用 shallowRef
44
+ const editorRef = shallowRef()
45
+
46
+ // 编辑器内容
47
+ const valueHtml = ref('')
48
+
49
+ // 编辑器模式
50
+ const mode = ref('default') // 或 'simple'
51
+
52
+ const props = defineProps({
53
+ /**
54
+ * 绑定的值
55
+ */
56
+ modelValue: {
57
+ type: String,
58
+ default: ''
59
+ },
60
+ /**
61
+ * 是否禁用
62
+ */
63
+ disabled: {
64
+ type: Boolean,
65
+ default: false
66
+ },
67
+ /**
68
+ * 是否只读
69
+ */
70
+ readonly: {
71
+ type: Boolean,
72
+ default: false
73
+ },
74
+ /**
75
+ * 占位文本
76
+ */
77
+ placeholder: {
78
+ type: String,
79
+ default: '请输入内容...'
80
+ },
81
+ /**
82
+ * 编辑器高度
83
+ */
84
+ height: {
85
+ type: [String, Number],
86
+ default: 300
87
+ },
88
+ /**
89
+ * 工具栏配置
90
+ */
91
+ toolbarConfig: {
92
+ type: Object,
93
+ default: () => ({})
94
+ },
95
+ /**
96
+ * 编辑器配置
97
+ */
98
+ editorConfig: {
99
+ type: Object,
100
+ default: () => ({})
101
+ },
102
+ /**
103
+ * 图片上传路径
104
+ */
105
+ imagePath: {
106
+ type: String,
107
+ default: 'editor'
108
+ },
109
+ /**
110
+ * 视频上传路径
111
+ */
112
+ videoPath: {
113
+ type: String,
114
+ default: 'video'
115
+ },
116
+ /**
117
+ * 最大长度
118
+ */
119
+ maxLength: {
120
+ type: Number,
121
+ default: undefined
122
+ }
123
+ });
124
+
125
+ const emit = defineEmits([
126
+ 'update:modelValue',
127
+ 'change',
128
+ 'focus',
129
+ 'blur',
130
+ 'created',
131
+ 'destroyed'
132
+ ]);
133
+
134
+ // 计算属性处理v-model双向绑定
135
+ const computedModelValue = computed({
136
+ get: () => props.modelValue,
137
+ set: (val) => {
138
+ emit('update:modelValue', val);
139
+ }
140
+ });
141
+
142
+ // 合并工具栏配置
143
+ const mergedToolbarConfig = computed(() => {
144
+ return {
145
+ ...props.toolbarConfig
146
+ };
147
+ });
148
+
149
+ // 合并编辑器配置
150
+ const mergedEditorConfig = computed(() => {
151
+ return {
152
+ placeholder: props.placeholder,
153
+ readOnly: props.disabled || props.readonly,
154
+ maxLength: props.maxLength,
155
+ MENU_CONF: {
156
+ uploadImage: {
157
+ customUpload(file, insertFn) {
158
+
159
+ upload({
160
+ path: props.imagePath,
161
+ file: {
162
+ name: file.name,
163
+ raw: file
164
+ },
165
+ onSuccess: (res) => {
166
+ insertFn(res.url, '', '');
167
+ }
168
+ });
169
+ },
170
+ },
171
+ uploadVideo: {
172
+ customUpload(file, insertFn) {
173
+ upload({
174
+ path: props.videoPath,
175
+ file: {
176
+ name: file.name,
177
+ raw: file
178
+ },
179
+ onSuccess: (res) => {
180
+ insertFn(res.url, '', '');
181
+ }
182
+ });
183
+ },
184
+ },
185
+ ...props.editorConfig?.MENU_CONF
186
+ },
187
+ ...props.editorConfig
188
+ };
189
+ });
190
+
191
+ // 编辑器创建完成回调
192
+ const handleCreated = (editor) => {
193
+ editorRef.value = editor; // 记录编辑器实例
194
+ emit('created', editor);
195
+ };
196
+
197
+ // 内容变化事件
198
+ const handleChange = (editor) => {
199
+ emit('change', editor.getHtml());
200
+ };
201
+
202
+ // 销毁事件
203
+ const handleDestroyed = (editor) => {
204
+ emit('destroyed', editor);
205
+ };
206
+
207
+ // 获得焦点事件
208
+ const handleFocus = (editor) => {
209
+ emit('focus', editor);
210
+ };
211
+
212
+ // 失去焦点事件
213
+ const handleBlur = (editor) => {
214
+ emit('blur', editor);
215
+ };
216
+
217
+ // 自定义提示事件
218
+ const handleCustomAlert = (info, type) => {
219
+ console.log(`【自定义提示】${type} - ${info}`);
220
+ };
221
+
222
+ // 自定义粘贴事件
223
+ const handleCustomPaste = (editor, event, callback) => {
224
+ console.log('ClipboardEvent 粘贴事件对象', event);
225
+ // 返回值(注意,vue 事件的返回值,不能用 return)
226
+ callback(true); // true 继续默认的粘贴行为
227
+ };
228
+
229
+ // 组件销毁时,销毁编辑器实例
230
+ onBeforeUnmount(() => {
231
+ const editor = editorRef.value;
232
+ if (editor === null) return;
233
+ editor.destroy();
234
+ });
235
+
236
+ // 暴露编辑器实例和方法
237
+ defineExpose({
238
+ editor: editorRef,
239
+ insertText: (text) => {
240
+ if (editorRef.value) {
241
+ editorRef.value.insertText(text);
242
+ }
243
+ },
244
+ getHtml: () => {
245
+ if (editorRef.value) {
246
+ return editorRef.value.getHtml();
247
+ }
248
+ return '';
249
+ },
250
+ getText: () => {
251
+ if (editorRef.value) {
252
+ return editorRef.value.getText();
253
+ }
254
+ return '';
255
+ }
256
+ });
257
+ </script>
258
+
259
+ <style scoped>
260
+ .ebiz-rich-text-editor {
261
+ border-radius: var(--td-radius-default);
262
+ overflow: hidden;
263
+ }
264
+
265
+ .ebiz-rich-text-editor :deep(.w-e-text-container) {
266
+ z-index: 1; /* 避免编辑区域遮挡其他元素 */
267
+ }
268
+
269
+ .ebiz-rich-text-editor :deep(.w-e-toolbar) {
270
+ z-index: 2; /* 确保工具栏在编辑区域之上 */
271
+ }
272
+
273
+ .ebiz-rich-text-editor :deep(.w-e-text-placeholder) {
274
+ color: var(--td-text-color-placeholder);
275
+ }
276
+ </style>
@@ -121,6 +121,23 @@
121
121
  @change="handleChange" />
122
122
  </template>
123
123
 
124
+ <!-- 富文本编辑器 -->
125
+ <template v-else-if="type === 'rich-text'">
126
+ <ebiz-rich-text-editor
127
+ v-model="computedModelValue"
128
+ :placeholder="placeholder || '请输入内容'"
129
+ :disabled="disabled"
130
+ :readonly="readonly"
131
+ :height="editorHeight"
132
+ :toolbar-config="editorToolbarConfig"
133
+ :editor-config="editorConfig"
134
+ :image-path="editorImagePath"
135
+ :video-path="editorVideoPath"
136
+ :max-length="maxLength"
137
+ @change="handleChange"
138
+ />
139
+ </template>
140
+
124
141
  <!-- 子表格 -->
125
142
  <template v-else-if="type === 'table'">
126
143
  <div class="ebiz-form-table">
@@ -239,7 +256,7 @@ export default {
239
256
  </script>
240
257
 
241
258
  <script setup>
242
- import { defineProps, defineEmits, computed, watch } from 'vue';
259
+ import { defineProps, defineEmits, computed, watch, onMounted } from 'vue';
243
260
  import {
244
261
  FormItem as TFormItem,
245
262
  Input as TInput,
@@ -263,6 +280,7 @@ import EbizRemoteSelect from '../../EbizRemoteSelect.vue';
263
280
  import EbizEmployeeSelector from '../../EbizEmployeeSelector.vue';
264
281
  import EbizDepartmentSelector from '../../EbizDepartmentSelector.vue';
265
282
  import { EbizUpload } from '../../../index.js'
283
+ import EbizRichTextEditor from '../../EbizRichTextEditor.vue';
266
284
 
267
285
  const props = defineProps({
268
286
  /**
@@ -275,7 +293,7 @@ const props = defineProps({
275
293
  validator: (val) => [
276
294
  'input', 'number', 'textarea', 'select', 'date', 'datetime', 'time', 'radio',
277
295
  'checkbox', 'switch', 'slider', 'upload', 'cascader', 'tree-select',
278
- 'color-picker', 'employee', 'dept', 'table'
296
+ 'color-picker', 'employee', 'dept', 'table', 'rich-text'
279
297
  ].includes(val)
280
298
  },
281
299
  /**
@@ -649,6 +667,41 @@ const props = defineProps({
649
667
  addButtonText: {
650
668
  type: String,
651
669
  default: '添加数据'
670
+ },
671
+ /**
672
+ * 富文本编辑器高度
673
+ */
674
+ editorHeight: {
675
+ type: [String, Number],
676
+ default: 300
677
+ },
678
+ /**
679
+ * 富文本编辑器工具栏配置
680
+ */
681
+ editorToolbarConfig: {
682
+ type: Object,
683
+ default: () => ({})
684
+ },
685
+ /**
686
+ * 富文本编辑器配置
687
+ */
688
+ editorConfig: {
689
+ type: Object,
690
+ default: () => ({})
691
+ },
692
+ /**
693
+ * 富文本图片上传路径
694
+ */
695
+ editorImagePath: {
696
+ type: String,
697
+ default: 'editor'
698
+ },
699
+ /**
700
+ * 富文本视频上传路径
701
+ */
702
+ editorVideoPath: {
703
+ type: String,
704
+ default: 'video'
652
705
  }
653
706
  });
654
707
 
@@ -804,6 +857,10 @@ watch(
804
857
  },
805
858
  { deep: true }
806
859
  );
860
+
861
+ // 组件挂载时初始化文件列表
862
+ onMounted(() => {
863
+ });
807
864
  </script>
808
865
 
809
866
  <style scoped>
package/src/index.js CHANGED
@@ -100,6 +100,7 @@ import EbizFileList from './components/EbizFileList.vue'
100
100
  import EbizDetailView from './components/EbizDetailView.vue'
101
101
  import EbizDetailItem from './components/EbizDetailItem.vue'
102
102
  import EbizPdfViewer from './components/EbizPdfViewer.vue'
103
+ import EbizRichTextEditor from './components/EbizRichTextEditor.vue'
103
104
 
104
105
  // 导出组件
105
106
  export {
@@ -242,5 +243,7 @@ export {
242
243
  EbizDetailView,
243
244
  EbizDetailItem,
244
245
  // PDF预览组件
245
- EbizPdfViewer
246
+ EbizPdfViewer,
247
+ // 富文本编辑器组件
248
+ EbizRichTextEditor
246
249
  }
@@ -4,12 +4,7 @@
4
4
  <div class="demo-section">
5
5
  <h3>基础表单示例</h3>
6
6
  <div class="demo-block">
7
- <ebiz-s-form
8
- ref="basicFormRef"
9
- :data="formData"
10
- :rules="formRules"
11
- show-error-message
12
- @success="handleSuccess"
7
+ <ebiz-s-form ref="basicFormRef" :data="formData" :rules="formRules" show-error-message @success="handleSuccess"
13
8
  @error="handleError">
14
9
  <ebiz-s-form-item label="姓名" name="name" type="input" placeholder="请输入姓名"></ebiz-s-form-item>
15
10
  <ebiz-s-form-item label="年龄" name="age" type="number" placeholder="请输入年龄"></ebiz-s-form-item>
@@ -17,6 +12,10 @@
17
12
  <ebiz-s-form-item label="爱好" name="hobbies" type="checkbox" :options="hobbyOptions"></ebiz-s-form-item>
18
13
  <ebiz-s-form-item label="职业" name="occupation" type="select" :options="occupationOptions"></ebiz-s-form-item>
19
14
  <ebiz-s-form-item label="出生日期" name="birthday" type="date"></ebiz-s-form-item>
15
+
16
+ <ebiz-s-form-item v-model="formData.richText" label="富文本" name="richText" type="rich-text"></ebiz-s-form-item>
17
+
18
+
20
19
  {{ formData.bio }}
21
20
  <ebiz-s-form-item v-model="formData.bio" label="简介" name="bio" type="table" :tableColumns="[
22
21
  { name: '名称', key: 'name' },
@@ -33,16 +32,9 @@
33
32
  <t-button @click="openEditFormWithData">打开编辑表单(预设数据)</t-button>
34
33
  <t-button @click="openEditFormWithId">打开编辑表单(加载详情)</t-button>
35
34
  </t-space>
36
- <ebiz-s-form
37
- ref="editFormRef"
38
- :api-config="submitApiConfig"
39
- :detail-api-config="detailApiConfig"
40
- :rules="editFormRules"
41
- show-error-message
42
- reset-on-success
43
- @success="handleEditSuccess"
44
- @error="handleEditError"
45
- @detail-loaded="handleDetailLoaded">
35
+ <ebiz-s-form ref="editFormRef" :api-config="submitApiConfig" :detail-api-config="detailApiConfig"
36
+ :rules="editFormRules" show-error-message reset-on-success @success="handleEditSuccess"
37
+ @error="handleEditError" @detail-loaded="handleDetailLoaded">
46
38
  <ebiz-s-form-item label="ID" name="id" type="input" disabled></ebiz-s-form-item>
47
39
  <ebiz-s-form-item label="标题" name="title" type="input" placeholder="请输入标题"></ebiz-s-form-item>
48
40
  <ebiz-s-form-item label="内容" name="body" type="textarea" placeholder="请输入内容"></ebiz-s-form-item>
@@ -54,10 +46,7 @@
54
46
  <div class="demo-section">
55
47
  <h3>行内表单示例</h3>
56
48
  <div class="demo-block">
57
- <ebiz-s-form
58
- :data="inlineFormData"
59
- layout="inline"
60
- label-width="60px">
49
+ <ebiz-s-form :data="inlineFormData" layout="inline" label-width="60px">
61
50
  <ebiz-s-form-item label="用户名" name="username" type="input" placeholder="请输入用户名"></ebiz-s-form-item>
62
51
  <ebiz-s-form-item label="密码" name="password" type="input" placeholder="请输入密码"></ebiz-s-form-item>
63
52
  </ebiz-s-form>
@@ -84,9 +73,7 @@
84
73
  <div class="demo-section">
85
74
  <h3>顶部标签表单示例</h3>
86
75
  <div class="demo-block">
87
- <ebiz-s-form
88
- :data="topLabelFormData"
89
- label-align="top">
76
+ <ebiz-s-form :data="topLabelFormData" label-align="top">
90
77
  <ebiz-s-form-item label="邮箱" name="email" type="input" placeholder="请输入邮箱"></ebiz-s-form-item>
91
78
  <ebiz-s-form-item label="手机号" name="phone" type="input" placeholder="请输入手机号"></ebiz-s-form-item>
92
79
  <ebiz-s-form-item label="是否启用" name="enabled" type="switch"></ebiz-s-form-item>
@@ -1,126 +0,0 @@
1
- import {request} from "./request";
2
- import COS from "cos-js-sdk-v5";
3
- import OSS from "ali-oss";
4
- import moment from "moment/moment";
5
-
6
- const defaultOnPercent = () => {
7
- }
8
- const defaultOnSuccess = () => {
9
- }
10
- const defaultOnFail = () => {
11
- }
12
-
13
- export const upload = (options: any) => {
14
- const path: string = options.path;
15
- const file: any = options.file;
16
- const onPercent: Function = options.onProgress || defaultOnPercent;
17
- const onSuccess: Function = options.onSuccess || defaultOnSuccess;
18
- const onFail: Function = options.onFail || defaultOnFail;
19
-
20
- let credentials: any, url;
21
- request.get({
22
- url: "/file/getSecretKey"
23
- }).then((res) => {
24
- if (res.oss_type === 'ALIYUN') {
25
- const client = new OSS({
26
- // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
27
- region: res.region,
28
- // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
29
- accessKeyId: res.accessKeyId,
30
- accessKeySecret: res.accessKeySecret,
31
- // 从STS服务获取的安全令牌(SecurityToken)。
32
- stsToken: res.securityToken,
33
- // 刷新临时访问凭证的时间间隔,单位为毫秒。
34
- refreshSTSTokenInterval: 300000,
35
- // 填写Bucket名称。
36
- bucket: res.bucket
37
- });
38
- const options = {
39
- mime: "json",
40
- headers: {"Content-Type": "text/plain"},
41
- };
42
- client.put(handleUploadName("img", path, file.name), file.raw, options).then((uploadRes: any) => {
43
- console.log(uploadRes)
44
- // 创建一个 URL 对象
45
- const urlObj = new URL(uploadRes.url);
46
- // 从 URL 对象中获取路径部分
47
- const url = res.host + urlObj.pathname.substring(1);
48
-
49
- request.get({
50
- url: "/file/getAccessUrl",
51
- params: {
52
- url,
53
- }
54
- }).then(res => {
55
- console.log(res)
56
- onSuccess({url: res})
57
- })
58
- }).catch((e: any) => {
59
- onFail(e)
60
- });
61
- } else {
62
- credentials = res.credentials;
63
- let cos = new COS({
64
- getAuthorization: function (options, callback) {
65
- callback({
66
- TmpSecretId: credentials.tmpSecretId,
67
- TmpSecretKey: credentials.tmpSecretKey,
68
- SecurityToken: credentials.sessionToken,
69
- StartTime: credentials.startTime,
70
- ExpiredTime: credentials.expiredTime
71
- });
72
- }
73
- });
74
- cos.uploadFile(
75
- {
76
- Bucket: credentials.bucket,
77
- Region: credentials.region,
78
- Key: handleUploadName("img", path, file.name),
79
- Body: file.raw,
80
- SliceSize: 1024 * 1024 * 5 /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */,
81
- onProgress: (progressData) => {
82
- if (!!onPercent) {
83
- onPercent({file, percent: progressData.percent});
84
- }
85
- },
86
- onFileFinish: (err, data, options) => {
87
- url = credentials.path + "/" + options.Key;
88
- request.get({
89
- url: "/file/getAccessUrl",
90
- params: {
91
- url,
92
- }
93
- }).then(res => {
94
- console.log(res)
95
- onPercent({file, percent: 100});
96
- onSuccess({url: res})
97
- })
98
- }
99
- },
100
- function (err, data) {
101
- onFail(err)
102
- }
103
- );
104
- }
105
-
106
- });
107
- }
108
-
109
-
110
- // 规范上传图片格式
111
- const handleUploadName = function (type: string, path: string, file_name: string) {
112
- // /img/类型(avatar/category/article)/年月日/md5(文件名+随机字符串+毫秒数)+时间.文件后缀
113
- let newFileName =
114
- type +
115
- '/' +
116
- path +
117
- '/' +
118
- moment(new Date()).format('YYMMDD') +
119
- '/' +
120
- file_name.split(file_name.substring(file_name.lastIndexOf('.')))[0] +
121
- Math.random().toString(36).substring(2) +
122
- Date.now() +
123
- moment(new Date()).format('HHmm') +
124
- file_name.substring(file_name.lastIndexOf('.'));
125
- return newFileName;
126
- };