@smartos-lib/components 1.7.0-beta.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.
- package/.eslintrc +12 -0
- package/.eslintrc-auto-import.json +332 -0
- package/Components.code-workspace +143 -0
- package/LICENSE +21 -0
- package/dist/smart-docx-editor/index.d.ts +2 -0
- package/dist/smart-docx-editor/index.js +68 -0
- package/dist/smart-file-preview/index.d.ts +18 -0
- package/dist/smart-file-preview/index.js +37 -0
- package/dist/smart-upload/index.d.ts +2 -0
- package/dist/smart-upload/index.js +800 -0
- package/index.html +16 -0
- package/package.json +23 -0
- package/public/favicon.svg +6 -0
- package/scripts/components.vite.config.ts +96 -0
- package/scripts/shared.ts +9 -0
- package/src/App.vue +28 -0
- package/src/components/Logo/index.vue +15 -0
- package/src/components-private/.gitkeep +0 -0
- package/src/composables/useElementStyle.ts +23 -0
- package/src/composables/useNaiveStyle.ts +43 -0
- package/src/composables/useNaiveTheme.ts +71 -0
- package/src/composables/useSmart.ts +36 -0
- package/src/layouts/default.vue +3 -0
- package/src/main.ts +33 -0
- package/src/modules/pinia/index.ts +8 -0
- package/src/modules/progress/index.ts +12 -0
- package/src/modules/router/install.ts +9 -0
- package/src/modules/router/routes.ts +40 -0
- package/src/pages/[...all].vue +21 -0
- package/src/pages/frame/component/[name].vue +14 -0
- package/src/pages/frame/index.vue +81 -0
- package/src/pages/index/composables/useTabsManage.ts +46 -0
- package/src/pages/index/index.vue +111 -0
- package/src/pages/index/type.ts +13 -0
- package/src/pages/index/utils/index.ts +41 -0
- package/src/settings.ts +9 -0
- package/src/shared/components.ts +52 -0
- package/src/shared/env.ts +11 -0
- package/src/shared/unocss.theme.ts +1600 -0
- package/src/stores/theme.ts +29 -0
- package/src/styles/element.scss +3 -0
- package/src/styles/styles.scss +21 -0
- package/src/types.ts +20 -0
- package/src/utils/callCustomElementExposed.ts +6 -0
- package/src/utils/deepCloneESModule.ts +10 -0
- package/src/utils/defineCustomElements.ts +18 -0
- package/src/utils/formatComponentsGlob.ts +16 -0
- package/src/utils/getFileMD5.ts +31 -0
- package/src/utils/getFileNameAndExt.ts +11 -0
- package/src/utils/isFileEqual.ts +13 -0
- package/src/utils/jsonToFormData.ts +8 -0
- package/src/web-components/smart-docx-drive-page/App.vue +37 -0
- package/src/web-components/smart-docx-drive-page/apis/doc.ts +85 -0
- package/src/web-components/smart-docx-drive-page/apis/file.ts +278 -0
- package/src/web-components/smart-docx-drive-page/apis/folder.ts +72 -0
- package/src/web-components/smart-docx-drive-page/children/Home.vue +8 -0
- package/src/web-components/smart-docx-drive-page/children/Me.vue +47 -0
- package/src/web-components/smart-docx-drive-page/components/CustomImage.vue +26 -0
- package/src/web-components/smart-docx-drive-page/components/CustomPopover.vue +62 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDir.vue +99 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDoc.vue +132 -0
- package/src/web-components/smart-docx-drive-page/components/DocxDownloadPopoverItem.vue +41 -0
- package/src/web-components/smart-docx-drive-page/components/DocxFileList.vue +156 -0
- package/src/web-components/smart-docx-drive-page/components/DocxPreview.vue +33 -0
- package/src/web-components/smart-docx-drive-page/components/DocxUpload.vue +164 -0
- package/src/web-components/smart-docx-drive-page/components/FileIcon.vue +62 -0
- package/src/web-components/smart-docx-drive-page/components-private/Header.vue +65 -0
- package/src/web-components/smart-docx-drive-page/components-private/Logo.vue +15 -0
- package/src/web-components/smart-docx-drive-page/components-private/Menu.vue +34 -0
- package/src/web-components/smart-docx-drive-page/components-private/Navbar.vue +36 -0
- package/src/web-components/smart-docx-drive-page/composables/useFullscreenElDialog.ts +41 -0
- package/src/web-components/smart-docx-drive-page/composables/usePrompt.ts +73 -0
- package/src/web-components/smart-docx-drive-page/data.ts +10 -0
- package/src/web-components/smart-docx-drive-page/external-style/custom-popover.sass +8 -0
- package/src/web-components/smart-docx-drive-page/external-style/index.sass +1 -0
- package/src/web-components/smart-docx-drive-page/index.ts +20 -0
- package/src/web-components/smart-docx-drive-page/index.vue +39 -0
- package/src/web-components/smart-docx-drive-page/info.ts +2 -0
- package/src/web-components/smart-docx-drive-page/stores/menu.ts +60 -0
- package/src/web-components/smart-docx-drive-page/types.ts +51 -0
- package/src/web-components/smart-docx-drive-page/utils/file-actions.ts +63 -0
- package/src/web-components/smart-docx-drive-page/utils/file.ts +31 -0
- package/src/web-components/smart-docx-editor/App.vue +32 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Markdown.vue +202 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/Menu.vue +100 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components/types.ts +6 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/Markdown.tsx +71 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/MarkdownElement.tsx +81 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.sass +6 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Blockquote/index.tsx +12 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.sass +14 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/Heading/index.tsx +17 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.scss +16 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/elements/List/index.tsx +39 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/components-react/types/custom-types.d.ts +69 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/composables/useTextSelection.ts +50 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.sass +19 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/index.vue +21 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/shared/const.ts +23 -0
- package/src/web-components/smart-docx-editor/MarkdownShortcuts/utils/slateHelpers.ts +23 -0
- package/src/web-components/smart-docx-editor/data.ts +38 -0
- package/src/web-components/smart-docx-editor/demo.vue +11 -0
- package/src/web-components/smart-docx-editor/index.md +3 -0
- package/src/web-components/smart-docx-editor/index.ts +5 -0
- package/src/web-components/smart-docx-editor/index.vue +12 -0
- package/src/web-components/smart-docx-editor/info.ts +2 -0
- package/src/web-components/smart-file-preview/category/Code.vue +171 -0
- package/src/web-components/smart-file-preview/category/Image.vue +49 -0
- package/src/web-components/smart-file-preview/category/Pdf.vue +14 -0
- package/src/web-components/smart-file-preview/category/Video.vue +27 -0
- package/src/web-components/smart-file-preview/demo.vue +34 -0
- package/src/web-components/smart-file-preview/index.md +5 -0
- package/src/web-components/smart-file-preview/index.ts +29 -0
- package/src/web-components/smart-file-preview/index.vue +56 -0
- package/src/web-components/smart-file-preview/info.ts +2 -0
- package/src/web-components/smart-file-preview/shared/const.ts +4 -0
- package/src/web-components/smart-file-preview/types.ts +38 -0
- package/src/web-components/smart-upload/index.ts +5 -0
- package/src/web-components/smart-upload/index.vue +101 -0
- package/src/web-components/smart-upload/info.ts +2 -0
- package/src/web-components/smart-upload/types.ts +28 -0
- package/tsconfig.json +15 -0
- package/types/auto-imports.d.ts +975 -0
- package/types/components.d.ts +14 -0
- package/types/env.d.ts +8 -0
- package/types/shims.d.ts +6 -0
- package/unocss.config.ts +23 -0
- package/vite.config.ts +60 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BasicColorSchema } from '@vueuse/core';
|
|
2
|
+
import { defineStore } from 'pinia';
|
|
3
|
+
|
|
4
|
+
export const useThemeStore = defineStore('theme', () => {
|
|
5
|
+
/** 主题模式状态 */
|
|
6
|
+
const mode = useColorMode<BasicColorSchema>({
|
|
7
|
+
storageKey: 'st-color-scheme',
|
|
8
|
+
initialValue: 'light',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/** 主题切换 */
|
|
12
|
+
const { state, next } = useCycleList<BasicColorSchema>(['light', 'dark', 'auto'], {
|
|
13
|
+
initialValue: mode.store,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/** 是否是深色模式 */
|
|
17
|
+
const dark = computed({
|
|
18
|
+
get: () => mode.value === 'dark',
|
|
19
|
+
set: v => (mode.value = v ? 'dark' : 'light'),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
syncRef(mode.store, state);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
value: mode.store,
|
|
26
|
+
dark,
|
|
27
|
+
toggle: next,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
body {
|
|
2
|
+
@apply scrollbar scrollbar-rounded;
|
|
3
|
+
|
|
4
|
+
-moz-osx-font-smoothing: grayscale;
|
|
5
|
+
-webkit-font-smoothing: antialiased;
|
|
6
|
+
text-rendering: optimizeLegibility;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
a,
|
|
10
|
+
a:focus,
|
|
11
|
+
a:hover {
|
|
12
|
+
@apply cursor-pointer text-primary underline;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
a,
|
|
16
|
+
a:focus,
|
|
17
|
+
a:active,
|
|
18
|
+
div,
|
|
19
|
+
div:focus {
|
|
20
|
+
@apply outline-none;
|
|
21
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { App } from 'vue';
|
|
2
|
+
import type { Router } from 'vue-router';
|
|
3
|
+
|
|
4
|
+
interface UserModuleContext {
|
|
5
|
+
app: App<Element>
|
|
6
|
+
router: Router
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 用户模块定义方法
|
|
11
|
+
*/
|
|
12
|
+
export type UserModule = (ctx: UserModuleContext) => void;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 项目配置
|
|
16
|
+
*/
|
|
17
|
+
export interface Settings {
|
|
18
|
+
/** 项目名称 */
|
|
19
|
+
name: string
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineCustomElement } from 'vue';
|
|
2
|
+
import { isBrowser } from 'mixte';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 定义自定义组件
|
|
6
|
+
* @param tag 自定义组件标签名
|
|
7
|
+
* @param component Vue 组件对象
|
|
8
|
+
*/
|
|
9
|
+
export function defineCustomElements(tag: string, component: any) {
|
|
10
|
+
if (isBrowser && !customElements.get(tag)) {
|
|
11
|
+
customElements.define(
|
|
12
|
+
tag,
|
|
13
|
+
component.prototype?.connectedCallback
|
|
14
|
+
? component
|
|
15
|
+
: defineCustomElement(component),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式化导入文件的信息
|
|
3
|
+
*/
|
|
4
|
+
export function formatComponentsGlob(files: Record<string, any> | string[]) {
|
|
5
|
+
if (Array.isArray(files)) {
|
|
6
|
+
return Object.fromEntries(
|
|
7
|
+
files.map(path => [path.split('/').reverse()[1], path]),
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return Object.fromEntries(
|
|
12
|
+
Object.entries(files).map(([path, value]) => {
|
|
13
|
+
return [path.split('/').reverse()[1], value];
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import SparkMd5 from 'spark-md5';
|
|
2
|
+
|
|
3
|
+
const FileSlice = File.prototype.slice || (File.prototype as any).mozSlice || (File.prototype as any).webkitSlice;
|
|
4
|
+
const FileChunkSize = 1024 * 1024 * 2; // 2MB
|
|
5
|
+
|
|
6
|
+
export function getFileMD5(file: File) {
|
|
7
|
+
return new Promise<string>((resolve) => {
|
|
8
|
+
const chunks = Math.ceil(file.size / FileChunkSize);
|
|
9
|
+
const spark = new SparkMd5.ArrayBuffer();
|
|
10
|
+
const fileReader = new FileReader();
|
|
11
|
+
let currentChunk = 0;
|
|
12
|
+
|
|
13
|
+
fileReader.onload = function (e) {
|
|
14
|
+
spark.append(e.target!.result as ArrayBuffer); // Append array buffer
|
|
15
|
+
currentChunk++;
|
|
16
|
+
|
|
17
|
+
if (currentChunk < chunks)
|
|
18
|
+
loadNext();
|
|
19
|
+
else
|
|
20
|
+
resolve(spark.end());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function loadNext() {
|
|
24
|
+
const start = currentChunk * FileChunkSize;
|
|
25
|
+
const end = start + FileChunkSize >= file.size ? file.size : start + FileChunkSize;
|
|
26
|
+
fileReader.readAsArrayBuffer(FileSlice.call(file, start, end));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
loadNext();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取文件名和后缀名
|
|
3
|
+
*/
|
|
4
|
+
export function getFileNameAndExt(fileName: string) {
|
|
5
|
+
const name = fileName.split('.');
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
name: name.length > 1 ? name.slice(0, -1).join('.') : fileName,
|
|
9
|
+
ext: name.length > 1 ? name.reverse()[0].toLowerCase() : '',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 比较两个文件是否相等
|
|
3
|
+
* @param file 文件1
|
|
4
|
+
* @param file2 文件2
|
|
5
|
+
*/
|
|
6
|
+
export function isFileEqual(file: File, file2: File) {
|
|
7
|
+
if (file.name !== file2.name) return false;
|
|
8
|
+
if (file.size !== file2.size) return false;
|
|
9
|
+
if (file.type !== file2.type) return false;
|
|
10
|
+
if (file.lastModified !== file2.lastModified) return false;
|
|
11
|
+
if (file.webkitRelativePath !== file2.webkitRelativePath) return false;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
1. element plus 命名空间设置
|
|
3
|
+
2. 参数默认值处理
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<NConfigProvider :cls-prefix="classPrefix" :theme-overrides="commonOverrides" abstract>
|
|
8
|
+
<NMessageProvider>
|
|
9
|
+
<ElConfigProvider :locale="zhCn" namespace="smart">
|
|
10
|
+
<Index v-bind="props" />
|
|
11
|
+
</ElConfigProvider>
|
|
12
|
+
</NMessageProvider>
|
|
13
|
+
</NConfigProvider>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script lang="ts" setup>
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
import zhCn from 'element-plus/dist/locale/zh-cn';
|
|
19
|
+
import { NConfigProvider, NMessageProvider } from 'naive-ui';
|
|
20
|
+
import Index from './index.vue';
|
|
21
|
+
import { menuStore } from './stores/menu';
|
|
22
|
+
import type { SmartDocxDrivePageProps } from './types';
|
|
23
|
+
|
|
24
|
+
const props = defineProps<SmartDocxDrivePageProps>();
|
|
25
|
+
|
|
26
|
+
const { activeMenu } = menuStore();
|
|
27
|
+
|
|
28
|
+
const { classPrefix } = useSmart();
|
|
29
|
+
|
|
30
|
+
// 当前激活的菜单项, 默认为主页
|
|
31
|
+
syncRef(activeMenu, toRef(props, 'activeMenu'), {
|
|
32
|
+
direction: 'rtl',
|
|
33
|
+
transform: {
|
|
34
|
+
rtl: value => value || (import.meta.env.DEV ? 'me' : 'home'),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { UseRequestOptions } from '@mixte/use';
|
|
2
|
+
import type { Descendant } from 'slate';
|
|
3
|
+
import { getConfigProvider } from '@smartos-lib/core';
|
|
4
|
+
import type { MaybeRefOrGetter } from 'vue';
|
|
5
|
+
import type { ResponseData } from '@smartos-lib/types';
|
|
6
|
+
import type { CancelTokenSource } from 'axios';
|
|
7
|
+
import { menuStore } from '../stores/menu';
|
|
8
|
+
|
|
9
|
+
const { meActiveMenuInfo } = menuStore();
|
|
10
|
+
|
|
11
|
+
/** 创建在线文档接口传参 */
|
|
12
|
+
export interface CreateOnlineDocxParams {
|
|
13
|
+
/** 文档标题 */
|
|
14
|
+
fileName?: string
|
|
15
|
+
/** 文档内容 */
|
|
16
|
+
docContext?: {
|
|
17
|
+
value?: Descendant[]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 创建在线文档 */
|
|
22
|
+
export function createOnlineDocx(params?: CreateOnlineDocxParams, options?: UseRequestOptions) {
|
|
23
|
+
return useRequestReactive<{
|
|
24
|
+
data: ResponseData<string>
|
|
25
|
+
}>(
|
|
26
|
+
(overlapParams?: CreateOnlineDocxParams) => {
|
|
27
|
+
const docContext: NonNullable<CreateOnlineDocxParams['docContext']> = overlapParams?.docContext ?? params?.docContext ?? {};
|
|
28
|
+
docContext.value ??= [];
|
|
29
|
+
|
|
30
|
+
return getConfigProvider('request')!({
|
|
31
|
+
url: '/de/file/createOnlineDoc',
|
|
32
|
+
method: 'post',
|
|
33
|
+
data: Object.assign({ filePath: meActiveMenuInfo.value?.filePath ?? '/' }, params, overlapParams, {
|
|
34
|
+
docContext: JSON.stringify(docContext),
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
options,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 修改在线文档接口传参 */
|
|
43
|
+
export interface UpdateOnlineDocxParams extends Partial<CreateOnlineDocxParams> {
|
|
44
|
+
userFileId: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 修改在线文档 */
|
|
48
|
+
export function updateOnlineDocx(_params?: MaybeRefOrGetter<UpdateOnlineDocxParams>, options?: UseRequestOptions) {
|
|
49
|
+
let cancelToken: CancelTokenSource | undefined;
|
|
50
|
+
|
|
51
|
+
return useRequestReactive<{ data: string }>(
|
|
52
|
+
(_overlapParams?: MaybeRefOrGetter<UpdateOnlineDocxParams>) => {
|
|
53
|
+
const params = toValue(_params);
|
|
54
|
+
const overlapParams = toValue(_overlapParams);
|
|
55
|
+
|
|
56
|
+
const docContext: NonNullable<CreateOnlineDocxParams['docContext']> = overlapParams?.docContext ?? params?.docContext ?? {};
|
|
57
|
+
docContext.value ??= [];
|
|
58
|
+
|
|
59
|
+
cancelToken?.cancel();
|
|
60
|
+
cancelToken = getConfigProvider('request')!.CancelToken.source();
|
|
61
|
+
|
|
62
|
+
return getConfigProvider('request')!({
|
|
63
|
+
url: '/de/file/updateOnlineFile',
|
|
64
|
+
method: 'post',
|
|
65
|
+
data: Object.assign({}, params, overlapParams, {
|
|
66
|
+
docContext: JSON.stringify(docContext),
|
|
67
|
+
}),
|
|
68
|
+
cancelToken: cancelToken.token,
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
options,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** 获取在线文档 */
|
|
76
|
+
export function getOnlineDocx(params?: { userFileId: string }, options?: UseRequestOptions) {
|
|
77
|
+
return useRequestReactive<{ data: ResponseData<{ docContext: string }> }>(
|
|
78
|
+
(overlapParams?: { userFileId: string }) => getConfigProvider('request')!({
|
|
79
|
+
url: '/de/file/queryOnlineFile',
|
|
80
|
+
method: 'get',
|
|
81
|
+
params: Object.assign({}, params, overlapParams),
|
|
82
|
+
}),
|
|
83
|
+
options,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { ImageExtEnum, type ResponseData, type ResponseListData } from '@smartos-lib/types';
|
|
2
|
+
import type { UseRequestOptions } from '@mixte/use';
|
|
3
|
+
import { getConfigProvider } from '@smartos-lib/core';
|
|
4
|
+
import { deepMerge, isNumeric } from 'mixte';
|
|
5
|
+
import type { MaybeRefOrGetter } from 'vue';
|
|
6
|
+
import { pick } from 'lodash-es';
|
|
7
|
+
import type { CancelToken, CancelTokenSource } from 'axios';
|
|
8
|
+
import type { FileItem } from '../types';
|
|
9
|
+
import { menuStore } from '../stores/menu';
|
|
10
|
+
import { getFileMD5 } from '@/utils/getFileMD5';
|
|
11
|
+
import { jsonToFormData } from '@/utils/jsonToFormData';
|
|
12
|
+
|
|
13
|
+
const { meActiveMenuInfo } = menuStore();
|
|
14
|
+
|
|
15
|
+
/** 文件信息 */
|
|
16
|
+
export interface FileInfo {
|
|
17
|
+
/** 文件 ID */
|
|
18
|
+
fileId: string
|
|
19
|
+
/** 用户文件 ID */
|
|
20
|
+
userFileId: string
|
|
21
|
+
/** 文件所在路径 */
|
|
22
|
+
filePath: string
|
|
23
|
+
/** 文件名 */
|
|
24
|
+
fileName: string
|
|
25
|
+
/** 文件后缀 */
|
|
26
|
+
extendName: string
|
|
27
|
+
/** 文件大小 */
|
|
28
|
+
fileSize: number
|
|
29
|
+
/**
|
|
30
|
+
* 是否是文件夹
|
|
31
|
+
* - 0: 否 ( 是文件 )
|
|
32
|
+
* - 1: 是 ( 是文件夹 )
|
|
33
|
+
*/
|
|
34
|
+
isDir: 0 | 1
|
|
35
|
+
/**
|
|
36
|
+
* 文件类型
|
|
37
|
+
* - 1: 普通文件
|
|
38
|
+
* - 2: 在线文档
|
|
39
|
+
*/
|
|
40
|
+
fileType: 1 | 2
|
|
41
|
+
/** 所有者 */
|
|
42
|
+
userId: string
|
|
43
|
+
/** 上传时间 */
|
|
44
|
+
uploadTime: string
|
|
45
|
+
|
|
46
|
+
/** 文件名 + 文件后缀 - 扩展字段 */
|
|
47
|
+
fileFullName: string
|
|
48
|
+
/** 下载请求 - 扩展字段 */
|
|
49
|
+
download: ReturnType<typeof downloadFile>
|
|
50
|
+
/** 下载进度 - 扩展字段 */
|
|
51
|
+
downloadProgress: Ref<number>
|
|
52
|
+
/** 图片预览 - 扩展字段 */
|
|
53
|
+
imagePreview?: ReturnType<typeof getPreviewFile>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 上传文件
|
|
58
|
+
*/
|
|
59
|
+
export function uploadFile(fileItem: Ref<FileItem | undefined>) {
|
|
60
|
+
return useRequestReactive(async () => {
|
|
61
|
+
const axios = getConfigProvider('request')!;
|
|
62
|
+
|
|
63
|
+
fileItem.value!.isReading = true;
|
|
64
|
+
|
|
65
|
+
const file = fileItem.value!.file;
|
|
66
|
+
const data = {
|
|
67
|
+
identifier: await getFileMD5(file),
|
|
68
|
+
filename: file.name,
|
|
69
|
+
relativePath: file.webkitRelativePath || file.name,
|
|
70
|
+
totalSize: file.size,
|
|
71
|
+
filePath: meActiveMenuInfo.value?.filePath ?? '/',
|
|
72
|
+
// 分片
|
|
73
|
+
// chunkNumber: 1,
|
|
74
|
+
// totalChunks: 1,
|
|
75
|
+
// currentChunkSize: file.size,
|
|
76
|
+
// chunkSize: file.size + 1,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const quickUpload = await axios({ url: '/de/filetransfer/uploadfile', method: 'get', params: data });
|
|
80
|
+
|
|
81
|
+
fileItem.value!.isReading = false;
|
|
82
|
+
|
|
83
|
+
// 服务器已有该文件, 不需要上传
|
|
84
|
+
if (quickUpload.data.data.skipUpload) {
|
|
85
|
+
fileItem.value!.isUploadSuccess = true;
|
|
86
|
+
fileItem.value!.isQuickUpload = true;
|
|
87
|
+
fileItem.value!.progress = 100;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fileItem.value!.isUploading = true;
|
|
92
|
+
|
|
93
|
+
return axios({
|
|
94
|
+
url: '/de/filetransfer/uploadfile',
|
|
95
|
+
method: 'post',
|
|
96
|
+
data: jsonToFormData({ ...data, file }),
|
|
97
|
+
onUploadProgress: (progressEvent) => {
|
|
98
|
+
fileItem.value!.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total!);
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
.then(() => {
|
|
102
|
+
fileItem.value!.isUploading = false;
|
|
103
|
+
fileItem.value!.isUploadSuccess = true;
|
|
104
|
+
})
|
|
105
|
+
.catch(() => {
|
|
106
|
+
fileItem.value!.isUploading = false;
|
|
107
|
+
fileItem.value!.isUploadError = true;
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** 获取文件列表接口传参 */
|
|
113
|
+
export interface GetFileListParams {
|
|
114
|
+
/** 当前页码 @default 1 */
|
|
115
|
+
currentPage?: number
|
|
116
|
+
/** 每页条数 @default 10 */
|
|
117
|
+
pageCount?: number
|
|
118
|
+
/** 文件路径 @default '/' */
|
|
119
|
+
filePath?: string
|
|
120
|
+
/**
|
|
121
|
+
* 文件类型
|
|
122
|
+
* - 0: 全部
|
|
123
|
+
* - 1: 音乐
|
|
124
|
+
* - 2: 图片
|
|
125
|
+
* @default '0'
|
|
126
|
+
*/
|
|
127
|
+
fileType?: '0' | '1' | '2'
|
|
128
|
+
/**
|
|
129
|
+
* 是否是文件夹
|
|
130
|
+
* - 0: 否 ( 是文件 )
|
|
131
|
+
* - 1: 是 ( 是文件夹 )
|
|
132
|
+
*/
|
|
133
|
+
isDir?: 0 | 1
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 获取文件列表 ( 不包含文件夹 )
|
|
137
|
+
*/
|
|
138
|
+
export function getFileList(params?: MaybeRefOrGetter<GetFileListParams>, options?: UseRequestOptions) {
|
|
139
|
+
const result = useRequestReactive<{
|
|
140
|
+
data: ResponseData<ResponseListData<FileInfo>>
|
|
141
|
+
}>(
|
|
142
|
+
(overlapParams?: MaybeRefOrGetter<GetFileListParams>) => {
|
|
143
|
+
return getConfigProvider('request')!({
|
|
144
|
+
url: '/de/file/getFileList',
|
|
145
|
+
method: 'get',
|
|
146
|
+
params: deepMerge({ currentPage: 1, pageCount: 1000, filePath: '/', fileType: '0' }, toValue(params), toValue(overlapParams), { isDir: 0 }),
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
options,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
result.onSuccess(() => {
|
|
153
|
+
if (!result.data?.data.records.length) return;
|
|
154
|
+
|
|
155
|
+
// 字段格式化
|
|
156
|
+
result.data.data.records.forEach((row) => {
|
|
157
|
+
row.fileSize = isNumeric(row.fileSize) ? Number(row.fileSize) : row.fileSize;
|
|
158
|
+
row.fileFullName = `${row.fileName ?? ''}${row.extendName ? `.${row.extendName}` : ''}`;
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// 写入预览相关
|
|
162
|
+
result.data.data.records.forEach((row) => {
|
|
163
|
+
if (ImageExtEnum.includes(row.extendName)) {
|
|
164
|
+
row.imagePreview = getPreviewFile({ userFileId: row.userFileId, isMin: true });
|
|
165
|
+
row.imagePreview.execute();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// 写入下载相关
|
|
170
|
+
result.data.data.records.forEach((row) => {
|
|
171
|
+
const progress = ref<number>(0);
|
|
172
|
+
const download = downloadFile(() => pick(row, ['userFileId']), { progress });
|
|
173
|
+
|
|
174
|
+
row.downloadProgress = progress;
|
|
175
|
+
row.download = download;
|
|
176
|
+
|
|
177
|
+
download.onSuccess(() => {
|
|
178
|
+
const url = URL.createObjectURL(download.data!);
|
|
179
|
+
const a = document.createElement('a');
|
|
180
|
+
a.href = url;
|
|
181
|
+
a.download = `${row.fileFullName}`;
|
|
182
|
+
a.setAttribute('target', '_blank');
|
|
183
|
+
a.click();
|
|
184
|
+
URL.revokeObjectURL(url);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** 获取预览文件接口传参 */
|
|
193
|
+
export interface GetPreviewFileParams {
|
|
194
|
+
/** 文件 ID */
|
|
195
|
+
userFileId: string
|
|
196
|
+
/** 是否是小尺寸图片 */
|
|
197
|
+
isMin?: boolean
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 获取预览文件
|
|
201
|
+
*/
|
|
202
|
+
export function getPreviewFile(params?: MaybeRefOrGetter<GetPreviewFileParams>, options?: UseRequestOptions) {
|
|
203
|
+
return useRequestReactive<ResponseData<Blob>>(
|
|
204
|
+
(overlapParams?: MaybeRefOrGetter<GetPreviewFileParams>) => {
|
|
205
|
+
return getConfigProvider('request')!({
|
|
206
|
+
url: '/de/filetransfer/preview',
|
|
207
|
+
method: 'get',
|
|
208
|
+
params: deepMerge({}, toValue(params), toValue(overlapParams)),
|
|
209
|
+
responseType: 'blob',
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
options,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** 获取预览文件接口选项 */
|
|
217
|
+
export interface DownloadFileOptions {
|
|
218
|
+
/** 下载进度 */
|
|
219
|
+
progress?: Ref<number>
|
|
220
|
+
/** 取消请求 */
|
|
221
|
+
cancelToken?: CancelToken
|
|
222
|
+
}
|
|
223
|
+
/** 下载文件 */
|
|
224
|
+
export function downloadFile(params?: MaybeRefOrGetter<{ userFileId: string }>, options?: DownloadFileOptions, requestOptions?: UseRequestOptions) {
|
|
225
|
+
return useRequestReactive<ResponseData<Blob>>(
|
|
226
|
+
(overlapParams?: MaybeRefOrGetter<{ userFileId: string }>, overlapOptions?: DownloadFileOptions) => {
|
|
227
|
+
const progress = overlapOptions?.progress ?? options?.progress;
|
|
228
|
+
const cancelToken = overlapOptions?.cancelToken ?? options?.cancelToken;
|
|
229
|
+
|
|
230
|
+
return getConfigProvider('request')!({
|
|
231
|
+
url: '/de/filetransfer/downloadfile',
|
|
232
|
+
method: 'get',
|
|
233
|
+
params: deepMerge({}, toValue(params), toValue(overlapParams)),
|
|
234
|
+
responseType: 'blob',
|
|
235
|
+
cancelToken,
|
|
236
|
+
onDownloadProgress: (progressEvent) => {
|
|
237
|
+
if (progress)
|
|
238
|
+
progress.value = Math.round((progressEvent.loaded * 100) / progressEvent.total!);
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
requestOptions,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** 重命名文件 */
|
|
247
|
+
export function renameFile(params?: MaybeRefOrGetter<{ userFileId: string; fileName: string }>, options?: UseRequestOptions) {
|
|
248
|
+
let cancelToken: CancelTokenSource | undefined;
|
|
249
|
+
|
|
250
|
+
return useRequestReactive<ResponseData>(
|
|
251
|
+
(overlapParams?: MaybeRefOrGetter<{ userFileId: string; fileName: string }>) => {
|
|
252
|
+
cancelToken?.cancel();
|
|
253
|
+
cancelToken = getConfigProvider('request')!.CancelToken.source();
|
|
254
|
+
|
|
255
|
+
return getConfigProvider('request')!({
|
|
256
|
+
url: '/de/file/renamefile',
|
|
257
|
+
method: 'post',
|
|
258
|
+
data: deepMerge({}, toValue(params), toValue(overlapParams)),
|
|
259
|
+
cancelToken: cancelToken.token,
|
|
260
|
+
});
|
|
261
|
+
},
|
|
262
|
+
options,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** 删除文件 */
|
|
267
|
+
export function deleteFile(params?: MaybeRefOrGetter<{ userFileId: string }>, options?: UseRequestOptions) {
|
|
268
|
+
return useRequestReactive<ResponseData>(
|
|
269
|
+
(overlapParams?: MaybeRefOrGetter<{ userFileId: string }>) => {
|
|
270
|
+
return getConfigProvider('request')!({
|
|
271
|
+
url: '/de/file/deletefile',
|
|
272
|
+
method: 'post',
|
|
273
|
+
data: deepMerge({}, toValue(params), toValue(overlapParams)),
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
options,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { UseRequestOptions } from '@mixte/use';
|
|
2
|
+
import type { ResponseData, ResponseListData } from '@smartos-lib/types';
|
|
3
|
+
import { getConfigProvider } from '@smartos-lib/core';
|
|
4
|
+
import { deepMerge } from 'mixte';
|
|
5
|
+
import type { MaybeRefOrGetter } from 'vue';
|
|
6
|
+
import { menuStore } from '../stores/menu';
|
|
7
|
+
import type { FileInfo, GetFileListParams } from './file';
|
|
8
|
+
|
|
9
|
+
let meActiveMenuInfo: ReturnType<typeof menuStore>['meActiveMenuInfo'];
|
|
10
|
+
|
|
11
|
+
// 有循环引用的问题, 延迟再获取
|
|
12
|
+
Promise.resolve().then(() => {
|
|
13
|
+
meActiveMenuInfo = menuStore().meActiveMenuInfo;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/** 文件夹信息 */
|
|
17
|
+
export interface DirInfo {
|
|
18
|
+
/** 文件夹 ID */
|
|
19
|
+
id: string
|
|
20
|
+
/** 文件夹名称 */
|
|
21
|
+
label: string
|
|
22
|
+
/** 文件夹路径 */
|
|
23
|
+
filePath: string
|
|
24
|
+
/** 子文件夹 */
|
|
25
|
+
children: DirInfo[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 获取目录树 */
|
|
29
|
+
export function getDirTree(options?: UseRequestOptions) {
|
|
30
|
+
return useRequestReactive<{
|
|
31
|
+
data: ResponseData<DirInfo>
|
|
32
|
+
}>(
|
|
33
|
+
() => getConfigProvider('request')!({ url: '/de/file/getfiletree', method: 'get' }),
|
|
34
|
+
options,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 获取文件夹列表 ( 不包含文件 )
|
|
40
|
+
*/
|
|
41
|
+
export function getFolderList(params?: MaybeRefOrGetter<GetFileListParams>, options?: UseRequestOptions) {
|
|
42
|
+
return useRequestReactive<{
|
|
43
|
+
data: ResponseData<ResponseListData<FileInfo>>
|
|
44
|
+
}>(
|
|
45
|
+
(overlapParams?: MaybeRefOrGetter<GetFileListParams>) => {
|
|
46
|
+
return getConfigProvider('request')!({
|
|
47
|
+
url: '/de/file/getFileList',
|
|
48
|
+
method: 'get',
|
|
49
|
+
params: deepMerge({ currentPage: 1, pageCount: 50, filePath: '/', fileType: '0' }, toValue(params), toValue(overlapParams), { isDir: 1 }),
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
options,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 创建文件夹 */
|
|
57
|
+
export function createDir(params?: { fileName: string }, options?: UseRequestOptions) {
|
|
58
|
+
return useRequestReactive<{
|
|
59
|
+
data: ResponseData<DirInfo>
|
|
60
|
+
}>(
|
|
61
|
+
(overlapParams?: { fileName: string }) => getConfigProvider('request')!({
|
|
62
|
+
url: '/de/file/createFold',
|
|
63
|
+
method: 'post',
|
|
64
|
+
data: deepMerge(
|
|
65
|
+
{ filePath: meActiveMenuInfo.value?.filePath ?? '/' },
|
|
66
|
+
toValue(params),
|
|
67
|
+
toValue(overlapParams),
|
|
68
|
+
),
|
|
69
|
+
}),
|
|
70
|
+
options,
|
|
71
|
+
);
|
|
72
|
+
}
|