gaoluyang
2 天以前 27ed1e7f2dd9db7ed30053205d925b6456b7dd71
银川
1.商机管理详情页面新增合同逻辑修改
2.商机状态枚举值修改
已修改12个文件
145 ■■■■■ 文件已修改
src/api/crm/business/index.ts 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/crm/business/status/index.ts 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/data.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/detail/data.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/detail/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/detail/modules/status-form.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/index.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/status/data.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/status/modules/form.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/contract/components/detail-list.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/contract/data.ts 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/contract/modules/form.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/crm/business/index.ts
@@ -21,7 +21,6 @@
    statusTypeName?: string;
    statusId: number;
    statusName?: string;
    endStatus: number;
    endRemark: string;
    dealTime: Date;
    totalProductPrice: number;
@@ -52,8 +51,7 @@
  /** 商机更新状态请求 */
  export interface BusinessUpdateStatusReqVO {
    id: number;
    statusId: number | undefined;
    endStatus: number | undefined;
    statusId: number;
  }
}
src/api/crm/business/status/index.ts
@@ -19,32 +19,9 @@
    id?: number;
    name: string;
    percent?: number;
    endStatus?: number;
    key?: string;
    sort?: number;
  }
}
/** 默认商机状态 */
export const DEFAULT_STATUSES = [
  {
    endStatus: 1,
    key: '结束',
    name: '赢单',
    percent: 100,
  },
  {
    endStatus: 2,
    key: '结束',
    name: '输单',
    percent: 0,
  },
  {
    endStatus: 3,
    key: '结束',
    name: '无效',
    percent: 0,
  },
] satisfies CrmBusinessStatusApi.BusinessStatusType[];
/** 查询商机状态组列表 */
export function getBusinessStatusPage(params: PageParam) {
src/views/crm/business/data.ts
@@ -265,6 +265,7 @@
      title: '商机阶段',
      fixed: 'right',
      width: 120,
      slots: { default: 'statusName' },
    },
    {
      title: '操作',
src/views/crm/business/detail/data.ts
@@ -7,7 +7,6 @@
import { erpPriceInputFormatter, formatDateTime } from '@vben/utils';
import {
  DEFAULT_STATUSES,
  getBusinessStatusSimpleList,
} from '#/api/crm/business/status';
@@ -95,24 +94,6 @@
    },
    {
      fieldName: 'statusId',
      label: '商机状态',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'endStatus',
      label: '商机状态',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'status',
      label: '商机阶段',
      component: 'Select',
      dependencies: {
@@ -121,17 +102,12 @@
          const statusList = await getBusinessStatusSimpleList(
            formData.value?.statusTypeId ?? 0,
          );
          const statusOptions = statusList.map((item) => ({
          const options = statusList.map((item) => ({
            label: `${item.name}(赢单率:${item.percent}%)`,
            value: item.id,
          }));
          const options = DEFAULT_STATUSES.map((item) => ({
            label: `${item.name}(赢单率:${item.percent}%)`,
            value: item.endStatus,
          }));
          statusOptions.push(...options);
          return {
            options: statusOptions,
            options,
          };
        },
      },
src/views/crm/business/detail/index.vue
@@ -160,6 +160,9 @@
          <ContractDetailsList
            :biz-id="businessId"
            :biz-type="BizTypeEnum.CRM_BUSINESS"
            :customer-id="business.customerId"
            :customer-name="business.customerName"
            :business-name="business.name"
          />
        </Tabs.TabPane>
        <Tabs.TabPane tab="操作日志" key="6" :force-render="true">
src/views/crm/business/detail/modules/status-form.vue
@@ -40,13 +40,12 @@
    // 提交表单
    const data = (await formApi.getValues()) as CrmBusinessApi.Business;
    try {
      if (!data.status) {
      if (!data.statusId) {
        return;
      }
      await updateBusinessStatus({
        id: data.id,
        statusId: data.status > 0 ? data.status : undefined,
        endStatus: data.status < 0 ? -data.status : undefined,
        statusId: data.statusId,
      });
      // 关闭并提示
      await modalApi.close();
@@ -65,7 +64,6 @@
    if (!data || !data.id) {
      return;
    }
    data.status = data.endStatus === null ? data.statusId : -data.endStatus;
    formData.value = data;
    modalApi.lock();
    try {
src/views/crm/business/index.vue
@@ -8,7 +8,7 @@
import { Page, useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message, Tabs } from 'ant-design-vue';
import { Button, message, Tabs, Tag } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
@@ -23,6 +23,22 @@
const { push } = useRouter();
const sceneType = ref('1');
const STATUS_COLORS: Record<string, string> = {
  拜访: 'default',
  初步接触: 'processing',
  需求确认: 'cyan',
  方案报价: 'orange',
  商务谈判: 'volcano',
  合同签订: 'success',
  赢单: 'success',
  输单: 'error',
  无效: 'default',
};
function getStatusColor(name: string): string {
  return STATUS_COLORS[name] || 'blue';
}
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
@@ -157,6 +173,9 @@
          {{ row.customerName }}
        </Button>
      </template>
      <template #statusName="{ row }">
        <Tag v-if="row.statusName" :color="getStatusColor(row.statusName)">{{ row.statusName }}</Tag>
      </template>
      <template #actions="{ row }">
        <TableAction
          :actions="[
src/views/crm/business/status/data.ts
@@ -85,10 +85,9 @@
export function useFormColumns(): VxeTableGridOptions['columns'] {
  return [
    {
      field: 'endStatus',
      title: '阶段',
      minWidth: 100,
      slots: { default: 'endStatus' },
      type: 'seq',
      title: '序号',
      width: 60,
    },
    {
      field: 'name',
src/views/crm/business/status/modules/form.vue
@@ -11,7 +11,6 @@
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
  createBusinessStatus,
  DEFAULT_STATUSES,
  getBusinessStatus,
  updateBusinessStatus,
} from '#/api/crm/business/status';
@@ -53,7 +52,6 @@
    try {
      if (formData.value?.statuses && formData.value.statuses.length > 0) {
        data.statuses = formData.value.statuses;
        data.statuses.splice(-3, 3);
      }
      await (formData.value?.id
        ? updateBusinessStatus(data)
@@ -94,8 +92,7 @@
      // 设置到 values
      await formApi.setValues(formData.value as any);
      await gridApi.grid.reloadData(
        (formData.value!.statuses =
          formData.value?.statuses?.concat(DEFAULT_STATUSES)) as any,
        (formData.value!.statuses) as any,
      );
    } finally {
      modalApi.unlock();
@@ -105,7 +102,7 @@
/** 添加状态 */
async function handleAddStatus() {
  formData.value!.statuses!.splice(-3, 0, {
  formData.value!.statuses!.push({
    name: '',
    percent: undefined,
  });
@@ -128,7 +125,7 @@
      mode: 'cell',
    },
    columns: useFormColumns(),
    data: formData.value?.statuses?.concat(DEFAULT_STATUSES),
    data: formData.value?.statuses,
    border: true,
    showOverflow: true,
    autoResize: true,
@@ -152,29 +149,20 @@
    <Form class="mx-4">
      <template #statuses>
        <Grid class="w-full">
          <template #endStatus="{ row, rowIndex }">
            <span>
              {{ row.endStatus ? '结束' : `阶段${rowIndex + 1}` }}
            </span>
          </template>
          <template #name="{ row }">
            <Input
              v-if="!row.endStatus"
              v-model:value="row.name"
              placeholder="请输入状态名"
            />
            <span v-else>{{ row.name }}</span>
          </template>
          <template #percent="{ row }">
            <InputNumber
              v-if="!row.endStatus"
              v-model:value="row.percent"
              :min="0"
              :max="100"
              :precision="2"
              placeholder="请输入赢单率"
            />
            <span v-else>{{ row.percent }}</span>
          </template>
          <template #actions="{ row, rowIndex }">
            <TableAction
@@ -182,14 +170,12 @@
                {
                  label: $t('ui.actionTitle.create'),
                  type: 'link',
                  ifShow: () => !row.endStatus,
                  onClick: handleAddStatus,
                },
                {
                  label: $t('common.delete'),
                  type: 'link',
                  danger: true,
                  ifShow: () => !row.endStatus,
                  popConfirm: {
                    title: $t('ui.actionMessage.deleteConfirm', [row.name]),
                    confirm: deleteStatusArea.bind(null, row, rowIndex),
src/views/crm/contract/components/detail-list.vue
@@ -24,6 +24,9 @@
const props = defineProps<{
  bizId: number; // 业务编号
  bizType: number; // 业务类型
  customerId?: number; // 客户编号(商机/联系人详情传入)
  customerName?: string; // 客户名称(商机/联系人详情传入)
  businessName?: string; // 商机名称(商机详情传入)
}>();
const { push } = useRouter();
@@ -52,7 +55,12 @@
        ? {
            customerId: props.bizId,
          }
        : { businessId: props.bizId },
        : {
            businessId: props.bizId,
            customerId: props.customerId,
            customerName: props.customerName,
            businessName: props.businessName,
          },
    )
    .open();
}
@@ -77,7 +85,7 @@
              customerId: props.bizId,
              ...formValues,
            });
          } else if (props.bizType === BizTypeEnum.CRM_CONTACT) {
          } else if (props.bizType === BizTypeEnum.CRM_BUSINESS) {
            return await getContractPageByBusiness({
              pageNo: page.currentPage,
              pageSize: page.pageSize,
src/views/crm/contract/data.ts
@@ -66,6 +66,10 @@
      componentProps: {
        placeholder: '请选择客户',
      },
      dependencies: {
        triggerFields: ['customerId'],
        disabled: (values) => !!values.customerId,
      },
    },
    {
      fieldName: 'orderDate',
@@ -88,9 +92,15 @@
        placeholder: '请选择商机',
      },
      dependencies: {
        triggerFields: ['customerId'],
        disabled: (values) => !values.customerId,
        triggerFields: ['customerId', 'businessId'],
        disabled: (values) => !!values.businessId || !values.customerId,
        async componentProps(values) {
          if (values.businessId && values.businessName) {
            return {
              options: [{ label: values.businessName, value: values.businessId }],
              placeholder: '请选择商机',
            };
          }
          if (!values.customerId) {
            return {
              options: [],
src/views/crm/contract/modules/form.vue
@@ -90,6 +90,10 @@
    // 加载数据
    const data = modalApi.getData<CrmContractApi.Contract>();
    if (!data || !data.id) {
      // 新增时,回显从商机/客户详情传入的数据
      if (data) {
        await formApi.setValues(data);
      }
      return;
    }
    modalApi.lock();