@scx-js/scx-app-x 0.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/index.js +4 -0
- package/package.json +13 -0
- package/scx_crud/ScxCrud.js +179 -0
- package/scx_fss/FSSHelper.js +93 -0
- package/scx_fss/FSSObject.js +26 -0
- package/scx_fss/JoinImageURLOptions.js +42 -0
- package/scx_fss/ScxFSS.js +224 -0
package/index.js
ADDED
package/package.json
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"name": "@scx-js/scx-app-x",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"description": "SCX App X",
|
5
|
+
"main": "index.js",
|
6
|
+
"repository": {
|
7
|
+
"type": "git",
|
8
|
+
"url": "https://github.com/scx567888/scx-js.git"
|
9
|
+
},
|
10
|
+
"dependencies": {
|
11
|
+
"spark-md5-es": "^3.0.2"
|
12
|
+
}
|
13
|
+
}
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import {QUERY_SERIALIZER} from "@scx-js/scx-data/query/serializer/QuerySerializer.js";
|
2
|
+
import {FIELD_FILTER_SERIALIZER} from "@scx-js/scx-data/field_filter/serializer/FieldFilterSerializer.js";
|
3
|
+
|
4
|
+
|
5
|
+
class CRUDListParam {
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @type {Query}
|
9
|
+
*/
|
10
|
+
query;
|
11
|
+
|
12
|
+
fieldFilter;
|
13
|
+
|
14
|
+
extParams;
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
class CRUDUpdateParam {
|
19
|
+
|
20
|
+
/**
|
21
|
+
* @type {Object}
|
22
|
+
*/
|
23
|
+
updateModel;
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @type {String[]}
|
27
|
+
*/
|
28
|
+
needUpdateFieldNames;
|
29
|
+
|
30
|
+
}
|
31
|
+
|
32
|
+
class ListResult {
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @type {Object[]}
|
36
|
+
*/
|
37
|
+
items;
|
38
|
+
|
39
|
+
/**
|
40
|
+
* @type {Number}
|
41
|
+
*/
|
42
|
+
total;
|
43
|
+
|
44
|
+
}
|
45
|
+
|
46
|
+
class BatchDeleteResult {
|
47
|
+
|
48
|
+
/**
|
49
|
+
* @type {Number}
|
50
|
+
*/
|
51
|
+
deletedCount;
|
52
|
+
|
53
|
+
}
|
54
|
+
|
55
|
+
class CheckUniqueResult {
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @type {Boolean}
|
59
|
+
*/
|
60
|
+
isUnique;
|
61
|
+
}
|
62
|
+
|
63
|
+
class ScxCrud {
|
64
|
+
|
65
|
+
/**
|
66
|
+
* @type {ScxReq}
|
67
|
+
*/
|
68
|
+
req;
|
69
|
+
|
70
|
+
listApi;
|
71
|
+
infoApi;
|
72
|
+
addApi;
|
73
|
+
updateApi;
|
74
|
+
deleteApi;
|
75
|
+
batchDeleteApi;
|
76
|
+
checkUniqueApi;
|
77
|
+
countApi;
|
78
|
+
|
79
|
+
constructor(req, baseCrudApi) {
|
80
|
+
this.req = req;
|
81
|
+
this.listApi = baseCrudApi + "/list";
|
82
|
+
this.infoApi = baseCrudApi + "/";
|
83
|
+
this.addApi = baseCrudApi;
|
84
|
+
this.updateApi = baseCrudApi;
|
85
|
+
this.deleteApi = baseCrudApi + "/";
|
86
|
+
this.batchDeleteApi = baseCrudApi + "/batch-delete";
|
87
|
+
this.checkUniqueApi = baseCrudApi + "/check-unique/";
|
88
|
+
this.countApi = baseCrudApi + "/count";
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* list
|
93
|
+
* @param crudListParam {CRUDListParam}
|
94
|
+
* @return {Promise<ListResult>}
|
95
|
+
*/
|
96
|
+
list(crudListParam) {
|
97
|
+
return new Promise((resolve, reject) => this.req.post(this.listApi, serializeCRUDListParam(crudListParam)).then(data => resolve(data)).catch(e => reject(e)));
|
98
|
+
};
|
99
|
+
|
100
|
+
/**
|
101
|
+
* info
|
102
|
+
* @param id {Number}
|
103
|
+
* @return {Promise<Object>}
|
104
|
+
*/
|
105
|
+
info(id) {
|
106
|
+
return new Promise((resolve, reject) => this.req.get(this.infoApi + id, null).then(data => resolve(data)).catch(e => reject(e)));
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* add
|
111
|
+
* @param saveModel {Object}
|
112
|
+
* @return {Promise<Object>}
|
113
|
+
*/
|
114
|
+
add(saveModel) {
|
115
|
+
return new Promise((resolve, reject) => this.req.post(this.addApi, saveModel).then(data => resolve(data)).catch(e => reject(e)));
|
116
|
+
}
|
117
|
+
|
118
|
+
/**
|
119
|
+
* update
|
120
|
+
* @param crudUpdateParam {CRUDUpdateParam}
|
121
|
+
* @return {Promise<Object>}
|
122
|
+
*/
|
123
|
+
update(crudUpdateParam) {
|
124
|
+
return new Promise((resolve, reject) => this.req.put(this.updateApi, crudUpdateParam).then(data => resolve(data)).catch(e => reject(e)));
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* delete
|
129
|
+
* @param crudListParam {CRUDListParam}
|
130
|
+
* @return {Promise<Number>}
|
131
|
+
*/
|
132
|
+
delete(crudListParam) {
|
133
|
+
return new Promise((resolve, reject) => this.req.delete(this.deleteApi, serializeCRUDListParam(crudListParam)).then(data => resolve(data)).catch(e => reject(e)));
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* checkUnique
|
138
|
+
* @param fieldName {String}
|
139
|
+
* @param value {Object}
|
140
|
+
* @param id {Number}
|
141
|
+
* @return {Promise<CheckUniqueResult>}
|
142
|
+
*/
|
143
|
+
checkUnique(fieldName, value, id = null) {
|
144
|
+
const v = {value, id};
|
145
|
+
return new Promise((resolve, reject) => this.req.post(this.checkUniqueApi + fieldName, v).then(data => resolve(data)).catch(e => reject(e)));
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* count
|
150
|
+
* @param crudListParam {CRUDListParam}
|
151
|
+
* @return {Promise<Number>}
|
152
|
+
*/
|
153
|
+
count(crudListParam) {
|
154
|
+
return new Promise((resolve, reject) => this.req.post(this.countApi, serializeCRUDListParam(crudListParam)).then(data => resolve(data)).catch(e => reject(e)));
|
155
|
+
};
|
156
|
+
|
157
|
+
}
|
158
|
+
|
159
|
+
function serializeCRUDListParam(crudListParam) {
|
160
|
+
const o = {};
|
161
|
+
if (crudListParam.query) {
|
162
|
+
o.query = QUERY_SERIALIZER.serializeQuery(crudListParam.query);
|
163
|
+
}
|
164
|
+
if (crudListParam.fieldFilter) {
|
165
|
+
o.fieldFilter = FIELD_FILTER_SERIALIZER.serializeFieldFilter(crudListParam.fieldFilter);
|
166
|
+
}
|
167
|
+
o.extParams = crudListParam.extParams;
|
168
|
+
return o;
|
169
|
+
}
|
170
|
+
|
171
|
+
export {
|
172
|
+
ScxCrud,
|
173
|
+
CRUDListParam,
|
174
|
+
CRUDUpdateParam,
|
175
|
+
ListResult,
|
176
|
+
BatchDeleteResult,
|
177
|
+
CheckUniqueResult,
|
178
|
+
serializeCRUDListParam,
|
179
|
+
};
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import SparkMD5 from "spark-md5-es";
|
2
|
+
import {percentage} from "@scx-js/scx-common";
|
3
|
+
import {CHECKING} from "./ScxFSS.js";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* 获取 分块和 MD5
|
7
|
+
* @param file
|
8
|
+
* @param chunkSize
|
9
|
+
* @param onProgress
|
10
|
+
* @returns {Promise<unknown>}
|
11
|
+
*/
|
12
|
+
function getChunkAndHash(file, chunkSize, onProgress) {
|
13
|
+
return new Promise((resolve, reject) => {
|
14
|
+
//创建一个对象先
|
15
|
+
const chunkAndHash = {
|
16
|
+
chunk: [],
|
17
|
+
hash: "",
|
18
|
+
};
|
19
|
+
//不需要切割 (适用于文件大小 < 分块大小的情况, 因为比较常见 所以单独做处理)
|
20
|
+
const noNeedSlice = file.size <= chunkSize;
|
21
|
+
//计算需要分块的数量
|
22
|
+
const chunks = Math.ceil(file.size / chunkSize);
|
23
|
+
//当前分块
|
24
|
+
let currentChunk = 0;
|
25
|
+
//创建 MD5 校验对象
|
26
|
+
const spark = new SparkMD5.ArrayBuffer();
|
27
|
+
//创建文件读取对象
|
28
|
+
const fileReader = new FileReader();
|
29
|
+
|
30
|
+
//设置加载文件回调
|
31
|
+
fileReader.onload = (e) => {
|
32
|
+
//设置计算MD5的进度
|
33
|
+
onProgress(CHECKING, percentage(currentChunk, chunks));
|
34
|
+
//读取
|
35
|
+
spark.append(e.target.result);
|
36
|
+
currentChunk = currentChunk + 1;
|
37
|
+
//还没有读完
|
38
|
+
if (currentChunk < chunks) {
|
39
|
+
loadNext();
|
40
|
+
} else { //读完了 赋值MD5 并返回
|
41
|
+
chunkAndHash.hash = spark.end(false);
|
42
|
+
//设置校验 md5 为 100%
|
43
|
+
onProgress(CHECKING, 100);
|
44
|
+
resolve(chunkAndHash);
|
45
|
+
}
|
46
|
+
};
|
47
|
+
|
48
|
+
//发生错误
|
49
|
+
fileReader.onerror = () => reject();
|
50
|
+
|
51
|
+
//加载区块方法
|
52
|
+
const loadNext = () => {
|
53
|
+
let tempFileChunk;
|
54
|
+
if (noNeedSlice) { // 不切割
|
55
|
+
tempFileChunk = file;
|
56
|
+
} else { // 按照 分块的大小进行切割文件
|
57
|
+
// 获取起始位置字节数
|
58
|
+
const start = currentChunk * chunkSize;
|
59
|
+
// 获取结束位置字节数
|
60
|
+
const end = Math.min(start + chunkSize, file.size);
|
61
|
+
tempFileChunk = file.slice(start, end);
|
62
|
+
}
|
63
|
+
// 将切割后的区块放入 fileInfo 对象的 chunk 中以便之后使用
|
64
|
+
chunkAndHash.chunk.push(tempFileChunk);
|
65
|
+
// 读取 (这里起始就是走的 fileReader.onload 方法)
|
66
|
+
fileReader.readAsArrayBuffer(tempFileChunk);
|
67
|
+
};
|
68
|
+
|
69
|
+
//开始加载
|
70
|
+
loadNext();
|
71
|
+
});
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
/**
|
76
|
+
* 格式化显示文件大小
|
77
|
+
* @param value
|
78
|
+
* @returns {string}
|
79
|
+
*/
|
80
|
+
function formatFileSize(value) {
|
81
|
+
if (null == value || value === "") {
|
82
|
+
return "0 Bytes";
|
83
|
+
}
|
84
|
+
const unitArr = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
85
|
+
let index;
|
86
|
+
const srcSize = parseFloat(value);
|
87
|
+
index = Math.floor(Math.log(srcSize) / Math.log(1024));
|
88
|
+
let size = srcSize / Math.pow(1024, index);
|
89
|
+
size = size.toFixed(2);//保留的小数位数
|
90
|
+
return size + unitArr[index];
|
91
|
+
}
|
92
|
+
|
93
|
+
export {getChunkAndHash, formatFileSize};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class FSSObject {
|
2
|
+
fssObjectID;//文件的 id
|
3
|
+
fileName;//文件的名称
|
4
|
+
uploadTime;//上传时间
|
5
|
+
fileHash;//文件 hash
|
6
|
+
fileSizeDisplay;//文件大小 格式化值
|
7
|
+
fileSize;//文件大小
|
8
|
+
|
9
|
+
constructor({
|
10
|
+
fssObjectID,
|
11
|
+
fileName,
|
12
|
+
uploadTime,
|
13
|
+
fileHash,
|
14
|
+
fileSizeDisplay,
|
15
|
+
fileSize,
|
16
|
+
}) {
|
17
|
+
this.fssObjectID = fssObjectID;
|
18
|
+
this.fileName = fileName;
|
19
|
+
this.uploadTime = uploadTime;
|
20
|
+
this.fileHash = fileHash;
|
21
|
+
this.fileSizeDisplay = fileSizeDisplay;
|
22
|
+
this.fileSize = fileSize;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
export {FSSObject};
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class JoinImageURLOptions {
|
2
|
+
|
3
|
+
/**
|
4
|
+
* width 的简写形式
|
5
|
+
* @type {Number}
|
6
|
+
*/
|
7
|
+
w;
|
8
|
+
|
9
|
+
/**
|
10
|
+
* height 的简写形式
|
11
|
+
* @type {Number}
|
12
|
+
*/
|
13
|
+
h;
|
14
|
+
|
15
|
+
/**
|
16
|
+
* type 的简写形式
|
17
|
+
* @type {String}
|
18
|
+
*/
|
19
|
+
t;
|
20
|
+
|
21
|
+
/**
|
22
|
+
* 优先级大于 w
|
23
|
+
* @type {Number}
|
24
|
+
*/
|
25
|
+
width;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* 优先级大于 h
|
29
|
+
* @type {Number}
|
30
|
+
*/
|
31
|
+
height;
|
32
|
+
|
33
|
+
/**
|
34
|
+
* 优先级大于 t
|
35
|
+
* @type {String}
|
36
|
+
*/
|
37
|
+
type;
|
38
|
+
}
|
39
|
+
|
40
|
+
export {
|
41
|
+
JoinImageURLOptions,
|
42
|
+
};
|
@@ -0,0 +1,224 @@
|
|
1
|
+
import {joinURL, percentage} from "@scx-js/scx-common";
|
2
|
+
import {JsonVOError} from "@scx-js/scx-http";
|
3
|
+
import {inject} from "vue";
|
4
|
+
import {formatFileSize, getChunkAndHash} from "./FSSHelper.js";
|
5
|
+
import {FSSObject} from "./FSSObject.js";
|
6
|
+
|
7
|
+
const UPLOAD_URL = "api/fss/upload";
|
8
|
+
const LIST_INFO_URL = "api/fss/list-info";
|
9
|
+
const INFO_URL = "api/fss/info";
|
10
|
+
const RAW_URL = "api/fss/raw/";
|
11
|
+
const IMAGE_URL = "api/fss/image/";
|
12
|
+
const DOWNLOAD_URL = "api/fss/download/";
|
13
|
+
const CHECK_ANY_FILE_EXISTS_BY_HASH_URL = "api/fss/check-any-file-exists-by-hash";
|
14
|
+
|
15
|
+
const CHECKING = "checking";
|
16
|
+
const UPLOADING = "uploading";
|
17
|
+
|
18
|
+
const NEED_MORE = "need-more";
|
19
|
+
const UPLOAD_SUCCESS = "upload-success";
|
20
|
+
const NO_ANY_FILE_EXISTS_FOR_HASH = "no-any-file-exists-for-hash";
|
21
|
+
|
22
|
+
/**
|
23
|
+
* req
|
24
|
+
*/
|
25
|
+
class ScxFSS {
|
26
|
+
scxReq;
|
27
|
+
maxUploadSize = 10 * 1024 * 1024 * 1024;//最大上传文件 写死 10GB
|
28
|
+
chunkSize = 2 * 1024 * 1024;//切片大小 这里写死 2MB
|
29
|
+
|
30
|
+
/**
|
31
|
+
* req 对象
|
32
|
+
* @param scxReq {ScxReq}
|
33
|
+
*/
|
34
|
+
constructor(scxReq) {
|
35
|
+
this.scxReq = scxReq;
|
36
|
+
}
|
37
|
+
|
38
|
+
static defaultOnProgress(state, value) {
|
39
|
+
console.log({
|
40
|
+
state: state,
|
41
|
+
value: value,
|
42
|
+
});
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* 上传到 fss 中
|
47
|
+
* @param file 待上传的文件
|
48
|
+
* @param onProgress 上传进度回调
|
49
|
+
* @returns {Promise<unknown>} r
|
50
|
+
*/
|
51
|
+
|
52
|
+
upload(file, onProgress = ScxFSS.defaultOnProgress) {
|
53
|
+
return new Promise((resolve, reject) => {
|
54
|
+
//先判断待上传的文件是否为空或者是否为 File 对象
|
55
|
+
if (file == null || !(file instanceof File)) {
|
56
|
+
reject("文件不能为空并且类型必须为文件 !!!");
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
//判断文件大小是否超出最大限制
|
60
|
+
if (file.size > this.maxUploadSize) {
|
61
|
+
reject("文件不能大于 " + formatFileSize(this.maxUploadSize) + " !!! 问题文件 : " + file.name);
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
//开始获取 md5和 分块
|
65
|
+
getChunkAndHash(file, this.chunkSize, onProgress).then(chunkAndMD5 => {
|
66
|
+
const fileName = file.name;
|
67
|
+
const fileSize = file.size;
|
68
|
+
const chunk = chunkAndMD5.chunk;
|
69
|
+
const hash = chunkAndMD5.hash;
|
70
|
+
let i = 0;
|
71
|
+
|
72
|
+
//创建上传方法
|
73
|
+
const uploadNext = () => {
|
74
|
+
//设置进度条 此处由已上传区块数量和全部区块数量计算而得
|
75
|
+
onProgress(UPLOADING, percentage(i, chunk.length));
|
76
|
+
const uploadFormData = new FormData();
|
77
|
+
uploadFormData.append("fileName", fileName);
|
78
|
+
uploadFormData.append("fileData", chunk[i]);
|
79
|
+
uploadFormData.append("fileSize", fileSize + "");
|
80
|
+
uploadFormData.append("fileHash", hash);
|
81
|
+
uploadFormData.append("chunkLength", chunk.length + "");
|
82
|
+
uploadFormData.append("nowChunkIndex", i + "");
|
83
|
+
|
84
|
+
//向后台发送请求
|
85
|
+
this.scxReq.post(UPLOAD_URL, uploadFormData).then(data => {
|
86
|
+
//这里因为有断点续传的功能所以可以直接设置 i 以便跳过已经上传过的区块
|
87
|
+
if (data.type === NEED_MORE) {
|
88
|
+
i = data.item;
|
89
|
+
uploadNext();
|
90
|
+
} else if (data.type === UPLOAD_SUCCESS) {
|
91
|
+
onProgress(UPLOADING, 100);
|
92
|
+
resolve(data);
|
93
|
+
} else { //这里就属于返回一些别的 类型了 我们虽然不知道是啥,但肯定不对 所以返回错误
|
94
|
+
reject(data);
|
95
|
+
}
|
96
|
+
}).catch(e => reject(e));
|
97
|
+
};
|
98
|
+
|
99
|
+
//这里先检查一下服务器是否已经有相同MD5的文件了 有的话就不传了
|
100
|
+
this.scxReq.post(CHECK_ANY_FILE_EXISTS_BY_HASH_URL, {
|
101
|
+
fileName,
|
102
|
+
fileSize,
|
103
|
+
fileHash: hash,
|
104
|
+
}).then(data => {
|
105
|
+
//这里表示服务器已经有这个文件了
|
106
|
+
onProgress(UPLOADING, 100);
|
107
|
+
resolve(data);
|
108
|
+
}).catch(e => {//这里表示服务器没找到这个文件 还是老老实实的传吧
|
109
|
+
//这里错误的种类比较多 也可能是网络错误或者权限错误啥的 这里判断一下先
|
110
|
+
if (e instanceof JsonVOError && e.message === NO_ANY_FILE_EXISTS_FOR_HASH) {
|
111
|
+
//开始递归上传
|
112
|
+
uploadNext();
|
113
|
+
} else {
|
114
|
+
reject(e);
|
115
|
+
}
|
116
|
+
});
|
117
|
+
|
118
|
+
}).catch(e => reject(e));
|
119
|
+
});
|
120
|
+
};
|
121
|
+
|
122
|
+
/**
|
123
|
+
*根据文件 id 获取文件基本信息
|
124
|
+
* @param fssObjectID s
|
125
|
+
* @returns {Promise<unknown>}
|
126
|
+
*/
|
127
|
+
info(fssObjectID) {
|
128
|
+
return new Promise((resolve, reject) => {
|
129
|
+
this.scxReq.post(INFO_URL, {fssObjectID}).then(data => {
|
130
|
+
resolve(data ? new FSSObject(data) : null);
|
131
|
+
}).catch(e => {
|
132
|
+
reject(e);
|
133
|
+
});
|
134
|
+
});
|
135
|
+
};
|
136
|
+
|
137
|
+
/**
|
138
|
+
* a
|
139
|
+
* @param fssObjectIDs {Array} a
|
140
|
+
* @returns {Promise<unknown>} a
|
141
|
+
*/
|
142
|
+
listInfo(fssObjectIDs) {
|
143
|
+
return new Promise((resolve, reject) => {
|
144
|
+
this.scxReq.post(LIST_INFO_URL, {fssObjectIDs}).then(data => {
|
145
|
+
const fssObjectList = data.map(i => new FSSObject(i));
|
146
|
+
resolve(fssObjectList);
|
147
|
+
}).catch(e => {
|
148
|
+
reject(e);
|
149
|
+
});
|
150
|
+
});
|
151
|
+
};
|
152
|
+
|
153
|
+
/**
|
154
|
+
* 获取 raw url
|
155
|
+
* @param fssObjectID
|
156
|
+
*/
|
157
|
+
joinRawURL(fssObjectID) {
|
158
|
+
return joinURL(this.scxReq.baseURL, RAW_URL, fssObjectID).toString();
|
159
|
+
};
|
160
|
+
|
161
|
+
/**
|
162
|
+
* 获取 img url
|
163
|
+
* @param fssObjectID
|
164
|
+
* @param options {JoinImageURLOptions}
|
165
|
+
*/
|
166
|
+
joinImageURL(fssObjectID, options = {}) {
|
167
|
+
const url = joinURL(this.scxReq.baseURL, IMAGE_URL, fssObjectID);
|
168
|
+
const {
|
169
|
+
w,
|
170
|
+
h,
|
171
|
+
t,
|
172
|
+
width = w,
|
173
|
+
height = h,
|
174
|
+
type = t,
|
175
|
+
} = options;
|
176
|
+
if (width || height || type) {
|
177
|
+
if (width) {
|
178
|
+
url.searchParams.set("w", width + "");
|
179
|
+
}
|
180
|
+
if (height) {
|
181
|
+
url.searchParams.set("h", height + "");
|
182
|
+
}
|
183
|
+
if (type) {
|
184
|
+
url.searchParams.set("t", type);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
return url.toString();
|
188
|
+
};
|
189
|
+
|
190
|
+
/**
|
191
|
+
* 获取 download url
|
192
|
+
* @param fssObjectID
|
193
|
+
*/
|
194
|
+
joinDownloadURL(fssObjectID) {
|
195
|
+
return joinURL(this.scxReq.baseURL, DOWNLOAD_URL, fssObjectID).toString();
|
196
|
+
};
|
197
|
+
|
198
|
+
install(app) {
|
199
|
+
app.provide(scxFSSKey, this);
|
200
|
+
}
|
201
|
+
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
*
|
206
|
+
* @type {string}
|
207
|
+
*/
|
208
|
+
const scxFSSKey = "scx-fss";
|
209
|
+
|
210
|
+
/**
|
211
|
+
*
|
212
|
+
* @returns {ScxFSS}
|
213
|
+
*/
|
214
|
+
function useScxFSS() {
|
215
|
+
return inject(scxFSSKey);
|
216
|
+
}
|
217
|
+
|
218
|
+
export {
|
219
|
+
scxFSSKey,
|
220
|
+
useScxFSS,
|
221
|
+
ScxFSS,
|
222
|
+
CHECKING,
|
223
|
+
UPLOADING,
|
224
|
+
};
|