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/saveByGroupId',
|
||||
|
||||
导入Bintask = '/scene/importBinTaskExcel',
|
||||
|
||||
实时监控场景 = '/scene/monitor/:id',
|
||||
实时监控真实场景 = '/scene/monitor/real/: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(
|
||||
id: SceneInfo['id'],
|
||||
options?: {
|
||||
|
@ -3,7 +3,7 @@ import { message, Modal } from 'ant-design-vue';
|
||||
import { computed, onMounted, provide, ref, type ShallowRef, shallowRef, watch } from 'vue';
|
||||
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 AutoCreateStorageModal from '../components/modal/auto-create-storage-modal.vue';
|
||||
import { EditorService } from '../services/editor.service';
|
||||
@ -80,15 +80,15 @@ const autoCreateStorageData = ref<{
|
||||
actionPoints: any[];
|
||||
}>({
|
||||
areaName: '',
|
||||
actionPoints: []
|
||||
actionPoints: [],
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
editor.value = new EditorService(container.value!);
|
||||
|
||||
|
||||
// 将 editor 存储到 store 中
|
||||
editorStore.setEditor(editor as ShallowRef<EditorService>);
|
||||
|
||||
|
||||
// 监听自动生成库位对话框事件
|
||||
editor.value?.on('autoCreateStorageDialog', (data: any) => {
|
||||
autoCreateStorageData.value = data;
|
||||
@ -134,6 +134,23 @@ const exportScene = () => {
|
||||
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 current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
||||
watch(
|
||||
@ -187,7 +204,7 @@ const backToCards = () => {
|
||||
// 处理自动生成库位确认
|
||||
const handleAutoCreateStorageConfirm = (actionPoints: any[]) => {
|
||||
if (!editor.value) return;
|
||||
|
||||
|
||||
editor.value.autoCreateStorageLocations(autoCreateStorageData.value.areaName, actionPoints);
|
||||
message.success(`已为 ${actionPoints.length} 个动作点自动生成库位`);
|
||||
};
|
||||
@ -216,6 +233,7 @@ const handleAutoCreateStorageCancel = () => {
|
||||
</a-button>
|
||||
<a-button @click="toPush">{{ $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-space>
|
||||
</a-flex>
|
||||
|
@ -7,6 +7,19 @@ const http: HttpInstance = axios.create({
|
||||
adapter: 'fetch',
|
||||
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;
|
||||
|
||||
// 添加请求拦截器
|
||||
@ -63,6 +76,7 @@ http.interceptors.response.use(
|
||||
type HttpInstance = Omit<AxiosInstance, 'get' | 'post'> & {
|
||||
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>;
|
||||
postFormData: <D = void>(url: string, formData: FormData, config?: AxiosRequestConfig) => Promise<D | undefined>;
|
||||
};
|
||||
|
||||
type CommonRes<T = void> = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user