fhrons-mobile-next 2.0.0

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.
@@ -0,0 +1,179 @@
1
+ /**
2
+ * 判断是否为空
3
+ */
4
+ function validateNull (val) {
5
+ if (typeof val === 'boolean') {
6
+ return false;
7
+ }
8
+ if (typeof val === 'number') {
9
+ return false;
10
+ }
11
+ if (val instanceof Array) {
12
+ if (val.length === 0) return true;
13
+ } else if (val instanceof Object) {
14
+ if (JSON.stringify(val) === '{}') return true;
15
+ } else {
16
+ if (val === 'null' || val === null || val === 'undefined' || val === undefined || val === '') return true;
17
+ return false;
18
+ }
19
+ return false;
20
+ }
21
+ const SESSION = 'session';
22
+ const keyName = `Fun-${process.env.VUE_APP_NAME}-${process.env.VUE_APP_ENV_CONFIG}-`;
23
+ const commonKeyName = `Fun-${process.env.VUE_APP_ENV_CONFIG}-`;
24
+ /**
25
+ * 存储localStorage
26
+ */
27
+ export const setStorage = (params = {}) => {
28
+ let { name } = params;
29
+ const { content, type, needListener, key, commonKey } = params;
30
+ name = key || (name === 'userGlobalGist' ? (commonKeyName + name) : commonKey ? (commonKeyName + commonKey) : (keyName + name));
31
+ const obj = {
32
+ dataType: typeof content,
33
+ content: content,
34
+ type: type,
35
+ dateTime: new Date().getTime()
36
+ };
37
+ const temp = { name, type, obj: JSON.stringify(obj) };
38
+ if (needListener) {
39
+ addSetStorageEvent(temp);
40
+ } else {
41
+ if (type && type.toLowerCase() === SESSION) window.sessionStorage.setItem(name, JSON.stringify(obj));
42
+ else window.localStorage.setItem(name, JSON.stringify(obj));
43
+ }
44
+ };
45
+
46
+ /**
47
+ * 获取localStorage
48
+ */
49
+
50
+ export const getStorage = (params = {}) => {
51
+ let { name } = params;
52
+ const { debug, key, commonKey } = params;
53
+ name = key || (name === 'userGlobalGist' ? (commonKeyName + name) : commonKey ? (commonKeyName + commonKey) : (keyName + name));
54
+ let obj = {};
55
+ let content;
56
+ obj = window.sessionStorage.getItem(name);
57
+ if (validateNull(obj)) obj = window.localStorage.getItem(name);
58
+ if (validateNull(obj)) return;
59
+ try {
60
+ obj = JSON.parse(obj);
61
+ } catch {
62
+ return obj;
63
+ }
64
+ if (debug || key) {
65
+ return obj;
66
+ }
67
+ if (obj.dataType === 'string') {
68
+ content = obj.content;
69
+ } else if (obj.dataType === 'number') {
70
+ content = Number(obj.content);
71
+ } else if (obj.dataType === 'boolean') {
72
+ content = obj.content || false;
73
+ } else if (obj.dataType === 'object') {
74
+ content = obj.content;
75
+ }
76
+ return content;
77
+ };
78
+ /**
79
+ * 删除localStorage
80
+ */
81
+ export const removeStorage = (params = {}) => {
82
+ let { name } = params;
83
+ const { type, key, commonKey } = params;
84
+ name = key || (name === 'userGlobalGist' ? (commonKeyName + name) : commonKey ? (commonKeyName + commonKey) : (keyName + name));
85
+ if (type && type.toLowerCase() === SESSION) {
86
+ window.sessionStorage.removeItem(name);
87
+ } else {
88
+ window.localStorage.removeItem(name);
89
+ }
90
+ };
91
+
92
+ /**
93
+ * 获取全部localStorage
94
+ */
95
+ export const getAllStorage = (params = {}) => {
96
+ const list = [];
97
+ const { type } = params;
98
+ if (type && type.toLowerCase() === SESSION) {
99
+ for (let i = 0; i <= window.sessionStorage.length; i++) {
100
+ list.push({
101
+ name: window.sessionStorage.key(i),
102
+ content: getStorage({
103
+ name: window.sessionStorage.key(i),
104
+ type: SESSION
105
+ })
106
+ });
107
+ }
108
+ } else {
109
+ for (let i = 0; i <= window.localStorage.length; i++) {
110
+ list.push({
111
+ name: window.localStorage.key(i),
112
+ content: getStorage({
113
+ name: window.localStorage.key(i)
114
+ })
115
+ });
116
+ }
117
+ }
118
+ return list;
119
+ };
120
+
121
+ /**
122
+ * 清空全部localStorage
123
+ */
124
+ export const clearStorage = (params = {}) => {
125
+ const { type } = params;
126
+ if (type && type.toLowerCase() === SESSION) {
127
+ window.sessionStorage.clear();
128
+ } else {
129
+ const platformInfo = getStorage({ name: 'platformInfo' });
130
+ const openId = getStorage({ name: 'openId' });
131
+ const platformCode = getStorage({ name: 'platformCode' });
132
+ const unionId = getStorage({ name: 'unionId' });
133
+ const firUrl = getStorage({ name: 'firUrl' });
134
+ const appId = getStorage({ name: 'appId' });
135
+ const saasId = getStorage({ name: 'saasId' });
136
+ const corpId = getStorage({ name: 'corpId' });
137
+ const head = getStorage({ name: 'head' });
138
+ const nickname = getStorage({ name: 'nickname' });
139
+ const isOrigin = getStorage({ name: 'isOrigin' });
140
+ const language = getStorage({ commonKey: 'language' }) || 'zh_CN';
141
+ const originPlatformCode = getStorage({ name: 'originPlatformCode' });
142
+ const saasPolicyListInfo = getStorage({ name: 'saasPolicyListInfo' });
143
+ window.localStorage.clear();
144
+ setStorage({ name: 'platformInfo', content: platformInfo });
145
+ setStorage({ name: 'openId', content: openId });
146
+ setStorage({ name: 'unionId', content: unionId });
147
+ setStorage({ name: 'firUrl', content: firUrl });
148
+ setStorage({ name: 'appId', content: appId });
149
+ setStorage({ name: 'saasId', content: saasId });
150
+ setStorage({ name: 'corpId', content: corpId });
151
+ setStorage({ name: 'platformCode', content: platformCode });
152
+ setStorage({ commonKey: 'platformCode', content: platformCode });
153
+ setStorage({ name: 'head', content: head });
154
+ setStorage({ name: 'nickname', content: nickname });
155
+ setStorage({ name: 'isOrigin', content: !!isOrigin });
156
+ setStorage({ commonKey: 'language', content: language });
157
+ setStorage({ name: 'originPlatformCode', content: originPlatformCode });
158
+ setStorage({ name: 'saasPolicyListInfo', content: saasPolicyListInfo });
159
+ }
160
+ };
161
+
162
+ export function addSetStorageEvent (params = {}) {
163
+ const { name, type, obj } = params;
164
+ // 创建一个StorageEvent事件
165
+ var newStorageEvent = document.createEvent('StorageEvent');
166
+ const storage = {
167
+ setItem: (type, k, val) => {
168
+ // 这里可以灵活更改local和session
169
+ if (type && type.toLowerCase() === SESSION) window.sessionStorage.setItem(k, val);
170
+ else window.localStorage.setItem(k, val);
171
+ // 初始化创建的事件
172
+ newStorageEvent.initStorageEvent('setItem', false, false, k, null, val, null, null);
173
+ // 派发对象
174
+ window.dispatchEvent(newStorageEvent);
175
+ }
176
+ };
177
+ return storage.setItem(type, name, obj);
178
+ }
179
+
@@ -0,0 +1,468 @@
1
+ // cdn引入axios
2
+ if (!window.axios) {
3
+ loadJavaScript(
4
+ "https://scrm-pro-1251973116.file.myqcloud.com/funzg/form/axios.js",
5
+ () => {
6
+ console.log("axios 加载成功");
7
+ }
8
+ );
9
+ }
10
+ // if (!window.AWS) {
11
+ // loadJavaScript('https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/aws-sdk-2.1562.0.min.js', () => {
12
+ // console.log('aws-sdk 加载成功');
13
+ // });
14
+ // }
15
+ if (!window.COS) {
16
+ loadJavaScript(
17
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/cos-js-sdk-v5.min.js",
18
+ () => {
19
+ console.log("腾讯cos 加载成功");
20
+ }
21
+ );
22
+ }
23
+ if (!window.lrz) {
24
+ loadJavaScript(
25
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/lrz.all.bundle.min.js",
26
+ () => {
27
+ console.log("lrz加载成功");
28
+ }
29
+ );
30
+ }
31
+ if (!window.FHENCYPT) {
32
+ loadJavaScript(
33
+ "https://dop-pro-1251973116.file.myqcloud.com/upload/jsfile/funzg/fhEncypt.js",
34
+ () => {
35
+ console.log("FHENCYPT加载成功");
36
+ }
37
+ );
38
+ }
39
+
40
+ // const Minio = require('./utils/minio/internal/client.js')
41
+ // import * as Minio from 'minio'
42
+
43
+ /**
44
+ * 第一个参数的可选属性
45
+ * @param {Blob} file 要上传的文件
46
+ * @param {String} target 要上传的目标云,类型:0大陆环境/1港险环境
47
+ * @param {String} project 所属项目:0全局,1课程,2开放平台,4:scrm 5:营销 6:frcdap
48
+ * @param {Function} keyFunc 生成key的方法
49
+ * @param {Boolean} needWholeRes 是否需要返回完整的响应体
50
+ * @param {Number} urlMaxLength url 的长度限制
51
+ *
52
+ * 第二个参数
53
+ * @param {Function} onProgress 接收上传进度的回调
54
+ * @returns Link 上传完成后的图片链接
55
+ *
56
+ * 例:
57
+ * const param = {
58
+ * file, target = 'tencent', project = '0', keyFunc
59
+ * }
60
+ * upload(param,(percent)=>{
61
+ * console.log(percent) // 输出上传进度的百分比
62
+ * })
63
+ */
64
+ // 将函数提取到外部,避免重复定义
65
+ function getFullFileName(file) {
66
+ // 优先使用 File 对象的 name 属性
67
+ const fileName = file.name || file.filename || "";
68
+
69
+ // 如果已有后缀名(包含点号),直接返回
70
+ if (fileName.includes(".")) {
71
+ return fileName;
72
+ }
73
+
74
+ // 没有后缀名,从 type 中提取
75
+ if (file.type && file.type.includes("/")) {
76
+ let extension = file.type.split("/")[1]; // 从"image/jpeg"提取"jpeg"
77
+
78
+ // 特殊情况处理
79
+ if (extension === "jpeg") {
80
+ extension = "jpg";
81
+ }
82
+
83
+ // 清理扩展名中的参数(如 "svg+xml")
84
+ extension = extension.split("+")[0];
85
+
86
+ return `${fileName}.${extension}`;
87
+ }
88
+
89
+ // 如果连 type 都没有,返回原文件名
90
+ return fileName;
91
+ }
92
+ export function upload(
93
+ { file, target, project = "0", keyFunc, needWholeRes },
94
+ onProgress
95
+ ) {
96
+ let defaultTarget =
97
+ location.origin.includes("https://smnguat.fhrons.net") ||
98
+ location.origin.includes("https://openuat.fhrons.net") ||
99
+ location.origin.includes("https://smng.avantech.io") ||
100
+ location.origin.includes("https://open.avantech.io") ||
101
+ (process.env.VUE_APP_ENV_CONFIG &&
102
+ process.env.VUE_APP_ENV_CONFIG.includes("hk"))
103
+ ? "1"
104
+ : "0";
105
+ defaultTarget =
106
+ process.env.VUE_APP_ENV_CONFIG &&
107
+ process.env.VUE_APP_ENV_CONFIG.includes("poc")
108
+ ? "2"
109
+ : defaultTarget;
110
+ target = target ? (target === "tencent" ? "0" : "1") : defaultTarget;
111
+ if (!file) {
112
+ console.error("上传的文件不能为空");
113
+ return;
114
+ }
115
+ if (file.raw) file = file.raw; // 有的file对象里面的raw才是实际的文件内容
116
+ if (file.file) file = file.file; // vant文件选择器选到的文件里还有一层file
117
+ // target = target === 'tencent' ? '0' : '1'; // 根据传进来的target转换
118
+ // target = '2'
119
+ const filename = getFullFileName(file);
120
+ const temp = filename.split(".");
121
+ const fileSffix = temp[temp.length - 1];
122
+ const appName = process.env.VUE_APP_NAME || "common";
123
+ if (
124
+ typeof keyFunc !== "function" ||
125
+ (typeof keyFunc === "function" && !keyFunc())
126
+ )
127
+ keyFunc = () =>
128
+ `/${appName}/${new Date().valueOf()}_${temp[0]}${
129
+ fileSffix ? "." + fileSffix : ""
130
+ }`;
131
+
132
+ let newKey = keyFunc();
133
+ newKey = removeLeadingSlash(newKey);
134
+ console.log("newKey", newKey);
135
+
136
+ // if(urlMaxLength && newKey.length > urlMaxLength) return Promise.reject(`文件名长度过长,请保持在${urlMaxLength}以下`)
137
+ return axios
138
+ .post(
139
+ `/funapi/cbsconfig/oss/secureSign`,
140
+ {
141
+ type:target,
142
+ project:project,
143
+ filePath:newKey,
144
+ },
145
+ { headers: { 'Content-Type': 'application/json' } }
146
+ )
147
+ .then((res) => {
148
+ if (
149
+ target !== "2" &&
150
+ (typeof res.data === "string" || typeof res === "string")
151
+ )
152
+ res = JSON.parse(FHENCYPT.decrypt(res.data || res));
153
+ console.log('res',JSON.stringify(res));
154
+
155
+ const {
156
+ tmpSecretId,
157
+ tmpSecretKey,
158
+ token,
159
+ sessionToken,
160
+ startTime,
161
+ expiredTime,
162
+ requestId,
163
+ type,
164
+ bucketName,
165
+ region,
166
+ cdnUrl,
167
+ status = "SUCCESS",
168
+ message = "",
169
+ } = res.data || res;
170
+ if (status !== "SUCCESS") {
171
+ throw new Error(message);
172
+ }
173
+ /**
174
+ * @tmpSecretId 临时访问密钥的标识符。
175
+ * @tmpSecretKey 临时访问密钥的密钥。
176
+ * @type 0腾讯/1亚马逊/2 minio 字符串格式
177
+ * @startTime 腾讯使用的字段,开始时间
178
+ * @expiredTime 腾讯使用的字段,过期时间
179
+ * @bucketName 存储桶名称
180
+ * @cdnUrl cdn链接的前缀
181
+ * @region 存储区域
182
+ */
183
+ // if (type === '1') { // 亚马逊
184
+ // AWS.config.update({
185
+ // accessKeyId: tmpSecretId,
186
+ // secretAccessKey: tmpSecretKey,
187
+ // region: region,
188
+ // sessionToken: token
189
+ // });
190
+ // const s3 = new AWS.S3();
191
+ // const params = {
192
+ // Bucket: bucketName,
193
+ // Key: newKey,
194
+ // ContentType: type,
195
+ // Body: file,
196
+ // 'Access-Control-Allow-Credentials': '*'
197
+ // };
198
+ // const upload = s3.upload(params);
199
+ // upload.on('httpUploadProgress', (progress) => {
200
+ // const { loaded, total } = progress;
201
+ // /* 非必须 */
202
+ // const percent = Math.round(parseInt(loaded / total) * 100);
203
+ // if (typeof onProgress === 'function') onProgress(percent);
204
+ // });
205
+ // const uploadPromise = upload.promise();
206
+ // return uploadPromise.then(res => {
207
+ // const { key, Key } = res;
208
+ // console.log(res);
209
+ // // const tempUrl = (key.startsWith('/') ? '' : '/');
210
+ // const fileUrl = `${cdnUrl}${cdnUrl.endsWith('/') ? '' : '/'}${key || Key}`
211
+ // if (needWholeRes) {
212
+ // return {
213
+ // ...res,
214
+ // fileUrl
215
+ // };
216
+ // } return fileUrl;
217
+ // }).catch(err => {
218
+ // console.log(err);
219
+ // }).finally(_ => {
220
+ // });
221
+ // } else
222
+ // if (type === '2') { // 如果type=2 则使用minIO上传
223
+ // console.log(Minio)
224
+ // const minioClient = new Minio.Client({
225
+ // endPoint: 'poc.fhrons.com',
226
+ // // port: 31003,
227
+ // useSSL: true,
228
+ // accessKey: tmpSecretId,
229
+ // secretKey: tmpSecretKey,
230
+ // sessionToken: token
231
+ // })
232
+ // return uploadFileToMinio(file, minioClient, bucketName, newKey, cdnUrl, needWholeRes).then(res => {
233
+ // if (typeof onProgress === 'function') onProgress(100)
234
+ // console.log('上传成功,', res)
235
+ // return res
236
+ // }).catch(err => {
237
+ // console.log(err);
238
+ // })
239
+
240
+ // }
241
+ // 腾讯 如果没有type 则默认使用腾讯上传
242
+ const cos = new COS({
243
+ getAuthorization: function (options, callback) {
244
+ callback({
245
+ TmpSecretId: tmpSecretId,
246
+ TmpSecretKey: tmpSecretKey,
247
+ XCosSecurityToken: sessionToken,
248
+ StartTime: startTime,
249
+ ExpiredTime: expiredTime,
250
+ requestId: requestId,
251
+ SecurityToken: token,
252
+ });
253
+ },
254
+ });
255
+ return cos
256
+ .sliceUploadFile({
257
+ Bucket: bucketName /* 必须 */,
258
+ Region: region /* 存储桶所在地域,必须字段 */,
259
+ Key: newKey /* 必须 */,
260
+ StorageClass: "STANDARD",
261
+ Body: file, // 上传文件对象
262
+ onProgress: (progressData) => {
263
+ console.log(progressData);
264
+ const { loaded, total, percent, speed } = progressData;
265
+ const per = Math.round(parseInt(percent * 100));
266
+ if (typeof onProgress === "function") onProgress(per);
267
+ },
268
+ })
269
+ .then((data) => {
270
+ console.log(data);
271
+ const { key, Key } = data;
272
+ const _key = key || Key;
273
+ const tempUrl = _key.startsWith("/")
274
+ ? _key.slice(1, _key.length)
275
+ : _key;
276
+ const fileUrl = `${cdnUrl}${
277
+ cdnUrl.endsWith("/") ? "" : "/"
278
+ }${tempUrl}`;
279
+ if (needWholeRes) {
280
+ return {
281
+ ...res,
282
+ fileUrl,
283
+ };
284
+ }
285
+ return fileUrl;
286
+ })
287
+ .catch((err) => {
288
+ console.log(err);
289
+ });
290
+ });
291
+ }
292
+
293
+ function uploadFileToMinio(
294
+ file,
295
+ minioClient,
296
+ bucketName,
297
+ newKey,
298
+ cdnUrl,
299
+ needWholeRes
300
+ ) {
301
+ return new Promise((resolve, reject) => {
302
+ const reader = new FileReader();
303
+ reader.onload = function (e) {
304
+ try {
305
+ const buffer = Buffer.from(e.target.result);
306
+ minioClient.putObject(bucketName, newKey, buffer, function (err, etag) {
307
+ if (err) {
308
+ console.log(err);
309
+ return err;
310
+ }
311
+ console.log(etag);
312
+ const fileUrl = `${cdnUrl}${
313
+ cdnUrl.endsWith("/") ? "" : "/"
314
+ }${newKey}`;
315
+ if (needWholeRes) {
316
+ resolve({
317
+ etag,
318
+ fileUrl,
319
+ });
320
+ }
321
+ resolve(fileUrl);
322
+ });
323
+ } catch (err) {
324
+ reject(err);
325
+ }
326
+ };
327
+ reader.onerror = function (err) {
328
+ reject(err);
329
+ };
330
+ reader.readAsArrayBuffer(file);
331
+ });
332
+ }
333
+
334
+ /**
335
+ * @param {Blob} file 上传的图片文件
336
+ * @param {Number} quality 压缩质量
337
+ * @returns 返回压缩后的图片文件
338
+ */
339
+ // 压缩文件
340
+ export async function compressFile(file, quality = 0.7) {
341
+ file = file.raw ? file.raw : file;
342
+ // const imageCompressor = new Compressor();
343
+ try {
344
+ let reFile = "";
345
+ const rst = await lrz(file, {
346
+ quality: quality, // 图片压缩质量,取值0-1,默认为0.7
347
+ });
348
+ // const rst = new Compressor(file);
349
+ reFile = new File([rst.file], file.name, {
350
+ type: "image/jpeg",
351
+ lastModified: Date.now(),
352
+ });
353
+ return reFile;
354
+ } catch (error) {
355
+ return "";
356
+ }
357
+ }
358
+
359
+ /**
360
+ * @param {Blob} file 上传的图片文件
361
+ * @param {Number} size 指定压缩后的图片大小
362
+ * @param {Number} quality 压缩质量
363
+ * @returns 返回压缩后的图片文件
364
+ */
365
+ // 循环压缩
366
+ export async function loopCompressFile(file, size, quality) {
367
+ if (!size) {
368
+ return new Error("size 不能为空");
369
+ }
370
+ // let reFile = file;
371
+ const reFile = await compressFile(file, quality);
372
+ if (reFile.size > size) {
373
+ compressFile(reFile, quality);
374
+ }
375
+ return reFile;
376
+ }
377
+
378
+ // 判断html文档中是否有重复引用的标签
379
+ /**
380
+ * @param {String} src 要检查的引用地址
381
+ */
382
+ function chectDuplicateScript(src) {
383
+ let result = false;
384
+ // 获取文档中所有的script标签
385
+ const scriptTags = document.getElementsByTagName("script");
386
+ // 创建一个存储已经出现过的URL集合
387
+ const scriptURLs = new Set();
388
+ // 遍历所有的tag 标签
389
+ for (let i = 0; i < scriptTags.length; i++) {
390
+ const currentSrc = scriptTags[i].getAttribute("src");
391
+ if (currentSrc && currentSrc === src) {
392
+ if (scriptURLs.has(currentSrc)) {
393
+ // console.log('重复引用,引用地址为', currentSrc);
394
+ result = true;
395
+ } else {
396
+ scriptURLs.add(currentSrc);
397
+ }
398
+ }
399
+ }
400
+ if (scriptURLs.size === 0) {
401
+ result = false;
402
+ // console.log('没有重复引用', src);
403
+ }
404
+ return result;
405
+ }
406
+ // 动态引入JS文件
407
+ export function loadJavaScript(src, callback) {
408
+ if (chectDuplicateScript(src)) return;
409
+ const script = document.createElement("script");
410
+ const head = document.getElementsByTagName("head")[0];
411
+ script.type = "text/javascript";
412
+ script.charset = "UTF-8";
413
+ script.src = src;
414
+ window.onerror = () => {
415
+ console.log(`loadJavaScript加载${src}失败`);
416
+ };
417
+ if (script.addEventListener) {
418
+ script.addEventListener(
419
+ "load",
420
+ function () {
421
+ callback();
422
+ },
423
+ false
424
+ );
425
+ } else if (script.attachEvent) {
426
+ script.attachEvent("onreadystatechange", function () {
427
+ const target = window.event.srcElement;
428
+ if (target.readyState === "loaded" || script.readState === "complate") {
429
+ callback();
430
+ }
431
+ });
432
+ }
433
+ script.addEventListener("error", (e) => {
434
+ if (!isEmpty(e)) {
435
+ callback("err");
436
+ }
437
+ });
438
+ if (src) {
439
+ // 如果src不存在,不加入到项目里面去,否则会报加载资源失败
440
+ head.appendChild(script);
441
+ }
442
+ }
443
+ /**
444
+ * 为空
445
+ * @param val
446
+ * @returns {boolean}
447
+ */
448
+ function isEmpty(val) {
449
+ if (
450
+ val === null ||
451
+ val === undefined ||
452
+ (typeof val === "string" &&
453
+ (val === "" || val === "undefined" || val === "null")) ||
454
+ (Array.isArray(val) && val.length === 0) ||
455
+ (Object.prototype.toString.call(val) === "[object Object]" &&
456
+ Object.keys(val).length === 0)
457
+ ) {
458
+ return true;
459
+ }
460
+ return false;
461
+ }
462
+
463
+ function removeLeadingSlash(str) {
464
+ if (str.startsWith("/")) {
465
+ return str.substring(1); // 返回去掉斜杠后的值
466
+ }
467
+ return str; // 如果字符串不以斜杠开头,则返回原始字符串
468
+ }