7 小时以前 700aa7f13377c21987fa23ad330776a007912cde
refactor(srm): 优化投标模块获奖信息获取和文件上传组件

- 替换 getAward 接口调用为 getAwardByProject 以按项目获取获奖信息
- 移除文件上传组件中冗余的注释和变量声明
- 重构表单初始化逻辑,统一设置字段值的方式
- 优化表单API中文件上传字段的值格式化处理
- 简化文件上传组件中的校验和上传流程
已修改17个文件
175 ■■■■ 文件已修改
src/api/srm/tender/index.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/upload/file-upload.vue 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/packages/@core/ui-kit/form-ui/src/form-api.ts 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/finance/payment/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/finance/receipt/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/in/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/modules/form.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/request/modules/form.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/return/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/out/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/return/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/stock/check/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/stock/in/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/stock/move/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/stock/out/modules/form.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/srm/tender/detail.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/srm/tender/index.ts
@@ -223,6 +223,10 @@
  return requestClient.get<SrmTenderApi.BidAwardVO>(`/srm/bid-award/get?id=${id}`);
}
export function getAwardByProject(tenderProjectId: number) {
  return requestClient.get<SrmTenderApi.BidAwardVO>(`/srm/bid-award/get-by-project?tenderProjectId=${tenderProjectId}`);
}
export function approveAward(id: number) {
  return requestClient.put(`/srm/bid-award/approve?id=${id}`);
}
src/components/upload/file-upload.vue
@@ -55,22 +55,20 @@
  maxSizeRef: maxSize,
});
/** 计算当前绑定的值,优先使用 modelValue */
const currentValue = computed(() => {
  return props.modelValue === undefined ? props.value : props.modelValue;
});
/** 判断是否使用 modelValue */
const isUsingModelValue = computed(() => {
  return props.modelValue !== undefined;
});
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true); // 文件大小错误提示
const isActMsg = ref<boolean>(true); // 文件类型错误提示
const isFirstRender = ref<boolean>(true); // 是否第一次渲染
const uploadNumber = ref<number>(0); // 上传文件计数器
const uploadList = ref<any[]>([]); // 临时上传列表
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
const isFirstRender = ref<boolean>(true);
const uploadNumber = ref<number>(0);
const uploadList = ref<any[]>([]);
watch(
  currentValue,
@@ -149,17 +147,10 @@
function handleUploadError(error: any) {
  console.error('上传错误:', error);
  message.error($t('ui.upload.uploadError'));
  // 上传失败时减少计数器
  uploadNumber.value = Math.max(0, uploadNumber.value - 1);
}
/**
 * 上传前校验
 * @param file 待上传的文件
 * @returns 是否允许上传
 */
async function beforeUpload(file: File) {
  // 检查文件数量限制
  if (fileList.value!.length >= props.maxNumber) {
    message.error($t('ui.upload.maxNumber', [props.maxNumber]));
    return Upload.LIST_IGNORE;
@@ -170,7 +161,6 @@
  if (!isAct) {
    message.error($t('ui.upload.acceptUpload', [accept]));
    isActMsg.value = false;
    // 防止弹出多个错误提示
    setTimeout(() => (isActMsg.value = true), 1000);
    return Upload.LIST_IGNORE;
  }
@@ -178,12 +168,10 @@
  if (isLt) {
    message.error($t('ui.upload.maxSizeMultiple', [maxSize]));
    isLtMsg.value = false;
    // 防止弹出多个错误提示
    setTimeout(() => (isLtMsg.value = true), 1000);
    return Upload.LIST_IGNORE;
  }
  // 只有在验证通过后才增加计数器
  uploadNumber.value++;
  if (props.returnText) {
    const fileContent = await file.text();
@@ -192,23 +180,18 @@
  return true;
}
/** 自定义上传请求 */
async function customRequest(info: UploadRequestOption) {
  let { api } = props;
  if (!api || !isFunction(api)) {
    api = useUpload(props.directory).httpRequest;
  }
  try {
    // 上传文件
    const progressEvent: AxiosProgressEvent = (e) => {
      const percent = Math.trunc((e.loaded / e.total!) * 100);
      info.onProgress!({ percent });
    };
    const res = await api?.(info.file as File, progressEvent);
    // 处理上传成功后的逻辑
    handleUploadSuccess(res, info.file as File);
    info.onSuccess!(res);
    message.success($t('ui.upload.uploadSuccess'));
  } catch (error: any) {
@@ -218,19 +201,12 @@
  }
}
/**
 * 处理上传成功
 * @param res 上传响应结果
 * @param file 上传的文件
 */
function handleUploadSuccess(res: any, file: File) {
  // 删除临时文件
  const index = fileList.value?.findIndex((item) => item.name === file.name);
  if (index !== -1) {
    fileList.value?.splice(index!, 1);
  }
  // 添加到临时上传列表
  const fileUrl = res?.url || res?.data || res;
  uploadList.value.push({
    name: res?.name || file.name,
@@ -241,13 +217,11 @@
    uid: file.name + Date.now(),
  });
  // 检查是否所有文件都上传完成
  if (uploadList.value.length >= uploadNumber.value) {
    fileList.value?.push(...uploadList.value);
    uploadList.value = [];
    uploadNumber.value = 0;
    // 更新值
    const value = getValue();
    isInnerOperate.value = true;
    emit('update:value', value);
@@ -256,10 +230,6 @@
  }
}
/**
 * 获取当前文件列表的值
 * @returns 文件 URL 列表或字符串
 */
function getValue() {
  const list = (fileList.value || [])
    .filter((item) => item?.status === UploadResultStatus.DONE)
@@ -276,10 +246,8 @@
      return props.valuePrefix ? `${props.valuePrefix}${val}` : val;
    });
  // 单个文件的情况,根据输入参数类型决定返回格式
  if (props.maxNumber === 1) {
    const singleValue = list.length > 0 ? list[0] : '';
    // 如果原始值是字符串或 modelValue 是字符串,返回字符串
    if (
      isString(props.value) ||
      (isUsingModelValue.value && isString(props.modelValue))
@@ -289,7 +257,6 @@
    return singleValue;
  }
  // 多文件情况,根据输入参数类型决定返回格式
  if (isUsingModelValue.value) {
    return Array.isArray(props.modelValue) ? list : list.join(',');
  }
@@ -382,7 +349,6 @@
</style>
<style>
/* 文件上传列表显示手型光标样式失效。不知道为啥. 先这里加上 */
.ant-upload-list-text .ant-upload-list-item {
  cursor: pointer;
}
src/packages/@core/ui-kit/form-ui/src/form-api.ts
@@ -166,7 +166,54 @@
    const values = form.values
      ? this.handleRangeTimeValue(cloneDeep(toRaw(form.values)))
      : {};
    return this.handleValueFormat(values) as T;
    const result = this.handleValueFormat(values);
    // 自动提取 FileUpload/Upload 字段中的文件 ID,避免提交时携带完整文件对象
    const currentSchema = this.state?.schema ?? [];
    for (const schema of currentSchema) {
      // 兼容字符串类型和已解析的 Vue Component 对象
      const compName: string =
        typeof schema.component === 'string'
          ? schema.component
          : (schema.component as any)?.name ?? '';
      if (compName !== 'FileUpload' && compName !== 'Upload') {
        continue;
      }
      if (schema.valueFormat) continue;
      const fieldName = schema.fieldName;
      const rawValue = result[fieldName];
      if (
        rawValue == null ||
        !Array.isArray(rawValue) ||
        rawValue.length === 0
      ) {
        continue;
      }
      if (
        typeof rawValue[0] !== 'object' ||
        !('status' in rawValue[0])
      ) {
        continue;
      }
      const props = (schema.componentProps || {}) as Record<string, any>;
      const valueKey = props.valueKey || 'url';
      const maxNumber = props.maxNumber ?? 1;
      const resultField = props.resultField;
      const valuePrefix = props.valuePrefix || '';
      const list = rawValue
        .filter((item: any) => item?.status === 'done')
        .map((item: any) => {
          if (resultField && item?.response) return item.response;
          const v =
            item?.response?.[valueKey] ??
            item?.[valueKey] ??
            item?.url ??
            item?.response?.url ??
            item?.response;
          return valuePrefix ? `${valuePrefix}${v}` : v;
        });
      result[fieldName] = maxNumber === 1 ? (list[0] ?? '') : list;
    }
    return result as T;
  }
  async isFieldValid(fieldName: string) {
src/views/erp/finance/payment/modules/form.vue
@@ -160,6 +160,8 @@
    modalApi.lock();
    try {
      formData.value = await getFinancePayment(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -168,10 +170,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/finance/receipt/modules/form.vue
@@ -174,6 +174,8 @@
    modalApi.lock();
    try {
      formData.value = await getFinanceReceipt(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -182,10 +184,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/purchase/in/modules/form.vue
@@ -190,6 +190,8 @@
    modalApi.lock();
    try {
      formData.value = await getPurchaseIn(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -198,10 +200,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/purchase/order/modules/form.vue
@@ -151,6 +151,7 @@
    modalApi.lock();
    try {
      formData.value = await getPurchaseOrder(data.id);
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -159,9 +160,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/purchase/request/modules/form.vue
@@ -113,6 +113,7 @@
    modalApi.lock();
    try {
      formData.value = await getPurchaseRequest(data.id);
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -121,9 +122,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/purchase/return/modules/form.vue
@@ -190,6 +190,8 @@
    modalApi.lock();
    try {
      formData.value = await getPurchaseReturn(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -198,10 +200,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/sale/order/modules/form.vue
@@ -132,6 +132,8 @@
    modalApi.lock();
    try {
      formData.value = await getSaleOrder(data.id);
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -140,10 +142,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/sale/out/modules/form.vue
@@ -185,6 +185,8 @@
    modalApi.lock();
    try {
      formData.value = await getSaleOut(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -193,10 +195,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/sale/return/modules/form.vue
@@ -190,6 +190,8 @@
    modalApi.lock();
    try {
      formData.value = await getSaleReturn(data.id);
      // 设置到 values
      await formApi.setValues(formData.value, false);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -198,10 +200,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value, false);
    } finally {
      modalApi.unlock();
    }
src/views/erp/stock/check/modules/form.vue
@@ -105,6 +105,8 @@
    modalApi.lock();
    try {
      formData.value = await getStockCheck(data.id);
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -113,10 +115,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/stock/in/modules/form.vue
@@ -101,6 +101,8 @@
    modalApi.lock();
    try {
      formData.value = await getStockIn(data.id);
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -109,10 +111,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/stock/move/modules/form.vue
@@ -105,6 +105,8 @@
    modalApi.lock();
    try {
      formData.value = await getStockMove(data.id);
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -113,10 +115,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/erp/stock/out/modules/form.vue
@@ -105,6 +105,8 @@
    modalApi.lock();
    try {
      formData.value = await getStockOut(data.id);
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value?.attachmentList?.length) {
        const blobIds = formData.value.attachmentList.map((item) => ({
          uid: String(item.id),
@@ -113,10 +115,8 @@
          status: 'done',
          id: item.id,
        }));
        formApi.setFieldValue('blobIds', blobIds);
        await formApi.setFieldValue('blobIds', blobIds);
      }
      // 设置到 values
      await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }
src/views/srm/tender/detail.vue
@@ -16,7 +16,7 @@
  getQuoteList, createQuote, updateQuote,
  createBidOpen, getBidOpen,
  getEvaluationList, createBidEvaluation, calculateRanking,
  createAward, getAward, approveAward, generatePurchaseOrder,
  createAward, getAward, getAwardByProject, approveAward, generatePurchaseOrder,
} from '#/api/srm/tender';
import { getSupplierSimpleList } from '#/api/srm/supplier';
import { getItemSimpleList } from '#/api/mdm/item';
@@ -210,7 +210,7 @@
const awardForm = ref<SrmTenderApi.BidAwardVO>({ tenderProjectId: projectId, supplierId: 0, bidId: 0, awardNo: '' });
async function loadAward() {
  try { award.value = await getAward(projectId); } catch { award.value = undefined; }
  try { award.value = await getAwardByProject(projectId); } catch { award.value = undefined; }
}
async function handleCreateAward() {
  await createAward(awardForm.value);