xianniu-ui 0.9.13 → 2.0.1

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/src/oss/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const OSS = require('ali-oss');
2
2
  import $dayjs from '@/utils/dayjs';
3
- const { v4: uuidv4 } = require('uuid');
4
3
 
5
4
  class Client {
6
5
  constructor(params = {}) {
@@ -14,15 +13,11 @@ class Client {
14
13
  const _token = localStorage.getItem('xnToken');
15
14
  if (!_token) return '';
16
15
 
17
- let token = ''
18
- if (_token) {
19
- try {
20
- token = JSON.parse(_token)
21
- } catch (error) {
22
- token = _token
23
- }
16
+ try {
17
+ return JSON.parse(_token);
18
+ } catch (error) {
19
+ return _token;
24
20
  }
25
- return token
26
21
  }
27
22
 
28
23
  getExt(file) {
@@ -37,34 +32,72 @@ class Client {
37
32
  return file.type.startsWith('audio') || file.type.startsWith('video');
38
33
  }
39
34
 
40
- getFileNameUUID() {
41
- return uuidv4();
35
+ generateFileName(originalName) {
36
+ const random = Math.random().toString(36).substring(2, 8);
37
+ const ext = this.getExt({ name: originalName });
38
+ const nameWithoutExt = originalName.substring(0, originalName.lastIndexOf('.'));
39
+ // 清理文件名中的特殊字符,保留中文、字母、数字、下划线和连字符
40
+ const cleanName = nameWithoutExt.replace(/[^\u4e00-\u9fa5a-zA-Z0-9_-]/g, '_');
41
+ return `${cleanName}_${random}.${ext}`;
42
42
  }
43
43
 
44
- async getStsToken(file) {
44
+ async getStsToken() {
45
45
  if (!this.stsUrl) {
46
- console.error('获取临时凭证地址不能为空');
47
- file.onError();
48
- return Promise.reject('获取临时凭证地址不能为空');
46
+ const error = new Error('获取临时凭证地址不能为空');
47
+ // eslint-disable-next-line no-console
48
+ console.error(error.message);
49
+ throw error;
49
50
  }
50
51
 
51
52
  try {
52
- const response = await fetch(this.stsUrl + '?xnToken=' + this.getToken());
53
+ const response = await fetch(this.stsUrl, {
54
+ headers: {
55
+ 'xnToken': this.getToken()
56
+ }
57
+ });
53
58
  const res = await response.json();
54
59
  const { accessKeyId, accessKeySecret, securityToken: stsToken, uploadHost, bucket, region } = res.data;
55
60
  this.uploadHost = uploadHost;
61
+
62
+ // 保存当前的凭证信息,用于自动刷新
63
+ this.currentCredentials = { accessKeyId, accessKeySecret, stsToken, bucket, region };
64
+
56
65
  this.oss = new OSS({
57
66
  accessKeyId,
58
67
  accessKeySecret,
59
68
  stsToken,
60
69
  bucket,
61
- region
70
+ region,
71
+ // 配置自动刷新STS Token
72
+ refreshSTSToken: async () => {
73
+ try {
74
+ const response = await fetch(this.stsUrl, {
75
+ headers: {
76
+ 'xnToken': this.getToken()
77
+ }
78
+ });
79
+ const res = await response.json();
80
+ const { accessKeyId, accessKeySecret, securityToken: stsToken } = res.data;
81
+ return {
82
+ accessKeyId,
83
+ accessKeySecret,
84
+ stsToken
85
+ };
86
+ } catch (err) {
87
+ // eslint-disable-next-line no-console
88
+ console.error('刷新STS Token失败:', err);
89
+ throw err;
90
+ }
91
+ },
92
+ // STS Token刷新间隔(毫秒),默认在过期前5分钟刷新
93
+ refreshSTSTokenInterval: 300000 // 5分钟
62
94
  });
63
95
  return this;
64
96
  } catch (err) {
65
- console.error('获取临时凭证失败:', err);
66
- file.onError();
67
- return Promise.reject(err);
97
+ const error = new Error(`获取临时凭证失败: ${err.message}`);
98
+ // eslint-disable-next-line no-console
99
+ console.error(error.message, err);
100
+ throw error;
68
101
  }
69
102
  }
70
103
 
@@ -86,49 +119,49 @@ class Client {
86
119
  const { data } = await response.json();
87
120
  return data;
88
121
  } catch (err) {
89
- console.error('设置文件ID失败:', err);
90
- return Promise.reject(err);
122
+ const error = new Error(`设置文件ID失败: ${err.message}`);
123
+ // eslint-disable-next-line no-console
124
+ console.error(error.message, err);
125
+ throw error;
91
126
  }
92
127
  }
93
128
 
94
- upload(file, headers = {}) {
95
- // eslint-disable-next-line no-async-promise-executor
96
- return new Promise(async (resolve, reject) => {
97
- const currentFile = file.file;
98
- const fileName = currentFile.name;
99
- const newFileName = this.getFileNameUUID() + '.' + this.getExt(currentFile);
100
- const path = `accessory/${$dayjs().format('YYYY/MM/DD')}/`;
101
-
102
- try {
103
- await this.getStsToken(file);
104
- const res = await this.oss.multipartUpload(path + newFileName, currentFile, {
105
- ...headers,
106
- progress: (p) => {
107
- const _progress = parseFloat(p * 100);
108
- file.onProgress({ percent: _progress });
109
- }
110
- });
111
-
112
- const fileObj = {
113
- name: fileName,
114
- size: currentFile.size,
115
- ext: this.getExt(currentFile),
116
- imgFlag: Number(this.isImg(currentFile)),
117
- isAV: Number(this.isAV(currentFile)),
118
- url: this.uploadHost + res.name,
119
- accessoryName: fileName,
120
- accessorySize: currentFile.size
121
- };
122
-
123
- const fileIdResponse = await this.setFileId(fileObj);
124
- file.onSuccess();
125
- resolve({ ...fileObj, fileId: fileIdResponse.fileId, file: currentFile });
126
- } catch (err) {
127
- console.error('上传文件失败:', err);
128
- file.onError();
129
- reject({ file, fileName, err });
130
- }
131
- });
129
+ async upload(file, headers = {}) {
130
+ const currentFile = file.file;
131
+ const fileName = currentFile.name;
132
+ const newFileName = this.generateFileName(fileName);
133
+ const path = `accessory/${$dayjs().format('YYYY/MM/DD')}/`;
134
+
135
+ try {
136
+ await this.getStsToken();
137
+ const res = await this.oss.multipartUpload(path + newFileName, currentFile, {
138
+ ...headers,
139
+ progress: (p) => {
140
+ const _progress = parseFloat(p * 100);
141
+ file.onProgress({ percent: _progress });
142
+ }
143
+ });
144
+
145
+ const fileObj = {
146
+ name: fileName,
147
+ size: currentFile.size,
148
+ ext: this.getExt(currentFile),
149
+ imgFlag: this.isImg(currentFile) ? 1 : 0,
150
+ isAV: this.isAV(currentFile) ? 1 : 0,
151
+ url: this.uploadHost + res.name,
152
+ accessoryName: fileName,
153
+ accessorySize: currentFile.size
154
+ };
155
+
156
+ const fileIdResponse = await this.setFileId(fileObj);
157
+ file.onSuccess();
158
+ return { ...fileObj, fileId: fileIdResponse.fileId, file: currentFile };
159
+ } catch (err) {
160
+ // eslint-disable-next-line no-console
161
+ console.error('上传文件失败:', err);
162
+ // 不调用 file.onError(),避免文件被 Element UI 移除,在组件层面处理失败状态
163
+ throw { file, fileName, err, message: err.message || '上传失败' };
164
+ }
132
165
  }
133
166
  }
134
167
 
@@ -1,6 +1,9 @@
1
1
  import Vue from 'vue'
2
- import Element from 'element-ui'
3
- import 'xn-ui/packages/style/src/theme/index.scss'
2
+ import Element from '@liuzengwei/element-ui'
3
+
4
+ // 始终导入 Element UI 样式(不使用 CDN)
5
+ require('@liuzengwei/element-ui/packages/theme-chalk/src/index.scss')
6
+
4
7
  Vue.use(Element, {
5
8
  size: 'small'
6
9
  })