根据你提供的代码,我看到了你的 VAxios 类实现。这里有一个关键问题需要修复,以及一个可能的响应处理问题。以下是完整的解决方案:

问题分析

  1. 主要问题:在 request 方法中,你添加了一个回调调用:
//zhangyafei---添加回调方法
config.success && config.success(res.data);
//zhangyafei---添加回调方法

这行代码会尝试调用 config.success 回调函数,但你的 API 调用中并没有传递这个回调。这可能导致 undefined 错误。

  1. 响应数据结构:从你的 uploadFile 方法中的处理来看,你的 API 响应格式可能是:
{
  "success": true,
  "code": 200,
  "message": "操作成功",
  "data": {
    "records": [...],
    "total": 100,
    "current": 1,
    "size": 10
  }
}

修正后的代码

1. 首先,修改你的 product.api.ts

import { defHttp } from '/@/utils/http/axios';

export enum Api {
  queryMaterialList = '/material/page',
}

/**
 * 获取物料列表
 * @param params 查询参数
 * @returns Promise
 */
export const queryMaterialList = (params?: any) => {
  return defHttp.get(
    { 
      url: Api.queryMaterialList, 
      params,
      // 如果你确实需要success回调,可以这样传递
      // success: (data) => console.log('请求成功', data)
    },
    {
      // 这里可以传递请求选项
      isTransformResponse: false, // 如果你希望直接获取原始响应
    }
  );
};

2. 修改你的 VAxios 类中的 request 方法,添加安全检查:

request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
  let conf: CreateAxiosOptions = cloneDeep(config);
  const transform = this.getTransform();

  const { requestOptions } = this.options;

  const opt: RequestOptions = Object.assign({}, requestOptions, options);

  const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
  if (beforeRequestHook && isFunction(beforeRequestHook)) {
    conf = beforeRequestHook(conf, opt);
  }
  conf.requestOptions = opt;

  conf = this.supportFormData(conf);

  return new Promise((resolve, reject) => {
    this.axiosInstance
      .request<any, AxiosResponse<Result>>(conf)
      .then((res: AxiosResponse<Result>) => {
        if (transformRequestHook && isFunction(transformRequestHook)) {
          try {
            const ret = transformRequestHook(res, opt);
            // 添加安全检查,避免调用 undefined 的回调
            if (config.success && typeof config.success === 'function') {
              config.success(res.data);
            }
            resolve(ret);
          } catch (err) {
            reject(err || new Error('request error!'));
          }
          return;
        }
        resolve(res as unknown as Promise<T>);
      })
      .catch((e: Error | AxiosError) => {
        if (requestCatchHook && isFunction(requestCatchHook)) {
          reject(requestCatchHook(e, opt));
          return;
        }
        if (axios.isAxiosError(e)) {
          // 在此处重写来自axios的错误消息
        }
        reject(e);
      });
  });
}

3. 修正你的 Vue 组件代码:

<template>
  <a-table 
    :columns="columns" 
    :data-source="materialList"
    :pagination="pagination"
    :loading="loading"
    @change="handleTableChange"
    rowKey="id"
  >
  </a-table>
</template>

<script lang="ts" setup>
import { queryMaterialList } from '/@/views/product/product.api.ts';
import { ref, onMounted } from 'vue';

const columns = [
  { title: '名称', dataIndex: 'materialName', key: 'materialName' },
  { title: '编码', dataIndex: 'materialCode', key: 'materialCode' },
  { title: '规格', dataIndex: 'specification', key: 'specification' },
  { title: '单位', dataIndex: 'unit', key: 'unit' },
];

const materialList = ref([]);
const pagination = ref({
  current: 1,
  pageSize: 10,
  total: 0,
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '50'],
  showTotal: (total: number) => `共 ${total} 条`,
});
const loading = ref(false);

async function fetchData() {
  loading.value = true;
  try {
    // 传递分页参数
    const params = {
      pageNo: pagination.value.current,  // 根据你的API调整参数名
      pageSize: pagination.value.pageSize,
    };
    
    const res = await queryMaterialList(params);
    console.log('API Response:', res);
    
    // 处理响应数据
    if (res) {
      // 根据你的实际响应结构调整
      // 假设响应格式为: { success: true, data: { records: [], total: 100 } }
      if (res.data && res.data.records) {
        materialList.value = res.data.records;
        pagination.value.total = res.data.total || 0;
        pagination.value.current = res.data.current || params.pageNo;
      } 
      // 或者直接返回数组
      else if (Array.isArray(res)) {
        materialList.value = res;
        pagination.value.total = res.length;
      }
      // 或者返回分页对象
      else if (res.records) {
        materialList.value = res.records;
        pagination.value.total = res.total || 0;
      }
    }
  } catch (error: any) {
    console.error('❌ 请求异常:', error.message);
    materialList.value = [];
  } finally {
    loading.value = false;
  }
}

const handleTableChange = (pag: any) => {
  pagination.value.current = pag.current;
  pagination.value.pageSize = pag.pageSize;
  fetchData();
};

onMounted(() => {
  fetchData();
});
</script>

4. 调试建议

如果仍然遇到 res undefined 的问题,可以:

  1. 在浏览器控制台查看完整响应
// 在 fetchData 中添加
console.log('Full response:', JSON.stringify(res, null, 2));
  1. 检查网络请求

    • 打开浏览器开发者工具(F12)
    • 切换到 Network 标签
    • 刷新页面,找到 /material/page 请求
    • 查看 Response 的实际格式
  2. 添加响应拦截器调试
    在你的 VAxios 类中,可以在 response 拦截器添加日志:

// 在 setupInterceptors 方法中
this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
  console.log('Response interceptor - raw:', res);
  res && axiosCanceler.removePending(res.config);
  if (responseInterceptors && isFunction(responseInterceptors)) {
    res = responseInterceptors(res);
    console.log('Response interceptor - transformed:', res);
  }
  return res;
}, undefined);

这样可以帮你确定数据是在哪个环节丢失的。


{
    "code": 200,
    "message": "success",
    "data": {
        "total": 19,
        "records": [
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT002",
                "materialCode": "MAT-IP13-256",
                "materialName": "iPhone 13",
                "specification": "256G 粉色",
                "unit": "台",
                "categoryId": "CAT001",
                "supplierId": "SUP001",
                "barcode": "6901234567892",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT003",
                "materialCode": "MAT-IP14-128",
                "materialName": "iPhone 14",
                "specification": "128G 紫色",
                "unit": "台",
                "categoryId": "CAT001",
                "supplierId": "SUP001",
                "barcode": "6901234567893",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT004",
                "materialCode": "MAT-HW-P50",
                "materialName": "华为P50 Pro",
                "specification": "8+256G 曜金黑",
                "unit": "台",
                "categoryId": "CAT001",
                "supplierId": "SUP002",
                "barcode": "6901234567894",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT005",
                "materialCode": "MAT-HW-M40",
                "materialName": "华为Mate 40 Pro",
                "specification": "8+256G 釉白色",
                "unit": "台",
                "categoryId": "CAT001",
                "supplierId": "SUP002",
                "barcode": "6901234567895",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT006",
                "materialCode": "MAT-XM-13",
                "materialName": "小米13 Ultra",
                "specification": "12+512G 黑色",
                "unit": "台",
                "categoryId": "CAT001",
                "supplierId": "SUP003",
                "barcode": "6901234567896",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT007",
                "materialCode": "MAT-XM-PAD",
                "materialName": "小米平板6",
                "specification": "8+128G 灰色",
                "unit": "台",
                "categoryId": "CAT002",
                "supplierId": "SUP003",
                "barcode": "6901234567897",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT008",
                "materialCode": "MAT-HW-PAD",
                "materialName": "华为MatePad Pro",
                "specification": "12+256G 金色",
                "unit": "台",
                "categoryId": "CAT002",
                "supplierId": "SUP002",
                "barcode": "6901234567898",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT009",
                "materialCode": "MAT-IP-PAD",
                "materialName": "iPad Air 5",
                "specification": "64G 银色",
                "unit": "台",
                "categoryId": "CAT002",
                "supplierId": "SUP001",
                "barcode": "6901234567899",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT010",
                "materialCode": "MAT-LENOVO",
                "materialName": "联想ThinkPad X1",
                "specification": "i7/16G/512G 黑色",
                "unit": "台",
                "categoryId": "CAT003",
                "supplierId": "SUP004",
                "barcode": "6901234567810",
                "status": 1
            },
            {
                "creator": "admin",
                "createTime": "2026-03-15 11:11:28",
                "updater": "admin",
                "updateTime": "2026-03-15 11:11:28",
                "deleted": 0,
                "id": "MAT011",
                "materialCode": "MAT-DELL",
                "materialName": "戴尔XPS 13",
                "specification": "i7/16G/1T 银色",
                "unit": "台",
                "categoryId": "CAT003",
                "supplierId": "SUP004",
                "barcode": "6901234567811",
                "status": 1
            }
        ],
        "current": 1,
        "size": 10
    }
}

非常好!你发现了关键点。设置 isTransformResponse: false 确实会影响响应数据的格式。让我解释一下不同选项下的响应格式,并提供完整的解决方案。

不同选项下的响应格式

1. isTransformResponse: false

返回的是原始的 Axios 响应对象:

{
  data: {
    success: true,
    code: 200,
    message: "操作成功",
    data: {
      records: [...],
      total: 100,
      current: 1,
      size: 10
    }
  },
  status: 200,
  statusText: "OK",
  headers: {...},
  config: {...}
}

2. isTransformResponse: true 或不设置时(默认)

返回的是转换后的数据,通常是 res.data 的内容:

{
  success: true,
  code: 200,
  message: "操作成功",
  data: {
    records: [...],
    total: 100,
    current: 1,
    size: 10
  }
}

根据你的需求选择方案

方案一:使用默认转换(推荐)

product.api.ts:

import { defHttp } from '/@/utils/http/axios';

export enum Api {
  queryMaterialList = '/material/page',
}

export const queryMaterialList = (params?: any) => {
  return defHttp.get(
    { url: Api.queryMaterialList, params }
    // 不传递第二个参数,使用默认转换
  );
};

组件代码:

<script lang="ts" setup>
async function fetchData() {
  loading.value = true;
  try {
    const params = {
      pageNo: pagination.value.current,
      pageSize: pagination.value.pageSize,
    };
    
    const res = await queryMaterialList(params);
    console.log('API Response:', res);
    
    // 默认转换后,res 就是响应体的 data 部分
    // 假设格式: { success: true, data: { records: [], total: 100 } }
    if (res && res.data) {
      materialList.value = res.data.records || [];
      pagination.value.total = res.data.total || 0;
    }
    // 或者如果直接返回分页对象: { records: [], total: 100 }
    else if (res && res.records) {
      materialList.value = res.records;
      pagination.value.total = res.total || 0;
    }
  } catch (error) {
    console.error('请求失败:', error);
  } finally {
    loading.value = false;
  }
}
</script>

方案二:使用 isTransformResponse: false(需要更多处理)

product.api.ts:

import { defHttp } from '/@/utils/http/axios';

export enum Api {
  queryMaterialList = '/material/page',
}

export const queryMaterialList = (params?: any) => {
  return defHttp.get(
    { url: Api.queryMaterialList, params },
    {
      isTransformResponse: false, // 获取原始响应
    }
  );
};

组件代码:

<script lang="ts" setup>
async function fetchData() {
  loading.value = true;
  try {
    const params = {
      pageNo: pagination.value.current,
      pageSize: pagination.value.pageSize,
    };
    
    const res = await queryMaterialList(params);
    console.log('Raw Response:', res);
    
    // 此时 res 是完整的 Axios 响应对象
    // 需要访问 res.data 获取实际数据
    if (res && res.data) {
      // 假设后端返回格式: { success: true, data: { records: [], total: 100 } }
      if (res.data.data) {
        materialList.value = res.data.data.records || [];
        pagination.value.total = res.data.data.total || 0;
      } 
      // 或者直接返回分页对象: { records: [], total: 100 }
      else if (res.data.records) {
        materialList.value = res.data.records;
        pagination.value.total = res.data.total || 0;
      }
    }
  } catch (error) {
    console.error('请求失败:', error);
  } finally {
    loading.value = false;
  }
}
</script>

方案三:通用处理函数(最灵活)

创建一个工具函数来处理不同格式的响应:

<script lang="ts" setup>
import { queryMaterialList } from '/@/views/product/product.api.ts';
import { ref, onMounted } from 'vue';

// 通用响应处理函数
function processResponse(response: any) {
  // 处理 Axios 原始响应
  if (response && response.data) {
    // 如果 response.data 包含 success/data 结构
    if (response.data.data && response.data.data.records) {
      return {
        records: response.data.data.records,
        total: response.data.data.total || 0,
        current: response.data.data.current || 1,
      };
    }
    // 如果 response.data 直接包含 records
    else if (response.data.records) {
      return {
        records: response.data.records,
        total: response.data.total || 0,
        current: response.data.current || 1,
      };
    }
  }
  
  // 处理已经转换过的响应
  if (response) {
    // 如果响应包含 data.records
    if (response.data && response.data.records) {
      return {
        records: response.data.records,
        total: response.data.total || 0,
        current: response.data.current || 1,
      };
    }
    // 如果响应直接包含 records
    else if (response.records) {
      return {
        records: response.records,
        total: response.total || 0,
        current: response.current || 1,
      };
    }
    // 如果响应是数组
    else if (Array.isArray(response)) {
      return {
        records: response,
        total: response.length,
        current: 1,
      };
    }
  }
  
  // 默认返回空数据
  return {
    records: [],
    total: 0,
    current: 1,
  };
}

const columns = [...]; // 你的列定义
const materialList = ref([]);
const pagination = ref({
  current: 1,
  pageSize: 10,
  total: 0,
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '50'],
  showTotal: (total: number) => `共 ${total} 条`,
});
const loading = ref(false);

async function fetchData() {
  loading.value = true;
  try {
    const params = {
      pageNo: pagination.value.current,
      pageSize: pagination.value.pageSize,
    };
    
    const res = await queryMaterialList(params);
    console.log('Response:', res);
    
    // 使用通用处理函数
    const processed = processResponse(res);
    materialList.value = processed.records;
    pagination.value.total = processed.total;
    pagination.value.current = processed.current;
    
  } catch (error: any) {
    console.error('❌ 请求异常:', error.message);
    materialList.value = [];
  } finally {
    loading.value = false;
  }
}

const handleTableChange = (pag: any) => {
  pagination.value.current = pag.current;
  pagination.value.pageSize = pag.pageSize;
  fetchData();
};

onMounted(() => {
  fetchData();
});
</script>

调试建议

为了确定实际的数据格式,建议先在浏览器控制台查看:

// 在 fetchData 中添加
const res = await queryMaterialList(params);
console.log('Response structure:', {
  hasData: !!res,
  keys: res ? Object.keys(res) : [],
  sample: res ? JSON.stringify(res).substring(0, 200) + '...' : 'null'
});

// 如果有 data 属性
if (res && res.data) {
  console.log('Data structure:', {
    hasDataData: !!res.data.data,
    dataKeys: Object.keys(res.data),
    sample: JSON.stringify(res.data).substring(0, 200) + '...'
  });
}

这样你就能清楚地看到数据的实际结构,然后根据实际结构调整处理逻辑。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐