diff --git a/package.json b/package.json
index 4a2f879..0b685b4 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
"@types/d3": "^7.4.3",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.7.4",
+ "@types/path-browserify": "^1.0.3",
"@types/react": "^18.3.10",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
@@ -57,7 +58,9 @@
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.12",
"globals": "^15.9.0",
+ "path-browserify": "^1.0.1",
"postcss-import": "^16.1.0",
+ "pretty-bytes": "^6.1.1",
"react-is": "^18.3.1",
"tailwind-merge": "^2.5.2",
"tailwindcss": "^3.4.13",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c3e6a9..cf3cd35 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -114,6 +114,12 @@ importers:
'@types/node':
specifier: ^22.7.4
version: 22.7.4
+ '@types/path-browserify':
+ specifier: ^1.0.3
+ version: 1.0.3
+ '@types/pretty-bytes':
+ specifier: ^5.2.0
+ version: 5.2.0
'@types/react':
specifier: ^18.3.10
version: 18.3.10
@@ -138,9 +144,15 @@ importers:
globals:
specifier: ^15.9.0
version: 15.9.0
+ path-browserify:
+ specifier: ^1.0.1
+ version: 1.0.1
postcss-import:
specifier: ^16.1.0
version: 16.1.0(postcss@8.4.47)
+ pretty-bytes:
+ specifier: ^6.1.1
+ version: 6.1.1
react-is:
specifier: ^18.3.1
version: 18.3.1
@@ -907,6 +919,13 @@ packages:
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
+ '@types/path-browserify@1.0.3':
+ resolution: {integrity: sha512-ZmHivEbNCBtAfcrFeBCiTjdIc2dey0l7oCGNGpSuRTy8jP6UVND7oUowlvDujBy8r2Hoa8bfFUOCiPWfmtkfxw==}
+
+ '@types/pretty-bytes@5.2.0':
+ resolution: {integrity: sha512-dJhMFphDp6CE+OAZVyqzha9KsmgeqRMbZN4dIbMSrfObiuzfjucwKdn6zu+ttrjMwmz+Vz71/xXgHx5pO0axhA==}
+ deprecated: This is a stub types definition. pretty-bytes provides its own type definitions, so you do not need this installed.
+
'@types/prismjs@1.26.4':
resolution: {integrity: sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==}
@@ -1867,6 +1886,9 @@ packages:
parse5@7.1.2:
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+ path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -1956,6 +1978,10 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
+ pretty-bytes@6.1.1:
+ resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
+ engines: {node: ^14.13.1 || >=16.0.0}
+
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
@@ -3395,6 +3421,12 @@ snapshots:
'@types/parse-json@4.0.2': {}
+ '@types/path-browserify@1.0.3': {}
+
+ '@types/pretty-bytes@5.2.0':
+ dependencies:
+ pretty-bytes: 6.1.1
+
'@types/prismjs@1.26.4': {}
'@types/prop-types@15.7.13': {}
@@ -4490,6 +4522,8 @@ snapshots:
dependencies:
entities: 4.5.0
+ path-browserify@1.0.1: {}
+
path-exists@4.0.0: {}
path-key@3.1.1: {}
@@ -4562,6 +4596,8 @@ snapshots:
prelude-ls@1.2.1: {}
+ pretty-bytes@6.1.1: {}
+
property-information@6.5.0: {}
punycode@2.3.1: {}
diff --git a/src/App.tsx b/src/App.tsx
index 23f563a..8da84c5 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -10,6 +10,8 @@ import { App as AiAgentApp } from './pages/ai-agent';
import { App as UserApp } from './pages/user';
import { App as ChatApp } from './pages/chat-manager';
import { App as GitHubApp } from './pages/github';
+import { App as UserAppApp } from './pages/app';
+import { App as FileApp } from './pages/file';
import '@abearxiong/container/dist/container.css';
@@ -33,6 +35,9 @@ export const App = () => {
} />
} />
} />
+ } />
+ } />
+
404} />
404} />
diff --git a/src/pages/app/edit/AppVersionList.tsx b/src/pages/app/edit/AppVersionList.tsx
new file mode 100644
index 0000000..ad99e19
--- /dev/null
+++ b/src/pages/app/edit/AppVersionList.tsx
@@ -0,0 +1,153 @@
+import { useParams } from 'react-router';
+import { useAppVersionStore } from '../store';
+import { useShallow } from 'zustand/react/shallow';
+import { useEffect } from 'react';
+import { Button, Form, Input, Modal } from 'antd';
+import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
+import { isObjectNull } from '@/utils/is-null';
+import { useNavigate } from 'react-router';
+import { FileUpload } from '../modules/FileUpload';
+const FormModal = () => {
+ const [form] = Form.useForm();
+ const containerStore = useAppVersionStore(
+ useShallow((state) => {
+ return {
+ showEdit: state.showEdit,
+ setShowEdit: state.setShowEdit,
+ formData: state.formData,
+ updateData: state.updateData,
+ };
+ }),
+ );
+ useEffect(() => {
+ const open = containerStore.showEdit;
+ if (open) {
+ if (open) {
+ const isNull = isObjectNull(containerStore.formData);
+ if (isNull) {
+ form.setFieldsValue({});
+ } else form.setFieldsValue(containerStore.formData);
+ }
+ }
+ }, [containerStore.showEdit]);
+ const onFinish = async (values: any) => {
+ containerStore.updateData(values);
+ };
+ const onClose = () => {
+ containerStore.setShowEdit(false);
+ form.resetFields();
+ };
+ const isEdit = containerStore.formData.id;
+ return (
+ containerStore.setShowEdit(false)}
+ destroyOnClose
+ footer={false}
+ width={800}
+ onCancel={onClose}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const AppVersionList = () => {
+ const params = useParams();
+ const appKey = params.appKey;
+ const versionStore = useAppVersionStore(
+ useShallow((state) => {
+ return {
+ list: state.list,
+ getList: state.getList,
+ setKey: state.setKey,
+ setShowEdit: state.setShowEdit,
+ setFormData: state.setFormData,
+ deleteData: state.deleteData,
+ };
+ }),
+ );
+ useEffect(() => {
+ // fetch app version list
+ if (appKey) {
+ versionStore.setKey(appKey);
+ versionStore.getList();
+ }
+ }, []);
+ return (
+
+
+
+
+
+
+
+
+
+
+ {versionStore.list.map((item, index) => {
+ return (
+
+
{item.version}
+
+
+
+
+
+
+ );
+ })}
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/app/edit/List.tsx b/src/pages/app/edit/List.tsx
new file mode 100644
index 0000000..aa41c79
--- /dev/null
+++ b/src/pages/app/edit/List.tsx
@@ -0,0 +1,129 @@
+import { useShallow } from 'zustand/react/shallow';
+import { useUserAppStore } from '../store';
+import { useEffect } from 'react';
+import { Button, Form, Input, Modal } from 'antd';
+import { PlusOutlined } from '@ant-design/icons';
+import { isObjectNull } from '@/utils/is-null';
+import { useNavigate } from 'react-router';
+import { FileUpload } from '../modules/FileUpload';
+const FormModal = () => {
+ const [form] = Form.useForm();
+ const containerStore = useUserAppStore(
+ useShallow((state) => {
+ return {
+ showEdit: state.showEdit,
+ setShowEdit: state.setShowEdit,
+ formData: state.formData,
+ updateData: state.updateData,
+ };
+ }),
+ );
+ useEffect(() => {
+ const open = containerStore.showEdit;
+ if (open) {
+ if (open) {
+ const isNull = isObjectNull(containerStore.formData);
+ if (isNull) {
+ form.setFieldsValue({});
+ } else form.setFieldsValue(containerStore.formData);
+ }
+ }
+ }, [containerStore.showEdit]);
+ const onFinish = async (values: any) => {
+ containerStore.updateData(values);
+ };
+ const onClose = () => {
+ containerStore.setShowEdit(false);
+ form.resetFields();
+ };
+ const isEdit = containerStore.formData.id;
+ return (
+ containerStore.setShowEdit(false)}
+ destroyOnClose
+ footer={false}
+ width={800}
+ onCancel={onClose}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Submit
+
+
+ Cancel
+
+
+
+
+ );
+};
+
+export const List = () => {
+ const userAppStore = useUserAppStore(
+ useShallow((state) => {
+ return {
+ list: state.list,
+ getList: state.getList,
+ setShowEdit: state.setShowEdit,
+ };
+ }),
+ );
+ const navicate = useNavigate();
+ useEffect(() => {
+ userAppStore.getList();
+ }, []);
+ return (
+
+
+
{
+ userAppStore.setShowEdit(true);
+ }}
+ icon={}>
+
+
+
+
+
+ {userAppStore.list.map((item) => {
+ return (
+
{
+ navicate(`/app/${item.key}/verison/list`);
+ }}>
+
{item.title}
+
+ );
+ })}
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/app/index.tsx b/src/pages/app/index.tsx
new file mode 100644
index 0000000..a2e7a2e
--- /dev/null
+++ b/src/pages/app/index.tsx
@@ -0,0 +1,15 @@
+import { Navigate, Route, Routes } from 'react-router-dom';
+import { Main } from './layouts';
+import { List } from './edit/List';
+import { AppVersionList } from './edit/AppVersionList';
+export const App = () => {
+ return (
+
+ }>
+ }>
+ } />
+ } />
+
+
+ );
+};
diff --git a/src/pages/app/layouts/index.tsx b/src/pages/app/layouts/index.tsx
new file mode 100644
index 0000000..acd878c
--- /dev/null
+++ b/src/pages/app/layouts/index.tsx
@@ -0,0 +1,5 @@
+import { LayoutMain } from '@/modules/layout';
+
+export const Main = () => {
+ return ;
+};
diff --git a/src/pages/app/modules/FileUpload.tsx b/src/pages/app/modules/FileUpload.tsx
new file mode 100644
index 0000000..d16543a
--- /dev/null
+++ b/src/pages/app/modules/FileUpload.tsx
@@ -0,0 +1,56 @@
+export type FileType = {
+ name: string;
+ size: number;
+ lastModified: number;
+ webkitRelativePath: string; // 包含name
+};
+
+export const FileUpload = () => {
+ const onChange = async (e) => {
+ console.log(e.target.files);
+ // webkitRelativePath
+ let files = Array.from(e.target.files) as any[];
+ console.log(files);
+ // 过滤 文件 .DS_Store
+ files = files.filter((file) => {
+ if (file.webkitRelativePath.startsWith('__MACOSX')) {
+ return false;
+ }
+ return !file.name.startsWith('.');
+ });
+ if (files.length === 0) {
+ console.log('no files');
+ return;
+ }
+ const root = files[0].webkitRelativePath.split('/')[0];
+ const formData = new FormData();
+ files.forEach((file) => {
+ // relativePath 去除第一级
+ const webkitRelativePath = file.webkitRelativePath.replace(root + '/', '');
+ formData.append('file', file, webkitRelativePath); // 保留文件夹路径
+ });
+ formData.append('appKey','codeflow');
+ formData.append('version', '0.0.2');
+ const res = await fetch('/api/app/upload', {
+ method: 'POST',
+ body: formData,//
+ headers: {
+ Authorization: 'Bearer ' + localStorage.getItem('token'),
+ },
+ });
+ console.log(res);
+ };
+
+ return (
+
+ 文件上传:
+
+
+ );
+};
diff --git a/src/pages/app/store/app-version.ts b/src/pages/app/store/app-version.ts
new file mode 100644
index 0000000..62252b3
--- /dev/null
+++ b/src/pages/app/store/app-version.ts
@@ -0,0 +1,78 @@
+import { create } from 'zustand';
+import { query } from '@/modules';
+import { message } from 'antd';
+
+type AppVersionStore = {
+ showEdit: boolean;
+ setShowEdit: (showEdit: boolean) => void;
+ formData: any;
+ setFormData: (formData: any) => void;
+ loading: boolean;
+ setLoading: (loading: boolean) => void;
+ key: string;
+ setKey: (key: string) => void;
+ list: any[];
+ getList: () => Promise;
+ updateData: (data: any) => Promise;
+ deleteData: (id: string) => Promise;
+};
+export const useAppVersionStore = create((set, get) => {
+ return {
+ showEdit: false,
+ setShowEdit: (showEdit) => set({ showEdit }),
+ formData: {},
+ setFormData: (formData) => set({ formData }),
+ loading: false,
+ setLoading: (loading) => set({ loading }),
+ key: '',
+ setKey: (key) => set({ key }),
+ list: [],
+ getList: async () => {
+ set({ loading: true });
+ const key = get().key;
+
+ const res = await query.post({
+ path: 'app',
+ key: 'list',
+ data: {
+ key,
+ },
+ });
+ set({ loading: false });
+ if (res.code === 200) {
+ set({ list: res.data });
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ updateData: async (data) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'app',
+ key: 'update',
+ data,
+ });
+ if (res.code === 200) {
+ message.success('Success');
+ set({ showEdit: false, formData: res.data });
+ getList();
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ deleteData: async (id) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'app',
+ key: 'delete',
+ id,
+ });
+ if (res.code === 200) {
+ getList();
+ message.success('Success');
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ };
+});
diff --git a/src/pages/app/store/index.ts b/src/pages/app/store/index.ts
new file mode 100644
index 0000000..866e600
--- /dev/null
+++ b/src/pages/app/store/index.ts
@@ -0,0 +1,2 @@
+export * from './user-app';
+export * from './app-version';
diff --git a/src/pages/app/store/user-app.ts b/src/pages/app/store/user-app.ts
new file mode 100644
index 0000000..20b8ab3
--- /dev/null
+++ b/src/pages/app/store/user-app.ts
@@ -0,0 +1,69 @@
+import { create } from 'zustand';
+import { query } from '@/modules';
+import { message } from 'antd';
+type UserAppStore = {
+ showEdit: boolean;
+ setShowEdit: (showEdit: boolean) => void;
+ formData: any;
+ setFormData: (formData: any) => void;
+ loading: boolean;
+ setLoading: (loading: boolean) => void;
+ list: any[];
+ getList: () => Promise;
+ updateData: (data: any) => Promise;
+ deleteData: (id: string) => Promise;
+};
+export const useUserAppStore = create((set, get) => {
+ return {
+ showEdit: false,
+ setShowEdit: (showEdit) => set({ showEdit }),
+ formData: {},
+ setFormData: (formData) => set({ formData }),
+ loading: false,
+ setLoading: (loading) => set({ loading }),
+ list: [],
+ getList: async () => {
+ set({ loading: true });
+
+ const res = await query.post({
+ path: 'user-app',
+ key: 'list',
+ });
+ set({ loading: false });
+ if (res.code === 200) {
+ set({ list: res.data });
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ updateData: async (data) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'user-app',
+ key: 'update',
+ data,
+ });
+ if (res.code === 200) {
+ message.success('Success');
+ set({ showEdit: false, formData: res.data });
+ getList();
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ deleteData: async (id) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'user-app',
+ key: 'delete',
+ id,
+ });
+ if (res.code === 200) {
+ getList();
+ message.success('Success');
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ };
+});
diff --git a/src/pages/file/edit/List.tsx b/src/pages/file/edit/List.tsx
new file mode 100644
index 0000000..d4d6f65
--- /dev/null
+++ b/src/pages/file/edit/List.tsx
@@ -0,0 +1,122 @@
+import { useShallow } from 'zustand/react/shallow';
+import { useFileStore } from '../store';
+import { useEffect } from 'react';
+import path from 'path-browserify';
+import prettyBytes from 'pretty-bytes';
+import clsx from 'clsx';
+import { isObjectNull } from '@/utils/is-null';
+export const CardPath = ({ children }: any) => {
+ const userAppStore = useFileStore(
+ useShallow((state) => {
+ return {
+ list: state.list,
+ getList: state.getList,
+ setPath: state.setPath,
+ path: state.path,
+ };
+ }),
+ );
+ const paths = ['root', ...userAppStore.path.split('/').filter((item) => item)];
+ const onDirectoryClick = (prefix: string) => {
+ if (prefix === 'root') {
+ userAppStore.setPath('');
+ userAppStore.getList();
+ return;
+ }
+ userAppStore.setPath(prefix.replace('root/', '') + '/');
+ userAppStore.getList();
+ };
+ return (
+
+
+
+
+
Path:
+
+ {paths.map((item, index) => {
+ const isLast = index === paths.length - 1;
+ return (
+
{
+ if (!isLast) {
+ onDirectoryClick(paths.slice(0, index + 1).join('/'));
+ }
+ }}>
+ {item}/
+
+ );
+ })}
+
+
+
+
+
{children}
+
+ );
+};
+export const List = () => {
+ const userAppStore = useFileStore(
+ useShallow((state) => {
+ return {
+ list: state.list,
+ getList: state.getList,
+ setPath: state.setPath,
+ path: state.path,
+ getFile: state.getFile,
+ file: state.file,
+ };
+ }),
+ );
+ useEffect(() => {
+ userAppStore.getList();
+ }, []);
+ const onDirectoryClick = (prefix: string) => {
+ userAppStore.setPath(prefix);
+ userAppStore.getList();
+ };
+ return (
+
+
+
+
+ {userAppStore.list.map((item, index) => {
+ if (item.prefix) {
+ let showPrefix = item.prefix.replace(userAppStore.path, '');
+ showPrefix = showPrefix.replace('/', '');
+ return (
+
{
+ onDirectoryClick(item.prefix);
+ }}>
+
Directory:
+
{showPrefix}
+
+ );
+ }
+ const name = path.basename(item.name);
+ const size = prettyBytes(item.size);
+ return (
+
{
+ userAppStore.getFile(item.name);
+ }}>
+
{name}
+
size: {size}
+
+ );
+ })}
+
+
+
+
{!isObjectNull(userAppStore.file) && JSON.stringify(userAppStore.file, null, 2)}
+
+
+
+ );
+};
diff --git a/src/pages/file/index.tsx b/src/pages/file/index.tsx
new file mode 100644
index 0000000..9dad8a7
--- /dev/null
+++ b/src/pages/file/index.tsx
@@ -0,0 +1,13 @@
+import { Navigate, Route, Routes } from 'react-router-dom';
+import { Main } from './layouts';
+import { List } from './edit/List';
+export const App = () => {
+ return (
+
+ }>
+ }>
+ } />
+
+
+ );
+};
diff --git a/src/pages/file/layouts/index.tsx b/src/pages/file/layouts/index.tsx
new file mode 100644
index 0000000..724cff7
--- /dev/null
+++ b/src/pages/file/layouts/index.tsx
@@ -0,0 +1,5 @@
+import { LayoutMain } from '@/modules/layout';
+
+export const Main = () => {
+ return ;
+};
diff --git a/src/pages/file/store/index.ts b/src/pages/file/store/index.ts
new file mode 100644
index 0000000..ff6c747
--- /dev/null
+++ b/src/pages/file/store/index.ts
@@ -0,0 +1,97 @@
+import { create } from 'zustand';
+import { query } from '@/modules';
+import { message } from 'antd';
+import { sortBy } from 'lodash-es';
+type FileStore = {
+ showEdit: boolean;
+ setShowEdit: (showEdit: boolean) => void;
+ formData: any;
+ setFormData: (formData: any) => void;
+ loading: boolean;
+ setLoading: (loading: boolean) => void;
+ path: string;
+ setPath: (path: string) => void;
+ list: any[];
+ getList: () => Promise;
+ updateData: (data: any) => Promise;
+ deleteData: (id: string) => Promise;
+ getFile: (path: string) => Promise;
+ file: any;
+ setFile: (file: any) => void;
+};
+export const useFileStore = create((set, get) => {
+ return {
+ showEdit: false,
+ setShowEdit: (showEdit) => set({ showEdit }),
+ formData: {},
+ setFormData: (formData) => set({ formData }),
+ loading: false,
+ setLoading: (loading) => set({ loading }),
+ path: '',
+ setPath: (path) => set({ path }),
+ list: [],
+ getList: async () => {
+ const { path } = get();
+ set({ loading: true });
+
+ const res = await query.post({
+ path: 'file',
+ key: 'list',
+ data: {
+ prefix: path,
+ },
+ });
+ set({ loading: false });
+ if (res.code === 200) {
+ const list = res.data;
+ const sortedList = sortBy(list, [(item) => !item.prefix]);
+ set({ list: sortedList });
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ updateData: async (data) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'file',
+ key: 'update',
+ data,
+ });
+ if (res.code === 200) {
+ message.success('Success');
+ set({ showEdit: false, formData: res.data });
+ getList();
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ deleteData: async (id) => {
+ const { getList } = get();
+ const res = await query.post({
+ path: 'file',
+ key: 'delete',
+ id,
+ });
+ if (res.code === 200) {
+ getList();
+ message.success('Success');
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ getFile: async (path) => {
+ const res = await query.post({
+ path: 'file',
+ key: 'stat',
+ data: { prefix: path },
+ });
+ if (res.code === 200) {
+ set({ file: res.data });
+ } else {
+ message.error(res.message || 'Request failed');
+ }
+ },
+ file: {},
+ setFile: (file) => set({ file }),
+ };
+});