feat: 添加导入Bintask Excel文件功能,更新API和场景编辑器以支持文件上传,优化HTTP服务以处理FormData
This commit is contained in:
parent
5cdbcebcd3
commit
6163b0baa5
@ -12,6 +12,8 @@ const enum API {
|
|||||||
获取组场景 = '/scene/getByGroupId',
|
获取组场景 = '/scene/getByGroupId',
|
||||||
保存组场景 = '/scene/saveByGroupId',
|
保存组场景 = '/scene/saveByGroupId',
|
||||||
|
|
||||||
|
导入Bintask = '/scene/importBinTaskExcel',
|
||||||
|
|
||||||
实时监控场景 = '/scene/monitor/:id',
|
实时监控场景 = '/scene/monitor/:id',
|
||||||
实时监控真实场景 = '/scene/monitor/real/:id',
|
实时监控真实场景 = '/scene/monitor/real/:id',
|
||||||
实时监控库位状态 = '/ws/storage-location/:id',
|
实时监控库位状态 = '/ws/storage-location/:id',
|
||||||
@ -123,6 +125,38 @@ export async function monitorRealSceneById(id: SceneInfo['id']): Promise<WebSock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function importBinTaskExcel(id: SceneInfo['id'], file: File): Promise<boolean> {
|
||||||
|
if (!id || !file) return false;
|
||||||
|
|
||||||
|
// 验证文件类型和大小
|
||||||
|
const allowedTypes = [
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
||||||
|
'application/vnd.ms-excel' // .xls
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!allowedTypes.includes(file.type)) {
|
||||||
|
throw new Error('请选择Excel文件(.xlsx或.xls格式)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证文件大小(1MB = 1024 * 1024 bytes)
|
||||||
|
const maxSize = 1024 * 1024;
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
throw new Error('文件大小不能超过1MB');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
formData.append('id', id);
|
||||||
|
|
||||||
|
await http.postFormData(API.导入Bintask, formData);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.debug(error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function monitorStorageLocationById(
|
export async function monitorStorageLocationById(
|
||||||
id: SceneInfo['id'],
|
id: SceneInfo['id'],
|
||||||
options?: {
|
options?: {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { message, Modal } from 'ant-design-vue';
|
|||||||
import { computed, onMounted, provide, ref, type ShallowRef, shallowRef, watch } from 'vue';
|
import { computed, onMounted, provide, ref, type ShallowRef, shallowRef, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { getSceneById, pushSceneById, saveSceneById } from '../apis/scene';
|
import { getSceneById, importBinTaskExcel, pushSceneById, saveSceneById } from '../apis/scene';
|
||||||
import BatchEditToolbar from '../components/batch-edit-toolbar.vue';
|
import BatchEditToolbar from '../components/batch-edit-toolbar.vue';
|
||||||
import AutoCreateStorageModal from '../components/modal/auto-create-storage-modal.vue';
|
import AutoCreateStorageModal from '../components/modal/auto-create-storage-modal.vue';
|
||||||
import { EditorService } from '../services/editor.service';
|
import { EditorService } from '../services/editor.service';
|
||||||
@ -80,15 +80,15 @@ const autoCreateStorageData = ref<{
|
|||||||
actionPoints: any[];
|
actionPoints: any[];
|
||||||
}>({
|
}>({
|
||||||
areaName: '',
|
areaName: '',
|
||||||
actionPoints: []
|
actionPoints: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
editor.value = new EditorService(container.value!);
|
editor.value = new EditorService(container.value!);
|
||||||
|
|
||||||
// 将 editor 存储到 store 中
|
// 将 editor 存储到 store 中
|
||||||
editorStore.setEditor(editor as ShallowRef<EditorService>);
|
editorStore.setEditor(editor as ShallowRef<EditorService>);
|
||||||
|
|
||||||
// 监听自动生成库位对话框事件
|
// 监听自动生成库位对话框事件
|
||||||
editor.value?.on('autoCreateStorageDialog', (data: any) => {
|
editor.value?.on('autoCreateStorageDialog', (data: any) => {
|
||||||
autoCreateStorageData.value = data;
|
autoCreateStorageData.value = data;
|
||||||
@ -134,6 +134,23 @@ const exportScene = () => {
|
|||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 导入Bintask Excel文件
|
||||||
|
const importBinTask = async () => {
|
||||||
|
try {
|
||||||
|
const file = await selectFile('.xlsx,.xls');
|
||||||
|
if (!file || !file.size) return;
|
||||||
|
|
||||||
|
const success = await importBinTaskExcel(props.id, file);
|
||||||
|
if (success) {
|
||||||
|
message.success('Bintask导入成功');
|
||||||
|
} else {
|
||||||
|
message.error('Bintask导入失败');
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
message.error(error.message || 'Bintask导入失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const show = ref<boolean>(true);
|
const show = ref<boolean>(true);
|
||||||
const current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
const current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
||||||
watch(
|
watch(
|
||||||
@ -187,7 +204,7 @@ const backToCards = () => {
|
|||||||
// 处理自动生成库位确认
|
// 处理自动生成库位确认
|
||||||
const handleAutoCreateStorageConfirm = (actionPoints: any[]) => {
|
const handleAutoCreateStorageConfirm = (actionPoints: any[]) => {
|
||||||
if (!editor.value) return;
|
if (!editor.value) return;
|
||||||
|
|
||||||
editor.value.autoCreateStorageLocations(autoCreateStorageData.value.areaName, actionPoints);
|
editor.value.autoCreateStorageLocations(autoCreateStorageData.value.areaName, actionPoints);
|
||||||
message.success(`已为 ${actionPoints.length} 个动作点自动生成库位`);
|
message.success(`已为 ${actionPoints.length} 个动作点自动生成库位`);
|
||||||
};
|
};
|
||||||
@ -216,6 +233,7 @@ const handleAutoCreateStorageCancel = () => {
|
|||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="toPush">{{ $t('推送') }}</a-button>
|
<a-button @click="toPush">{{ $t('推送') }}</a-button>
|
||||||
<a-button @click="importScene">{{ $t('导入') }}</a-button>
|
<a-button @click="importScene">{{ $t('导入') }}</a-button>
|
||||||
|
<a-button @click="importBinTask">导入Bintask</a-button>
|
||||||
<a-button @click="exportScene">{{ $t('导出') }}</a-button>
|
<a-button @click="exportScene">{{ $t('导出') }}</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-flex>
|
</a-flex>
|
||||||
|
|||||||
@ -7,6 +7,19 @@ const http: HttpInstance = axios.create({
|
|||||||
adapter: 'fetch',
|
adapter: 'fetch',
|
||||||
timeout: 30_000,
|
timeout: 30_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 添加FormData上传方法
|
||||||
|
http.postFormData = async <D = void>(url: string, formData: FormData, config?: AxiosRequestConfig): Promise<D | undefined> => {
|
||||||
|
const response = await http.post<D>(url, formData, {
|
||||||
|
...config,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
...config?.headers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
export default http;
|
export default http;
|
||||||
|
|
||||||
// 添加请求拦截器
|
// 添加请求拦截器
|
||||||
@ -63,6 +76,7 @@ http.interceptors.response.use(
|
|||||||
type HttpInstance = Omit<AxiosInstance, 'get' | 'post'> & {
|
type HttpInstance = Omit<AxiosInstance, 'get' | 'post'> & {
|
||||||
get: <D = void>(url: string, config?: AxiosRequestConfig) => Promise<D | undefined>;
|
get: <D = void>(url: string, config?: AxiosRequestConfig) => Promise<D | undefined>;
|
||||||
post: <D = void, B = unknown>(url: string, body?: B, config?: AxiosRequestConfig<B>) => Promise<D | undefined>;
|
post: <D = void, B = unknown>(url: string, body?: B, config?: AxiosRequestConfig<B>) => Promise<D | undefined>;
|
||||||
|
postFormData: <D = void>(url: string, formData: FormData, config?: AxiosRequestConfig) => Promise<D | undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CommonRes<T = void> = {
|
type CommonRes<T = void> = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user