|
|
@@ -1,6 +1,7 @@
|
|
1
|
|
-import { joinFileUrl, API_HOST } from '@/config'
|
|
|
1
|
+import { FILE_BASE, API_HOST } from '@/config'
|
|
2
|
2
|
|
|
3
|
3
|
const PLACEHOLDER_PATHS = ['/static/logo.png']
|
|
|
4
|
+const API_PROXY_PREFIX = /^\/(dev-api|prod-api|shop-api)\//i
|
|
4
|
5
|
|
|
5
|
6
|
/** 是否外链或 data URL */
|
|
6
|
7
|
export function isExternalUrl(url) {
|
|
|
@@ -8,7 +9,7 @@ export function isExternalUrl(url) {
|
|
8
|
9
|
return /^(https?:|data:|\/\/)/i.test(String(url).trim())
|
|
9
|
10
|
}
|
|
10
|
11
|
|
|
11
|
|
-/** 去掉 /dev-api 等代理前缀,得到后端真实路径 */
|
|
|
12
|
+/** 去掉 /dev-api、/shop-api 等代理前缀,得到后端真实路径 */
|
|
12
|
13
|
function stripApiProxyPrefix(path) {
|
|
13
|
14
|
return String(path).replace(/^\/(dev-api|prod-api|shop-api)/, '') || '/'
|
|
14
|
15
|
}
|
|
|
@@ -18,6 +19,32 @@ function isPlaceholderPath(path) {
|
|
18
|
19
|
return PLACEHOLDER_PATHS.includes(raw)
|
|
19
|
20
|
}
|
|
20
|
21
|
|
|
|
22
|
+/**
|
|
|
23
|
+ * 图片根地址
|
|
|
24
|
+ * - H5 生产:自动取浏览器当前访问的 IP/域名(window.location.origin)
|
|
|
25
|
+ * - H5 开发 / 小程序:用 .env 里的 VITE_APP_API_HOST
|
|
|
26
|
+ */
|
|
|
27
|
+export function getFileBase() {
|
|
|
28
|
+ // #ifdef H5
|
|
|
29
|
+ if (import.meta.env.PROD && typeof window !== 'undefined') {
|
|
|
30
|
+ const origin = window.location?.origin
|
|
|
31
|
+ if (origin && origin !== 'null') {
|
|
|
32
|
+ return origin.replace(/\/$/, '')
|
|
|
33
|
+ }
|
|
|
34
|
+ }
|
|
|
35
|
+ // #endif
|
|
|
36
|
+ return String(FILE_BASE).replace(/\/$/, '')
|
|
|
37
|
+}
|
|
|
38
|
+
|
|
|
39
|
+/** 拼接图片完整 URL */
|
|
|
40
|
+function joinFileUrlRuntime(path) {
|
|
|
41
|
+ const base = getFileBase()
|
|
|
42
|
+ if (!path) return base
|
|
|
43
|
+ if (/^https?:\/\//i.test(path)) return path
|
|
|
44
|
+ const p = path.startsWith('/') ? path : `/${path}`
|
|
|
45
|
+ return base + p
|
|
|
46
|
+}
|
|
|
47
|
+
|
|
21
|
48
|
/**
|
|
22
|
49
|
* 是否已是可直接使用的图片地址(避免重复拼接)
|
|
23
|
50
|
*/
|
|
|
@@ -26,14 +53,17 @@ export function isResolvedFileUrl(url) {
|
|
26
|
53
|
const raw = String(url).trim()
|
|
27
|
54
|
if (isExternalUrl(raw)) return true
|
|
28
|
55
|
if (raw.startsWith('/static/')) return true
|
|
|
56
|
+ const fileBase = getFileBase()
|
|
|
57
|
+ if (fileBase && (raw === fileBase || raw.startsWith(`${fileBase}/`))) return true
|
|
|
58
|
+ if (API_PROXY_PREFIX.test(raw)) return true
|
|
29
|
59
|
const apiHost = String(API_HOST).replace(/\/$/, '')
|
|
30
|
|
- return !!(apiHost && (raw === apiHost || raw.startsWith(`${apiHost}/`)))
|
|
|
60
|
+ return !!(apiHost && apiHost.startsWith('http') && (raw === apiHost || raw.startsWith(`${apiHost}/`)))
|
|
31
|
61
|
}
|
|
32
|
62
|
|
|
33
|
63
|
/**
|
|
34
|
|
- * 将后端返回的图片路径转为可展示的完整 URL(可重复调用)
|
|
35
|
|
- * 结果形如:http://192.168.1.6:8020/profile/upload/xxx.jpg
|
|
36
|
|
- * @param {string} path bannerImage / categoryPic / mainPic 等
|
|
|
64
|
+ * 将后端返回的图片路径转为可展示的 URL(可重复调用)
|
|
|
65
|
+ * - H5 生产:http://当前访问IP/profile/upload/xxx.jpg(自动)
|
|
|
66
|
+ * - 开发:http://VITE_APP_API_HOST/profile/upload/xxx.jpg
|
|
37
|
67
|
*/
|
|
38
|
68
|
export function resolveFileUrl(path) {
|
|
39
|
69
|
if (path == null || path === '') {
|
|
|
@@ -43,26 +73,32 @@ export function resolveFileUrl(path) {
|
|
43
|
73
|
if (!raw || isPlaceholderPath(raw)) {
|
|
44
|
74
|
return ''
|
|
45
|
75
|
}
|
|
46
|
|
- if (isExternalUrl(raw)) {
|
|
|
76
|
+ if (isExternalUrl(raw) || raw.startsWith('/static/')) {
|
|
|
77
|
+ return raw
|
|
|
78
|
+ }
|
|
|
79
|
+
|
|
|
80
|
+ const fileBase = getFileBase()
|
|
|
81
|
+ if (fileBase && (raw === fileBase || raw.startsWith(`${fileBase}/`))) {
|
|
47
|
82
|
return raw
|
|
48
|
83
|
}
|
|
49
|
|
- if (raw.startsWith('/static/')) {
|
|
|
84
|
+ if (API_PROXY_PREFIX.test(raw)) {
|
|
50
|
85
|
return raw
|
|
51
|
86
|
}
|
|
|
87
|
+
|
|
52
|
88
|
const apiHost = String(API_HOST).replace(/\/$/, '')
|
|
53
|
|
- if (apiHost && (raw === apiHost || raw.startsWith(`${apiHost}/`))) {
|
|
|
89
|
+ if (apiHost && apiHost.startsWith('http') && (raw === apiHost || raw.startsWith(`${apiHost}/`))) {
|
|
54
|
90
|
return raw
|
|
55
|
91
|
}
|
|
56
|
|
- if (/^\/(dev-api|prod-api|shop-api)\//i.test(raw)) {
|
|
|
92
|
+
|
|
|
93
|
+ if (API_PROXY_PREFIX.test(raw)) {
|
|
57
|
94
|
raw = stripApiProxyPrefix(raw)
|
|
58
|
95
|
}
|
|
59
|
96
|
const normalized = raw.startsWith('/') ? raw : `/${raw}`
|
|
60
|
|
- return joinFileUrl(normalized)
|
|
|
97
|
+ return joinFileUrlRuntime(normalized)
|
|
61
|
98
|
}
|
|
62
|
99
|
|
|
63
|
100
|
/**
|
|
64
|
|
- * 将逗号分隔或数组形式的图片路径转为完整 URL 列表
|
|
65
|
|
- * @param {string|string[]|null|undefined} pathOrList
|
|
|
101
|
+ * 将逗号分隔或数组形式的图片路径转为 URL 列表
|
|
66
|
102
|
*/
|
|
67
|
103
|
export function resolveFileUrlList(pathOrList) {
|
|
68
|
104
|
if (pathOrList == null || pathOrList === '') return []
|