银川
1.销售订单页面开发、联调
2.合同管理页面开发联调
3.项目代码相关配置修改
| | |
| | | export function exportSaleOrder(params: any) { |
| | | return requestClient.download('/erp/sale-order/export-excel', { params }); |
| | | } |
| | | |
| | | /** 作废销售订单 */ |
| | | export function cancelSaleOrder(id: number) { |
| | | return requestClient.put('/erp/sale-order/cancel', null, { |
| | | params: { id }, |
| | | }); |
| | | } |
| | | |
| | | /** 启用销售订单(恢复已作废订单) */ |
| | | export function enableSaleOrder(id: number) { |
| | | return requestClient.put('/erp/sale-order/enable', null, { |
| | | params: { id }, |
| | | }); |
| | | } |
| | |
| | | attrs.onCancel = popConfirm.cancel; |
| | | } |
| | | |
| | | // 不设置 getPopupContainer,让它默认挂载到 body,避免被遮挡 |
| | | |
| | | return attrs; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | .ant-popconfirm { |
| | | width: 210px; |
| | | |
| | | //.ant-popconfirm-message { |
| | | // white-space: nowrap; |
| | | //} |
| | | |
| | | .ant-popconfirm-buttons { |
| | | .ant-btn { |
| | | margin-inline-start: 4px !important; |
| | |
| | | cancel?: () => void; |
| | | icon?: string; |
| | | disabled?: boolean; |
| | | placement?: string; |
| | | getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement; |
| | | } |
| | | |
| | | export interface ActionItem extends ButtonProps { |
| | |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'auditStatus', |
| | | label: '合同状态', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '未提交', value: 0 }, |
| | | { label: '审批中', value: 10 }, |
| | | { label: '审核通过', value: 20 }, |
| | | { label: '审核不通过', value: 30 }, |
| | | { label: '已取消', value: 40 }, |
| | | { label: '已作废', value: 50 }, |
| | | ], |
| | | placeholder: '请选择合同状态', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'orderNo', |
| | | label: '关联订单', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请输入订单号', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | |
| | | field: 'no', |
| | | minWidth: 180, |
| | | fixed: 'left', |
| | | slots: { default: 'no' }, |
| | | }, |
| | | { |
| | | title: '合同名称', |
| | |
| | | label: '公司签约人', |
| | | }, |
| | | { |
| | | field: 'orderNo', |
| | | label: '销售订单', |
| | | slot: 'orderNo', // 使用 slot 自定义渲染 |
| | | }, |
| | | { |
| | | field: 'remark', |
| | | label: '备注', |
| | | }, |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmContractApi } from '#/api/crm/contract'; |
| | | |
| | | import { Divider } from 'ant-design-vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | import { Button, Divider } from 'ant-design-vue'; |
| | | |
| | | import { useDescription } from '#/components/description'; |
| | | import { useFollowUpDetailSchema } from '#/views/crm/followup/data'; |
| | | |
| | | import { useDetailBaseSchema } from '../data'; |
| | | |
| | | defineProps<{ |
| | | const props = defineProps<{ |
| | | contract: CrmContractApi.Contract; // 合同信息 |
| | | }>(); |
| | | |
| | | const router = useRouter(); |
| | | |
| | | const [BaseDescriptions] = useDescription({ |
| | | title: '基本信息', |
| | |
| | | class: 'mx-4', |
| | | schema: useFollowUpDetailSchema(), |
| | | }); |
| | | |
| | | /** 查看销售订单 */ |
| | | function handleViewOrder() { |
| | | if (props.contract.orderId) { |
| | | router.push({ |
| | | path: '/erp/sale/order', |
| | | query: { orderId: props.contract.orderId }, |
| | | }); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div> |
| | | <BaseDescriptions :data="contract" /> |
| | | <BaseDescriptions :data="contract"> |
| | | <template #orderNo="{ data }"> |
| | | <Button v-if="data.orderId" type="link" @click="handleViewOrder"> |
| | | {{ data.orderNo }} |
| | | </Button> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </BaseDescriptions> |
| | | <Divider /> |
| | | <SystemDescriptions :data="contract" /> |
| | | </div> |
| | |
| | | import { Page, useVbenModal } from '../../../packages/effects/common-ui/src'; |
| | | import { downloadFileFromBlobPart } from '../../../packages/utils/src'; |
| | | |
| | | import { Button, message, Modal, Select, Tabs, Tag } from 'ant-design-vue'; |
| | | import { Button, message, Modal, Select, Tabs, Tag, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | |
| | | {{ row.name }} |
| | | </Button> |
| | | </template> |
| | | <template #no="{ row }"> |
| | | <Tooltip v-if="row.auditStatus === 50" title="该合同已作废,订单已失效"> |
| | | <span class="text-red-500 cursor-pointer" @click="handleDetail(row)"> |
| | | {{ row.no }} |
| | | </span> |
| | | </Tooltip> |
| | | <Button v-else type="link" @click="handleDetail(row)"> |
| | | {{ row.no }} |
| | | </Button> |
| | | </template> |
| | | <template #customerName="{ row }"> |
| | | <Button type="link" @click="handleCustomerDetail(row)"> |
| | | {{ row.customerName }} |
| | |
| | | <Tag v-if="row.auditStatus === 10" color="warning">审批中</Tag> |
| | | <Tag v-if="row.auditStatus === 20" color="success">审核通过</Tag> |
| | | <Tag v-if="row.auditStatus === 30" color="error">审核不通过</Tag> |
| | | <Tag v-if="row.auditStatus === 40" color="default">已取消</Tag> |
| | | <Tag v-if="row.auditStatus === 50" color="error">已作废</Tag> |
| | | </template> |
| | | <template #orderNo="{ row }"> |
| | | <Button v-if="row.orderId" type="link" @click="handleViewOrder(row)"> |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { DICT_TYPE } from '../../../../packages/constants/src'; |
| | | import { getDictOptions } from '../../../../packages/effects/hooks/src'; |
| | | import { erpPriceInputFormatter } from '../../../../packages/utils/src'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | |
| | | label: '状态', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.ERP_AUDIT_STATUS, 'number'), |
| | | options: [ |
| | | { label: '未审核', value: 10 }, |
| | | { label: '已审核', value: 20 }, |
| | | { label: '已作废', value: 30 }, |
| | | ], |
| | | placeholder: '请选择状态', |
| | | allowClear: true, |
| | | }, |
| | |
| | | title: '订单单号', |
| | | width: 200, |
| | | fixed: 'left', |
| | | slots: { default: 'no' }, |
| | | }, |
| | | { |
| | | field: 'productNames', |
| | |
| | | { |
| | | field: 'status', |
| | | title: '状态', |
| | | minWidth: 120, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.ERP_AUDIT_STATUS }, |
| | | }, |
| | | minWidth: 100, |
| | | fixed: 'right', |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | title: '操作', |
| | |
| | | import { Page, useVbenModal } from '../../../../packages/effects/common-ui/src'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '../../../../packages/utils/src'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | import { message, Tag, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | cancelSaleOrder, |
| | | deleteSaleOrder, |
| | | enableSaleOrder, |
| | | exportSaleOrder, |
| | | getSaleOrderPage, |
| | | updateSaleOrderStatus, |
| | |
| | | try { |
| | | await updateSaleOrderStatus(row.id!, status); |
| | | message.success(`${status === 20 ? '审批' : '反审批'}成功`); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** 作废销售订单 */ |
| | | async function handleCancel(row: ErpSaleOrderApi.SaleOrder) { |
| | | const hideLoading = message.loading({ |
| | | content: '正在作废该订单...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await cancelSaleOrder(row.id!); |
| | | message.success('作废成功'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** 启用销售订单(恢复已作废订单) */ |
| | | async function handleEnable(row: ErpSaleOrderApi.SaleOrder) { |
| | | const hideLoading = message.loading({ |
| | | content: '正在启用该订单...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await enableSaleOrder(row.id!); |
| | | message.success('启用成功'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #no="{ row }"> |
| | | <Tooltip v-if="row.status === 30" title="该订单已作废,订单已失效"> |
| | | <span class="text-red-500 cursor-pointer" @click="handleDetail(row)"> |
| | | {{ row.no }} |
| | | </span> |
| | | </Tooltip> |
| | | <a v-else class="text-primary cursor-pointer" @click="handleDetail(row)"> |
| | | {{ row.no }} |
| | | </a> |
| | | </template> |
| | | <template #contractNo="{ row }"> |
| | | <a v-if="row.contractId" class="text-primary cursor-pointer" @click="handleViewContract(row)"> |
| | | {{ row.contractNo }} |
| | | </a> |
| | | <span v-else>-</span> |
| | | </template> |
| | | <template #status="{ row }"> |
| | | <Tag v-if="row.status === 10" color="warning">未审核</Tag> |
| | | <Tag v-if="row.status === 20" color="success">已审核</Tag> |
| | | <Tag v-if="row.status === 30" color="error">已作废</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['erp:sale-order:update'], |
| | | ifShow: () => row.status !== 20, |
| | | ifShow: () => row.status === 10, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: row.status === 10 ? '审批' : '反审批', |
| | | label: '审批', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['erp:sale-order:update-status'], |
| | | ifShow: () => row.status === 10, |
| | | popConfirm: { |
| | | title: `确认${row.status === 10 ? '审批' : '反审批'}${row.no}吗?`, |
| | | confirm: handleUpdateStatus.bind( |
| | | null, |
| | | row, |
| | | row.status === 10 ? 20 : 10, |
| | | ), |
| | | title: `确认审批${row.no}吗?`, |
| | | confirm: handleUpdateStatus.bind(null, row, 20), |
| | | }, |
| | | }, |
| | | { |
| | | label: '反审批', |
| | | type: 'link', |
| | | icon: ACTION_ICON.AUDIT, |
| | | auth: ['erp:sale-order:update-status'], |
| | | ifShow: () => row.status === 20, |
| | | popConfirm: { |
| | | title: `确认反审批${row.no}吗?`, |
| | | confirm: handleUpdateStatus.bind(null, row, 10), |
| | | }, |
| | | }, |
| | | { |
| | | label: '作废', |
| | | type: 'link', |
| | | icon: 'ant-design:stop-outlined', |
| | | auth: ['erp:sale-order:cancel'], |
| | | ifShow: () => row.status === 20, |
| | | popConfirm: { |
| | | title: `确认作废${row.no}吗?作废后不可恢复!`, |
| | | confirm: handleCancel.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | | label: '启用', |
| | | type: 'link', |
| | | icon: 'ant-design:check-circle-outlined', |
| | | auth: ['erp:sale-order:enable'], |
| | | ifShow: () => row.status === 30, |
| | | popConfirm: { |
| | | title: `确认启用${row.no}吗?`, |
| | | confirm: handleEnable.bind(null, row), |
| | | }, |
| | | }, |
| | | { |
| | |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['erp:sale-order:delete'], |
| | | ifShow: () => row.status === 10, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.no]), |
| | | confirm: handleDelete.bind(null, [row.id!]), |
| | |
| | | <Grid class="w-full"> |
| | | <template #productId="{ row }"> |
| | | <Select |
| | | v-if="!disabled" |
| | | v-model:value="row.productId" |
| | | :options="productOptions" |
| | | :field-names="{ label: 'name', value: 'id' }" |
| | |
| | | show-search |
| | | @change="handleProductChange($event, row)" |
| | | /> |
| | | <span v-else>{{ row.productName || '-' }}</span> |
| | | </template> |
| | | <template #count="{ row }"> |
| | | <InputNumber |
| | |
| | | }, |
| | | server: { |
| | | allowedHosts: true, |
| | | watch: { |
| | | ignored: ['**/node_modules/**', '**/dist/**', '**/.git/**'], |
| | | }, |
| | | proxy: { |
| | | '/admin-api': { |
| | | changeOrigin: true, |