@liujitcn/kratos-admin-core 0.0.53 → 0.0.55
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/dist/package/declarations/src/api/base/v1/file.d.ts +3 -3
- package/dist/package/declarations/src/components/Upload/File.vue.d.ts +3 -1
- package/dist/package/declarations/src/components/Upload/Files.vue.d.ts +3 -1
- package/dist/package/declarations/src/components/Upload/Img.vue.d.ts +4 -2
- package/dist/package/declarations/src/components/Upload/Imgs.vue.d.ts +3 -1
- package/dist/package/declarations/src/hooks/useImageUrl.d.ts +8 -0
- package/dist/package/declarations/src/hooks/useLogoUrl.d.ts +8 -0
- package/dist/package/declarations/src/rpc/base/v1/file.d.ts +11 -0
- package/dist/package/src/api/base/v1/file.ts +5 -3
- package/dist/package/src/assets/images/logo.svg +7 -1
- package/dist/package/src/components/Upload/File.vue +5 -3
- package/dist/package/src/components/Upload/Files.vue +5 -3
- package/dist/package/src/components/Upload/Img.vue +5 -3
- package/dist/package/src/components/Upload/Imgs.vue +5 -3
- package/dist/package/src/hooks/useImageUrl.ts +25 -0
- package/dist/package/src/hooks/useLogoUrl.ts +11 -0
- package/dist/package/src/layouts/LayoutClassic/index.vue +9 -2
- package/dist/package/src/layouts/LayoutColumns/index.vue +9 -2
- package/dist/package/src/layouts/LayoutTransverse/index.vue +9 -2
- package/dist/package/src/layouts/LayoutVertical/index.vue +4 -1
- package/dist/package/src/rpc/base/v1/file.ts +12 -0
- package/dist/package/src/views/login/index.vue +24 -4
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { BaseFileAccessMode, type MultiUploadFileResponse, type FileInfo } from "../../../rpc/base/v1/file";
|
|
2
2
|
/** 文件服务 */
|
|
3
3
|
export declare class FileServiceImpl {
|
|
4
4
|
/** 多个文件上传 */
|
|
5
|
-
MultiUploadFile(files: File[], fileType: string): Promise<MultiUploadFileResponse>;
|
|
5
|
+
MultiUploadFile(files: File[], fileType: string, accessMode?: BaseFileAccessMode): Promise<MultiUploadFileResponse>;
|
|
6
6
|
/** 上传文件 */
|
|
7
|
-
UploadFile(file: File, fileType: string): Promise<FileInfo>;
|
|
7
|
+
UploadFile(file: File, fileType: string, accessMode?: BaseFileAccessMode): Promise<FileInfo>;
|
|
8
8
|
/** 读取文件内容并返回 Blob。 */
|
|
9
9
|
GetFileBlob(file: string, fileName: string): Promise<Blob>;
|
|
10
10
|
/** 下载文件 */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UploadUserFile } from "element-plus";
|
|
2
|
-
import type
|
|
2
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
3
3
|
/** 单文件上传组件属性。 */
|
|
4
4
|
interface UploadFileProps {
|
|
5
5
|
fileInfo?: UploadUserFile;
|
|
@@ -8,6 +8,7 @@ interface UploadFileProps {
|
|
|
8
8
|
fileSize?: number;
|
|
9
9
|
fileType?: string[];
|
|
10
10
|
uploadType?: string;
|
|
11
|
+
accessMode?: BaseFileAccessMode;
|
|
11
12
|
}
|
|
12
13
|
declare const __VLS_export: import("vue").DefineComponent<UploadFileProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
14
|
"update:fileInfo": (value: UploadUserFile | undefined) => any;
|
|
@@ -16,6 +17,7 @@ declare const __VLS_export: import("vue").DefineComponent<UploadFileProps, {}, {
|
|
|
16
17
|
}>, {
|
|
17
18
|
disabled: boolean;
|
|
18
19
|
fileType: string[];
|
|
20
|
+
accessMode: BaseFileAccessMode;
|
|
19
21
|
uploadType: string;
|
|
20
22
|
fileInfo: UploadUserFile;
|
|
21
23
|
fileSize: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UploadUserFile } from "element-plus";
|
|
2
|
-
import type
|
|
2
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
3
3
|
/** 多文件上传组件属性。 */
|
|
4
4
|
interface UploadFilesProps {
|
|
5
5
|
fileList: UploadUserFile[];
|
|
@@ -9,6 +9,7 @@ interface UploadFilesProps {
|
|
|
9
9
|
fileSize?: number;
|
|
10
10
|
fileType?: string[];
|
|
11
11
|
uploadType?: string;
|
|
12
|
+
accessMode?: BaseFileAccessMode;
|
|
12
13
|
}
|
|
13
14
|
declare const __VLS_export: import("vue").DefineComponent<UploadFilesProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
15
|
"update:fileList": (value: UploadUserFile[]) => any;
|
|
@@ -17,6 +18,7 @@ declare const __VLS_export: import("vue").DefineComponent<UploadFilesProps, {},
|
|
|
17
18
|
}>, {
|
|
18
19
|
disabled: boolean;
|
|
19
20
|
fileType: string[];
|
|
21
|
+
accessMode: BaseFileAccessMode;
|
|
20
22
|
uploadType: string;
|
|
21
23
|
fileSize: number;
|
|
22
24
|
fileList: UploadUserFile[];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
2
2
|
/** 单图上传组件属性。 */
|
|
3
3
|
interface UploadFileProps {
|
|
4
4
|
imageUrl: string;
|
|
5
5
|
api?: (file: File) => Promise<FileInfo>;
|
|
6
6
|
uploadType?: string;
|
|
7
|
+
accessMode?: BaseFileAccessMode;
|
|
7
8
|
drag?: boolean;
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
fileSize?: number;
|
|
@@ -27,10 +28,11 @@ declare const __VLS_base: import("vue").DefineComponent<UploadFileProps, {}, {},
|
|
|
27
28
|
width: string;
|
|
28
29
|
height: string;
|
|
29
30
|
drag: boolean;
|
|
31
|
+
imageUrl: string;
|
|
30
32
|
fileType: File.ImageMimeType[];
|
|
33
|
+
accessMode: BaseFileAccessMode;
|
|
31
34
|
uploadType: string;
|
|
32
35
|
fileSize: number;
|
|
33
|
-
imageUrl: string;
|
|
34
36
|
borderRadius: string;
|
|
35
37
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
36
38
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { UploadUserFile } from "element-plus";
|
|
2
|
-
import type
|
|
2
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
3
3
|
/** 多图上传组件属性。 */
|
|
4
4
|
interface UploadFileProps {
|
|
5
5
|
fileList: UploadUserFile[];
|
|
6
6
|
api?: (file: File) => Promise<FileInfo>;
|
|
7
7
|
uploadType?: string;
|
|
8
|
+
accessMode?: BaseFileAccessMode;
|
|
8
9
|
drag?: boolean;
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
limit?: number;
|
|
@@ -30,6 +31,7 @@ declare const __VLS_base: import("vue").DefineComponent<UploadFileProps, {}, {},
|
|
|
30
31
|
height: string;
|
|
31
32
|
drag: boolean;
|
|
32
33
|
fileType: File.ImageMimeType[];
|
|
34
|
+
accessMode: BaseFileAccessMode;
|
|
33
35
|
uploadType: string;
|
|
34
36
|
fileSize: number;
|
|
35
37
|
fileList: UploadUserFile[];
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { BytesValue } from "../../google/protobuf/wrappers";
|
|
2
|
+
/** 文件访问方式。 */
|
|
3
|
+
export declare enum BaseFileAccessMode {
|
|
4
|
+
/** BASE_FILE_ACCESS_MODE_UNSPECIFIED - 未指定文件访问方式,服务端按授权访问处理。 */
|
|
5
|
+
BASE_FILE_ACCESS_MODE_UNSPECIFIED = 0,
|
|
6
|
+
/** BASE_FILE_ACCESS_MODE_PUBLIC - 允许匿名公开访问。 */
|
|
7
|
+
BASE_FILE_ACCESS_MODE_PUBLIC = 1,
|
|
8
|
+
/** BASE_FILE_ACCESS_MODE_AUTHORIZED - 必须携带有效访问令牌。 */
|
|
9
|
+
BASE_FILE_ACCESS_MODE_AUTHORIZED = 2
|
|
10
|
+
}
|
|
2
11
|
/** 批量上传文件请求参数 */
|
|
3
12
|
export interface MultiUploadFileRequest {
|
|
4
13
|
/** 文件名 */
|
|
@@ -24,6 +33,8 @@ export interface UploadFileInfo {
|
|
|
24
33
|
path: string;
|
|
25
34
|
/** 二进制内容将通过 base64 编码传输 */
|
|
26
35
|
content: Uint8Array;
|
|
36
|
+
/** 文件访问方式,未指定时默认需要访问令牌 */
|
|
37
|
+
access_mode: BaseFileAccessMode;
|
|
27
38
|
}
|
|
28
39
|
/** 下载文件请求参数 */
|
|
29
40
|
export interface DownloadFileRequest {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import service from "../../../utils/request";
|
|
2
|
-
import type
|
|
2
|
+
import { BaseFileAccessMode, type DownloadFileRequest, type MultiUploadFileResponse, type FileInfo } from "../../../rpc/base/v1/file";
|
|
3
3
|
|
|
4
4
|
const FILE_URL = "/v1/base/file";
|
|
5
5
|
|
|
6
6
|
/** 文件服务 */
|
|
7
7
|
export class FileServiceImpl {
|
|
8
8
|
/** 多个文件上传 */
|
|
9
|
-
MultiUploadFile(files: File[], fileType: string): Promise<MultiUploadFileResponse> {
|
|
9
|
+
MultiUploadFile(files: File[], fileType: string, accessMode = BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED): Promise<MultiUploadFileResponse> {
|
|
10
10
|
const formData = new FormData();
|
|
11
11
|
files.map(file => {
|
|
12
12
|
formData.append(file.name, file);
|
|
13
13
|
});
|
|
14
14
|
formData.append("fileType", fileType);
|
|
15
|
+
formData.append("accessMode", String(accessMode));
|
|
15
16
|
return service<FormData, MultiUploadFileResponse>({
|
|
16
17
|
url: `${FILE_URL}/multi`,
|
|
17
18
|
method: "post",
|
|
@@ -22,10 +23,11 @@ export class FileServiceImpl {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
/** 上传文件 */
|
|
25
|
-
UploadFile(file: File, fileType: string): Promise<FileInfo> {
|
|
26
|
+
UploadFile(file: File, fileType: string, accessMode = BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED): Promise<FileInfo> {
|
|
26
27
|
const formData = new FormData();
|
|
27
28
|
formData.append("file", file);
|
|
28
29
|
formData.append("fileType", fileType);
|
|
30
|
+
formData.append("accessMode", String(accessMode));
|
|
29
31
|
return service<FormData, FileInfo>({
|
|
30
32
|
url: `${FILE_URL}`,
|
|
31
33
|
method: "post",
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Admin logo">
|
|
2
|
+
<rect width="64" height="64" rx="16" fill="#2563eb"/>
|
|
3
|
+
<path fill="#fff" d="M17 18.5A4.5 4.5 0 0 1 21.5 14h21a4.5 4.5 0 0 1 4.5 4.5v25a4.5 4.5 0 0 1-4.5 4.5h-21a4.5 4.5 0 0 1-4.5-4.5v-25Zm5 1.5v21h20V20.5H22Zm0 25h20v-1H22v1Z"/>
|
|
4
|
+
<circle cx="23" cy="17.5" r="1.5" fill="#93c5fd"/>
|
|
5
|
+
<circle cx="28" cy="17.5" r="1.5" fill="#93c5fd"/>
|
|
6
|
+
<path fill="#93c5fd" d="M25 26h3v10h-3V26Zm5-3h3v13h-3V23Zm5 6h3v7h-3v-7Z"/>
|
|
7
|
+
</svg>
|
|
@@ -39,7 +39,7 @@ import { Delete, Document, Download } from "@element-plus/icons-vue";
|
|
|
39
39
|
import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
|
|
40
40
|
import type { UploadProps, UploadRequestOptions, UploadUserFile } from "element-plus";
|
|
41
41
|
import { defFileService } from "../../api/base/v1/file";
|
|
42
|
-
import type
|
|
42
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
43
43
|
import { useLocaleStore } from "../../locales";
|
|
44
44
|
|
|
45
45
|
const { t } = useLocaleStore();
|
|
@@ -52,6 +52,7 @@ interface UploadFileProps {
|
|
|
52
52
|
fileSize?: number;
|
|
53
53
|
fileType?: string[];
|
|
54
54
|
uploadType?: string;
|
|
55
|
+
accessMode?: BaseFileAccessMode; // 文件访问方式,默认需要访问令牌。
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
@@ -59,7 +60,8 @@ const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
|
59
60
|
disabled: false,
|
|
60
61
|
fileSize: 20,
|
|
61
62
|
fileType: () => [],
|
|
62
|
-
uploadType: "file"
|
|
63
|
+
uploadType: "file",
|
|
64
|
+
accessMode: BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
const emit = defineEmits<{
|
|
@@ -113,7 +115,7 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
|
|
|
113
115
|
/** 执行自定义文件上传。 */
|
|
114
116
|
const handleHttpUpload = async (options: UploadRequestOptions) => {
|
|
115
117
|
try {
|
|
116
|
-
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType));
|
|
118
|
+
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType, props.accessMode));
|
|
117
119
|
const data = await api(options.file);
|
|
118
120
|
options.onSuccess(data);
|
|
119
121
|
} catch (error) {
|
|
@@ -45,7 +45,7 @@ import { Delete, Document, Download } from "@element-plus/icons-vue";
|
|
|
45
45
|
import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
|
|
46
46
|
import type { UploadProps, UploadRequestOptions, UploadUserFile } from "element-plus";
|
|
47
47
|
import { defFileService } from "../../api/base/v1/file";
|
|
48
|
-
import type
|
|
48
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
49
49
|
import { useLocaleStore } from "../../locales";
|
|
50
50
|
|
|
51
51
|
const { t } = useLocaleStore();
|
|
@@ -59,6 +59,7 @@ interface UploadFilesProps {
|
|
|
59
59
|
fileSize?: number;
|
|
60
60
|
fileType?: string[];
|
|
61
61
|
uploadType?: string;
|
|
62
|
+
accessMode?: BaseFileAccessMode; // 文件访问方式,默认需要访问令牌。
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
const props = withDefaults(defineProps<UploadFilesProps>(), {
|
|
@@ -67,7 +68,8 @@ const props = withDefaults(defineProps<UploadFilesProps>(), {
|
|
|
67
68
|
limit: 5,
|
|
68
69
|
fileSize: 20,
|
|
69
70
|
fileType: () => [],
|
|
70
|
-
uploadType: "file"
|
|
71
|
+
uploadType: "file",
|
|
72
|
+
accessMode: BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
const emit = defineEmits<{
|
|
@@ -129,7 +131,7 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
|
|
|
129
131
|
/** 执行多文件自定义上传。 */
|
|
130
132
|
const handleHttpUpload = async (options: UploadRequestOptions) => {
|
|
131
133
|
try {
|
|
132
|
-
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType));
|
|
134
|
+
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType, props.accessMode));
|
|
133
135
|
const data = await api(options.file);
|
|
134
136
|
options.onSuccess(data);
|
|
135
137
|
} catch (error) {
|
|
@@ -54,7 +54,7 @@ import { formatSrc } from "../../utils/utils";
|
|
|
54
54
|
import { defFileService } from "../../api/base/v1/file";
|
|
55
55
|
import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
|
|
56
56
|
import type { UploadProps, UploadRequestOptions } from "element-plus";
|
|
57
|
-
import type
|
|
57
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
58
58
|
import { useLocaleStore } from "../../locales";
|
|
59
59
|
|
|
60
60
|
const { t } = useLocaleStore();
|
|
@@ -63,7 +63,8 @@ const { t } = useLocaleStore();
|
|
|
63
63
|
interface UploadFileProps {
|
|
64
64
|
imageUrl: string; // 图片地址 ==> 必传
|
|
65
65
|
api?: (file: File) => Promise<FileInfo>; // 上传图片的 api 方法,默认使用当前文件服务 ==> 非必传
|
|
66
|
-
uploadType?: string;
|
|
66
|
+
uploadType?: string;
|
|
67
|
+
accessMode?: BaseFileAccessMode; // 文件访问方式,默认需要访问令牌。
|
|
67
68
|
drag?: boolean; // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
|
68
69
|
disabled?: boolean; // 是否禁用上传组件 ==> 非必传(默认为 false)
|
|
69
70
|
fileSize?: number; // 图片大小限制 ==> 非必传(默认为 5M)
|
|
@@ -77,6 +78,7 @@ interface UploadFileProps {
|
|
|
77
78
|
const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
78
79
|
imageUrl: "",
|
|
79
80
|
uploadType: "image",
|
|
81
|
+
accessMode: BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED,
|
|
80
82
|
drag: true,
|
|
81
83
|
disabled: false,
|
|
82
84
|
fileSize: 5,
|
|
@@ -112,7 +114,7 @@ const emit = defineEmits<{
|
|
|
112
114
|
const handleHttpUpload = async (options: UploadRequestOptions) => {
|
|
113
115
|
try {
|
|
114
116
|
// 优先使用页面显式传入的业务上传类型,避免不同业务图片都落到同一个 image 分类。
|
|
115
|
-
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType));
|
|
117
|
+
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType, props.accessMode));
|
|
116
118
|
const data = await api(options.file);
|
|
117
119
|
emit("update:imageUrl", data.url);
|
|
118
120
|
// 调用 el-form 内部的校验方法(可自动校验)
|
|
@@ -50,7 +50,7 @@ import { defFileService } from "../../api/base/v1/file";
|
|
|
50
50
|
import { formatSrc } from "../../utils/utils";
|
|
51
51
|
import type { UploadProps, UploadFile, UploadUserFile, UploadRequestOptions } from "element-plus";
|
|
52
52
|
import { ElNotification, formContextKey, formItemContextKey } from "element-plus";
|
|
53
|
-
import type
|
|
53
|
+
import { BaseFileAccessMode, type FileInfo } from "../../rpc/base/v1/file";
|
|
54
54
|
import { useLocaleStore } from "../../locales";
|
|
55
55
|
|
|
56
56
|
const { t } = useLocaleStore();
|
|
@@ -59,7 +59,8 @@ const { t } = useLocaleStore();
|
|
|
59
59
|
interface UploadFileProps {
|
|
60
60
|
fileList: UploadUserFile[];
|
|
61
61
|
api?: (file: File) => Promise<FileInfo>; // 上传图片的 api 方法,默认使用当前文件服务 ==> 非必传
|
|
62
|
-
uploadType?: string;
|
|
62
|
+
uploadType?: string;
|
|
63
|
+
accessMode?: BaseFileAccessMode; // 文件访问方式,默认需要访问令牌。
|
|
63
64
|
drag?: boolean; // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
|
64
65
|
disabled?: boolean; // 是否禁用上传组件 ==> 非必传(默认为 false)
|
|
65
66
|
limit?: number; // 最大图片上传数 ==> 非必传(默认为 5张)
|
|
@@ -73,6 +74,7 @@ interface UploadFileProps {
|
|
|
73
74
|
const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
74
75
|
fileList: () => [],
|
|
75
76
|
uploadType: "image",
|
|
77
|
+
accessMode: BaseFileAccessMode.BASE_FILE_ACCESS_MODE_AUTHORIZED,
|
|
76
78
|
drag: true,
|
|
77
79
|
disabled: false,
|
|
78
80
|
limit: 5,
|
|
@@ -133,7 +135,7 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
|
|
|
133
135
|
const handleHttpUpload = async (options: UploadRequestOptions) => {
|
|
134
136
|
try {
|
|
135
137
|
// 优先使用页面显式传入的业务上传类型,避免不同业务图片都落到同一个 image 分类。
|
|
136
|
-
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType));
|
|
138
|
+
const api = props.api ?? (file => defFileService.UploadFile(file, props.uploadType, props.accessMode));
|
|
137
139
|
const data = await api(options.file);
|
|
138
140
|
options.onSuccess(data);
|
|
139
141
|
} catch (error) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ref, watch, type Ref } from "vue";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 管理图片地址,并在配置地址为空或加载失败时回退到指定的本地资源。
|
|
5
|
+
*/
|
|
6
|
+
export function useImageUrl(configuredImageUrl: Readonly<Ref<string>>, fallbackImageUrl: string) {
|
|
7
|
+
const imageUrl = ref(fallbackImageUrl);
|
|
8
|
+
|
|
9
|
+
watch(
|
|
10
|
+
configuredImageUrl,
|
|
11
|
+
value => {
|
|
12
|
+
imageUrl.value = value || fallbackImageUrl;
|
|
13
|
+
},
|
|
14
|
+
{ immediate: true }
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
/** 图片加载失败时回退到指定的本地资源。 */
|
|
18
|
+
const handleImageError = () => {
|
|
19
|
+
if (imageUrl.value !== fallbackImageUrl) {
|
|
20
|
+
imageUrl.value = fallbackImageUrl;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return { imageUrl, handleImageError };
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Ref } from "vue";
|
|
2
|
+
import defaultLogoUrl from "../assets/images/logo.svg";
|
|
3
|
+
import { useImageUrl } from "../hooks/useImageUrl";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 管理站点 Logo 地址,并在配置地址不可用时回退到本地默认 Logo。
|
|
7
|
+
*/
|
|
8
|
+
export function useLogoUrl(configuredLogoUrl: Readonly<Ref<string>>) {
|
|
9
|
+
const { imageUrl, handleImageError } = useImageUrl(configuredLogoUrl, defaultLogoUrl);
|
|
10
|
+
return { logoUrl: imageUrl, handleLogoError: handleImageError };
|
|
11
|
+
}
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
<el-header>
|
|
5
5
|
<div class="header-lf mask-image">
|
|
6
6
|
<div class="logo flx-center">
|
|
7
|
-
<img
|
|
7
|
+
<img
|
|
8
|
+
class="logo-img"
|
|
9
|
+
:src="logoUrl"
|
|
10
|
+
:alt="t('core.layout.logo_alt')"
|
|
11
|
+
@error="handleLogoError"
|
|
12
|
+
/>
|
|
8
13
|
<span class="logo-text">{{ title }}</span>
|
|
9
14
|
</div>
|
|
10
15
|
<ToolBarLeft />
|
|
@@ -47,6 +52,7 @@ import SubMenu from "../../layouts/components/Menu/SubMenu.vue";
|
|
|
47
52
|
import ToolBarLeft from "../../layouts/components/Header/ToolBarLeft.vue";
|
|
48
53
|
import ToolBarRight from "../../layouts/components/Header/ToolBarRight.vue";
|
|
49
54
|
import { useLocaleStore } from "../../locales";
|
|
55
|
+
import { useLogoUrl } from "../../hooks/useLogoUrl";
|
|
50
56
|
|
|
51
57
|
const route = useRoute();
|
|
52
58
|
const authStore = useAuthStore();
|
|
@@ -58,7 +64,8 @@ const isCollapse = computed(() => globalStore.isCollapse);
|
|
|
58
64
|
const menuList = computed(() => authStore.showMenuListGet);
|
|
59
65
|
const activeMenu = computed(() => route.path as string);
|
|
60
66
|
const title = computed(() => configStore.display.sysName || import.meta.env.VITE_GLOB_APP_TITLE);
|
|
61
|
-
const
|
|
67
|
+
const configuredLogoUrl = computed(() => configStore.display.adminLogo);
|
|
68
|
+
const { logoUrl, handleLogoError } = useLogoUrl(configuredLogoUrl);
|
|
62
69
|
</script>
|
|
63
70
|
|
|
64
71
|
<style scoped lang="scss">
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
<el-container class="layout">
|
|
4
4
|
<div class="aside-split">
|
|
5
5
|
<div class="logo flx-center">
|
|
6
|
-
<img
|
|
6
|
+
<img
|
|
7
|
+
class="logo-img"
|
|
8
|
+
:src="logoUrl"
|
|
9
|
+
:alt="t('core.layout.logo_alt')"
|
|
10
|
+
@error="handleLogoError"
|
|
11
|
+
/>
|
|
7
12
|
</div>
|
|
8
13
|
<el-scrollbar>
|
|
9
14
|
<div class="split-list">
|
|
@@ -61,6 +66,7 @@ import ToolBarLeft from "../../layouts/components/Header/ToolBarLeft.vue";
|
|
|
61
66
|
import ToolBarRight from "../../layouts/components/Header/ToolBarRight.vue";
|
|
62
67
|
import SubMenu from "../../layouts/components/Menu/SubMenu.vue";
|
|
63
68
|
import { useLocaleStore } from "../../locales";
|
|
69
|
+
import { useLogoUrl } from "../../hooks/useLogoUrl";
|
|
64
70
|
|
|
65
71
|
const route = useRoute();
|
|
66
72
|
const router = useRouter();
|
|
@@ -74,7 +80,8 @@ const menuList = computed(() => authStore.showMenuListGet.filter(item => Boolean
|
|
|
74
80
|
const activeMenu = computed(() => route.path as string);
|
|
75
81
|
const title = computed(() => configStore.display.sysName || import.meta.env.VITE_GLOB_APP_TITLE);
|
|
76
82
|
const collapseTitle = computed(() => title.value.slice(0, 1).toUpperCase() || "S");
|
|
77
|
-
const
|
|
83
|
+
const configuredLogoUrl = computed(() => configStore.display.adminLogo);
|
|
84
|
+
const { logoUrl, handleLogoError } = useLogoUrl(configuredLogoUrl);
|
|
78
85
|
|
|
79
86
|
const subMenuList = ref<RouteItem[]>([]);
|
|
80
87
|
const splitActive = ref("");
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
<el-container class="layout">
|
|
4
4
|
<el-header>
|
|
5
5
|
<div class="logo flx-center">
|
|
6
|
-
<img
|
|
6
|
+
<img
|
|
7
|
+
class="logo-img"
|
|
8
|
+
:src="logoUrl"
|
|
9
|
+
:alt="t('core.layout.logo_alt')"
|
|
10
|
+
@error="handleLogoError"
|
|
11
|
+
/>
|
|
7
12
|
<span class="logo-text">{{ title }}</span>
|
|
8
13
|
</div>
|
|
9
14
|
<el-menu mode="horizontal" :router="false" :default-active="activeMenu">
|
|
@@ -45,6 +50,7 @@ import Main from "../../layouts/components/Main/index.vue";
|
|
|
45
50
|
import ToolBarRight from "../../layouts/components/Header/ToolBarRight.vue";
|
|
46
51
|
import SubMenu from "../../layouts/components/Menu/SubMenu.vue";
|
|
47
52
|
import { useLocaleStore } from "../../locales";
|
|
53
|
+
import { useLogoUrl } from "../../hooks/useLogoUrl";
|
|
48
54
|
|
|
49
55
|
const route = useRoute();
|
|
50
56
|
const router = useRouter();
|
|
@@ -54,7 +60,8 @@ const { t } = useLocaleStore();
|
|
|
54
60
|
const menuList = computed(() => authStore.showMenuListGet);
|
|
55
61
|
const activeMenu = computed(() => route.path as string);
|
|
56
62
|
const title = computed(() => configStore.display.sysName || import.meta.env.VITE_GLOB_APP_TITLE);
|
|
57
|
-
const
|
|
63
|
+
const configuredLogoUrl = computed(() => configStore.display.adminLogo);
|
|
64
|
+
const { logoUrl, handleLogoError } = useLogoUrl(configuredLogoUrl);
|
|
58
65
|
|
|
59
66
|
const handleClickMenu = (subItem: RouteItem) => {
|
|
60
67
|
const target = getRouteTarget(subItem);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
class="logo-img"
|
|
11
11
|
:src="logoUrl"
|
|
12
12
|
:alt="t('core.layout.logo_alt')"
|
|
13
|
+
@error="handleLogoError"
|
|
13
14
|
/>
|
|
14
15
|
<span
|
|
15
16
|
v-show="!isCollapse"
|
|
@@ -53,6 +54,7 @@ import ToolBarLeft from "../../layouts/components/Header/ToolBarLeft.vue";
|
|
|
53
54
|
import ToolBarRight from "../../layouts/components/Header/ToolBarRight.vue";
|
|
54
55
|
import SubMenu from "../../layouts/components/Menu/SubMenu.vue";
|
|
55
56
|
import { useLocaleStore } from "../../locales";
|
|
57
|
+
import { useLogoUrl } from "../../hooks/useLogoUrl";
|
|
56
58
|
|
|
57
59
|
const route = useRoute();
|
|
58
60
|
const authStore = useAuthStore();
|
|
@@ -64,7 +66,8 @@ const isCollapse = computed(() => globalStore.isCollapse);
|
|
|
64
66
|
const menuList = computed(() => authStore.showMenuListGet);
|
|
65
67
|
const activeMenu = computed(() => route.path as string);
|
|
66
68
|
const title = computed(() => configStore.display.sysName || import.meta.env.VITE_GLOB_APP_TITLE);
|
|
67
|
-
const
|
|
69
|
+
const configuredLogoUrl = computed(() => configStore.display.adminLogo);
|
|
70
|
+
const { logoUrl, handleLogoError } = useLogoUrl(configuredLogoUrl);
|
|
68
71
|
const logoWrapperRef = ref<HTMLElement>();
|
|
69
72
|
const logoIconRef = ref<HTMLImageElement>();
|
|
70
73
|
const logoTextRef = ref<HTMLElement>();
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
/* eslint-disable */
|
|
8
8
|
import type { BytesValue } from "../../google/protobuf/wrappers";
|
|
9
9
|
|
|
10
|
+
/** 文件访问方式。 */
|
|
11
|
+
export enum BaseFileAccessMode {
|
|
12
|
+
/** BASE_FILE_ACCESS_MODE_UNSPECIFIED - 未指定文件访问方式,服务端按授权访问处理。 */
|
|
13
|
+
BASE_FILE_ACCESS_MODE_UNSPECIFIED = 0,
|
|
14
|
+
/** BASE_FILE_ACCESS_MODE_PUBLIC - 允许匿名公开访问。 */
|
|
15
|
+
BASE_FILE_ACCESS_MODE_PUBLIC = 1,
|
|
16
|
+
/** BASE_FILE_ACCESS_MODE_AUTHORIZED - 必须携带有效访问令牌。 */
|
|
17
|
+
BASE_FILE_ACCESS_MODE_AUTHORIZED = 2,
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
/** 批量上传文件请求参数 */
|
|
11
21
|
export interface MultiUploadFileRequest {
|
|
12
22
|
/** 文件名 */
|
|
@@ -35,6 +45,8 @@ export interface UploadFileInfo {
|
|
|
35
45
|
path: string;
|
|
36
46
|
/** 二进制内容将通过 base64 编码传输 */
|
|
37
47
|
content: Uint8Array;
|
|
48
|
+
/** 文件访问方式,未指定时默认需要访问令牌 */
|
|
49
|
+
access_mode: BaseFileAccessMode;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
/** 下载文件请求参数 */
|
|
@@ -4,11 +4,23 @@
|
|
|
4
4
|
<SwitchDark class="dark" />
|
|
5
5
|
<LocaleSwitch v-if="languageOptions.length > 1" class="locale" />
|
|
6
6
|
<div class="login-left">
|
|
7
|
-
<img
|
|
7
|
+
<img
|
|
8
|
+
class="login-left-img"
|
|
9
|
+
:src="backgroundUrl"
|
|
10
|
+
:alt="t('core.login.background_alt')"
|
|
11
|
+
@error="handleBackgroundError"
|
|
12
|
+
/>
|
|
8
13
|
</div>
|
|
9
14
|
<div ref="loginFormRef" class="login-form">
|
|
10
15
|
<div ref="loginLogoRef" class="login-logo">
|
|
11
|
-
<img
|
|
16
|
+
<img
|
|
17
|
+
v-show="showLogoIcon"
|
|
18
|
+
ref="logoIconRef"
|
|
19
|
+
class="login-icon"
|
|
20
|
+
:src="logoUrl"
|
|
21
|
+
alt=""
|
|
22
|
+
@error="handleLogoError"
|
|
23
|
+
/>
|
|
12
24
|
<h2 ref="logoTextRef" class="logo-text" :style="{ fontSize: `${logoFontSize}px` }">{{ projectName }}</h2>
|
|
13
25
|
</div>
|
|
14
26
|
<LoginForm :dialog-anchor="loginFormRef" />
|
|
@@ -24,12 +36,20 @@ import SwitchDark from "../../components/SwitchDark/index.vue";
|
|
|
24
36
|
import LocaleSwitch from "../../components/LocaleSwitch/index.vue";
|
|
25
37
|
import { useConfigStore } from "../../stores/modules/config";
|
|
26
38
|
import { useLocaleStore } from "../../locales";
|
|
39
|
+
import defaultBackgroundUrl from "../../assets/images/login_left.png";
|
|
40
|
+
import { useLogoUrl } from "../../hooks/useLogoUrl";
|
|
41
|
+
import { useImageUrl } from "../../hooks/useImageUrl";
|
|
27
42
|
|
|
28
43
|
const configStore = useConfigStore();
|
|
29
44
|
const { t, languageOptions } = useLocaleStore();
|
|
30
45
|
const projectName = computed(() => configStore.display.sysName || import.meta.env.VITE_GLOB_APP_TITLE);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
46
|
+
const configuredLogoUrl = computed(() => configStore.display.adminLogo);
|
|
47
|
+
const { logoUrl, handleLogoError } = useLogoUrl(configuredLogoUrl);
|
|
48
|
+
const configuredBackgroundUrl = computed(() => configStore.display.background);
|
|
49
|
+
const { imageUrl: backgroundUrl, handleImageError: handleBackgroundError } = useImageUrl(
|
|
50
|
+
configuredBackgroundUrl,
|
|
51
|
+
defaultBackgroundUrl
|
|
52
|
+
);
|
|
33
53
|
|
|
34
54
|
const MAX_LOGO_FONT_SIZE = 42;
|
|
35
55
|
const PREFERRED_MIN_LOGO_FONT_SIZE = 30;
|