diff --git a/.env b/.env index 41552c8f6..ed600aacc 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ VITE_APP_TITLE=暖界办公 # 项目本地运行端口号 -VITE_PORT=81 +VITE_PORT=80 # open 运行 npm run dev 时自动打开浏览器 VITE_OPEN=true diff --git a/.env.dev b/.env.dev index f4ae32dc9..d1087686c 100644 --- a/.env.dev +++ b/.env.dev @@ -34,4 +34,4 @@ VITE_MALL_H5_DOMAIN='http://8.130.12.151' VITE_APP_CAPTCHA_ENABLE=false # GoView域名 -VITE_GOVIEW_URL='http://127.0.0.1:3000' \ No newline at end of file +VITE_GOVIEW_URL='http://8.130.12.151:3000' \ No newline at end of file diff --git a/.env.local b/.env.local index 925808d83..0af2b7fc0 100644 --- a/.env.local +++ b/.env.local @@ -4,7 +4,7 @@ NODE_ENV=development VITE_DEV=true # 请求路径 -VITE_BASE_URL='http://172.22.3.6:48080' +VITE_BASE_URL='http://127.0.0.1:48080' # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务 VITE_UPLOAD_TYPE=server diff --git a/.env.test b/.env.test index 2252e146d..e911da88a 100644 --- a/.env.test +++ b/.env.test @@ -4,7 +4,7 @@ NODE_ENV=production VITE_DEV=false # 请求路径 -VITE_BASE_URL='http://localhost:48080' +VITE_BASE_URL='http://172.22.3.168:48080' # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 VITE_UPLOAD_TYPE=server diff --git a/src/api/crm/business/index.ts b/src/api/crm/business/index.ts index 5361cdb59..4c748e345 100644 --- a/src/api/crm/business/index.ts +++ b/src/api/crm/business/index.ts @@ -61,6 +61,11 @@ export const getSimpleBusinessList = async () => { return await request.get({ url: `/crm/business/simple-all-list` }) } +// 获得 CRM 我的商机列表 +export const getSelfSimpleBusinessList = async () => { + return await request.get({ url: `/crm/business/self-simple-list` }) +} + // 新增 CRM 商机 export const createBusiness = async (data: BusinessVO) => { return await request.post({ url: `/crm/business/create`, data }) diff --git a/src/api/crm/business/status/index.ts b/src/api/crm/business/status/index.ts index cddaa5a2c..dfd8a1132 100644 --- a/src/api/crm/business/status/index.ts +++ b/src/api/crm/business/status/index.ts @@ -15,7 +15,7 @@ export const DEFAULT_STATUSES = [ { endStatus: 1, key: '结束', - name: '赢单', + name: '成交', percent: 100 }, { diff --git a/src/api/crm/contract/index.ts b/src/api/crm/contract/index.ts index a25d7c403..bbff82253 100644 --- a/src/api/crm/contract/index.ts +++ b/src/api/crm/contract/index.ts @@ -78,6 +78,11 @@ export const getContract = async (id: number) => { return await request.get({ url: `/crm/contract/get?id=` + id }) } +// 查询 CRM 合同详情 +export const getChangeContract = async (id: number) => { + return await request.get({ url: `/crm/contract/getChangeContract?contractChangeId=` + id }) +} + // 查询 CRM 合同下拉列表 export const getContractSimpleList = async (customerId: number) => { return await request.get({ @@ -115,6 +120,11 @@ export const transferContract = async (data: TransferReqVO) => { return await request.put({ url: '/crm/contract/transfer', data }) } +// 合同变更 +export const changeContract = async (data: TransferReqVO) => { + return await request.put({ url: '/crm/contract/changeContract', data }) +} + // 获得待审核合同数量 export const getAuditContractCount = async () => { return await request.get({ url: '/crm/contract/audit-count' }) @@ -125,6 +135,16 @@ export const getRemindContractCount = async () => { return await request.get({ url: '/crm/contract/remind-count' }) } +// 合作主主体 +export const getOrg = async (params) => { + return await request.get({ url: '/system/organizations/page', params }) +} + +// 合作主主体详情 +export const getOrgInfo = async (params) => { + return await request.get({ url: '/system/organizations/get?id=' + params }) +} + // ==================== 子表(CRM 合同产品关联) ==================== // 获得CRM 合同产品关联列表 @@ -151,3 +171,8 @@ export const getContractAAuthorizedPersonListByContractId = async (contractId) = export const getContractBAuthorizedPersonListByContractId = async (contractId) => { return await request.get({ url: `/crm/contract/contract-B-authorized-person/list-by-contract-id?contractId=` + contractId }) } + +// 获得合同乙方授权人信息列表 +export const quotationTimes = async (contractId) => { + return await request.get({ url: `/crm/contract/quotationTimes?id=` + contractId }) +} \ No newline at end of file diff --git a/src/api/crm/customer/index.ts b/src/api/crm/customer/index.ts index d149d4e78..45e396098 100644 --- a/src/api/crm/customer/index.ts +++ b/src/api/crm/customer/index.ts @@ -29,6 +29,57 @@ export interface CustomerVO { creatorName?: string // 创建人名称 createTime: Date // 创建时间 updateTime: Date // 更新时间 + + + cooperationType?: number // 合作类型 + cooperationArea?: number // 合作地区 + leadSource?: number // 线索来源 + customerStatus?: number // 客户状态 + dataType?: number // 是否为公海数据 + serviceStatus?: string // 经营状态 + developer?: number // 商务拓展人 + contractor?: number // 商务签约人 + clueDeveloper?: number // 线索拓展人 + maintainer?: number // 售后维护人 + assist?: number // 协助人 + customerOwner?: number // 客户归属人 + website?: string // 网站 + contactAddress?: string // 通讯地址 + customerDetails?: string // 客户详情 + rejectionReason?: string // 客户退回原因 + claim?: number // 是否领取 + claimTime?: Date // 领取时间 + startDate?: string // 成立日期 + registerCapital?: string // 注册资本 + legalPersonName?: string // 法定代表人 + actualCapital?: string // 实缴注册资本 + registerCapitalCurrency?: string // 注册资本币种 + bankName?: string // 开户行名称 + bankAccount?: string // 银行账号 + taxQualification?: string // 纳税人资质 + socialEmployeeNum?: string // 参保人数 + creditNo?: string // 社会统一信用代码 + businessTerm?: string // 营业期限 + belongOrg?: string // 登记机关 + regType?: string // 公司类型 + actualCharacters?: string // 实缴字符数 + registerNo?: string // 工商注册号 + registeredAddress?: string // 注册地址 + businessScope?: string // 经营范围 + partnerTotal?: string // 股东数量 + changeRecordDataTotal?: string // 变更数量 + employeeDataTotal?: string // 董事会成员数量 + attention?: number // 是否关注(1关注,0不关注) + creditAmount?: number // 授信额度 + accountPeriod?: number // 账期(天) + creditGrantingMethod?: number // 授信方式 + creditCalculationCycle?: number // 授信计算周期 + equityPledge?: number // 股权出质 + judgmentRecord?: number // 被执行记录 + defendantRecord?: number // 被告记录 + dishonestyRecord?: number // 失信记录 + abnormalService?: number // 经营异常 + financeRecord?: number // 融资记录 } // 查询客户列表 @@ -101,6 +152,16 @@ export const getCustomerSimpleList = async () => { return await request.get({ url: `/crm/customer/simple-list` }) } +// 我的客户列表 +export const getSelfCustomerSimpleList = async () => { + return await request.get({ url: `/crm/customer/self-simple-list` }) +} + +// 模糊查询公司 +export const getCompanyList = async (params) => { + return await request.get({ url: `/crm/customer/fuzzyQueryCompany`, params }) +} + // ======================= 业务操作 ======================= // 客户转移 diff --git a/src/api/crm/permission/index.ts b/src/api/crm/permission/index.ts index 4f88b14fc..9352abbba 100644 --- a/src/api/crm/permission/index.ts +++ b/src/api/crm/permission/index.ts @@ -34,7 +34,8 @@ export enum BizTypeEnum { CRM_CONTRACT = 5, // 合同 CRM_PRODUCT = 6, // 产品 CRM_RECEIVABLE = 7, // 回款 - CRM_RECEIVABLE_PLAN = 8 // 回款计划 + CRM_RECEIVABLE_PLAN = 8, // 回款计划 + CRM_QUOTATION = 9 // 报价 } /** diff --git a/src/api/crm/quotation/index.ts b/src/api/crm/quotation/index.ts index 4fe63d92c..1c7f77da4 100644 --- a/src/api/crm/quotation/index.ts +++ b/src/api/crm/quotation/index.ts @@ -65,6 +65,11 @@ export const QuotationApi = { return await request.download({ url: `/crm/quotation/export-excel`, params }) }, + // 提交审核 + submitContract: async (id: number) => { + return await request.put({ url: `/crm/quotation/submit?id=${id}` }) + }, + // ==================== 子表(CRM 报价产品关联) ==================== // 获得CRM 报价产品关联列表 diff --git a/src/api/crm/statistics/funnel.ts b/src/api/crm/statistics/funnel.ts index 574a5f4f7..c5ede85ef 100644 --- a/src/api/crm/statistics/funnel.ts +++ b/src/api/crm/statistics/funnel.ts @@ -3,7 +3,7 @@ import request from '@/config/axios' export interface CrmStatisticFunnelRespVO { customerCount: number // 客户数 businessCount: number // 商机数 - businessWinCount: number // 赢单数 + businessWinCount: number // 成交数 } export interface CrmStatisticsBusinessSummaryByDateRespVO { @@ -15,7 +15,7 @@ export interface CrmStatisticsBusinessSummaryByDateRespVO { export interface CrmStatisticsBusinessInversionRateSummaryByDateRespVO { time: string // 时间 businessCount: number // 商机数量 - businessWinCount: number // 赢单商机数 + businessWinCount: number // 成交商机数 } // 客户分析 API diff --git a/src/components/contact/index.vue b/src/components/contact/index.vue new file mode 100644 index 000000000..0257d50d1 --- /dev/null +++ b/src/components/contact/index.vue @@ -0,0 +1,158 @@ + + + diff --git a/src/components/user/index.vue b/src/components/user/index.vue new file mode 100644 index 000000000..bd60dccfe --- /dev/null +++ b/src/components/user/index.vue @@ -0,0 +1,158 @@ + + + diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 416bb4570..cbb0c0ef4 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -541,7 +541,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ title: '票据模版新增', noCache: true, hidden: true, - activeMenu: '/crm/business' + activeMenu: '/crm/bill-template' }, component: () => import('@/views/crm/billtemplate/BillTemplateForm.vue') }, @@ -552,18 +552,19 @@ const remainingRouter: AppRouteRecordRaw[] = [ title: '票据模版编辑', noCache: true, hidden: true, - activeMenu: '/crm/business' + activeMenu: '/crm/bill-template' }, component: () => import('@/views/crm/billtemplate/BillTemplateForm.vue') }, { - path: 'business/quotationAdd', + path: 'quotation/QuotationForm', name: 'QuotationAdd', meta: { title: '方案报价新增', noCache: true, + canTo: true, hidden: true, - activeMenu: '/crm/business' + activeMenu: '/crm/quotation' }, component: () => import('@/views/crm/quotation/QuotationForm.vue') }, @@ -574,18 +575,19 @@ const remainingRouter: AppRouteRecordRaw[] = [ title: '方案报价编辑', noCache: true, hidden: true, - activeMenu: '/crm/business' + activeMenu: '/crm/quotation' }, component: () => import('@/views/crm/quotation/QuotationForm.vue') }, { - path: 'business/quotationDetail', + path: 'quotation/QuotationDetail', name: 'QuotationDetail', meta: { title: '方案报价详情', noCache: true, + canTo: true, hidden: true, - activeMenu: '/crm/business' + activeMenu: '/crm/quotation' }, component: () => import('@/views/crm/quotation/QuotationDetail.vue') }, @@ -612,11 +614,57 @@ const remainingRouter: AppRouteRecordRaw[] = [ component: () => import('@/views/crm/business/BusinessForm.vue') }, { - path: 'contract/detail/:id', + path: 'contract/add', + name: 'CrmContractAdd', + meta: { + title: '合同新增', + noCache: true, + hidden: true, + activeMenu: '/crm/contract' + }, + component: () => import('@/views/crm/contract/ContractForm.vue') + }, + { + path: 'contract/edit', + name: 'CrmContractEdit', + meta: { + title: '合同编辑', + noCache: true, + hidden: true, + activeMenu: '/crm/contract' + }, + component: () => import('@/views/crm/contract/ContractForm.vue') + }, + { + path: 'contract/ContractChange', + name: 'CrmContractChange', + meta: { + title: '合同变更', + noCache: true, + hidden: true, + activeMenu: '/crm/contract' + }, + component: () => import('@/views/crm/contract/ContractChange.vue') + }, + { + path: 'contract/detail/ContractChangeDetail', + name: 'CrmContractChangeDetail', + meta: { + title: '合同变更详情', + noCache: true, + canTo: true, + hidden: true, + activeMenu: '/crm/contract' + }, + component: () => import('@/views/crm/contract/detail/ContractChangeDetail.vue') + }, + { + path: 'contract/detail/index', name: 'CrmContractDetail', meta: { title: '合同详情', noCache: true, + canTo: true, hidden: true, activeMenu: '/crm/contract' }, diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 37cbdb119..e514ff2b7 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -225,6 +225,7 @@ export enum DICT_TYPE { CRM_RETURN_VISIT_STSTUS = "crm_return_visit_type", //CRM 回访类型 CRM_COMPLAINT_METHOD = "crm_complaint_method", // 投诉方式 CRM_COMPLAINT_LEVEL = "crm_complaint_level", // 投诉级别 + TECH_SUPPORT = "tech_support", // 是否 // 商机账期 PAYMENT_TERM = "payment_term", // 投诉级别 diff --git a/src/views/Home/Index.vue b/src/views/Home/Index.vue index 199ed09e7..1943566af 100644 --- a/src/views/Home/Index.vue +++ b/src/views/Home/Index.vue @@ -1,339 +1,11 @@ diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 58b98ea14..16b0425ee 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -116,8 +116,8 @@ - {{ t('login.otherLogin') }} - + + diff --git a/src/views/bpm/task/todo/index.vue b/src/views/bpm/task/todo/index.vue index 45a2eb449..9c0df6b7d 100644 --- a/src/views/bpm/task/todo/index.vue +++ b/src/views/bpm/task/todo/index.vue @@ -148,7 +148,7 @@ prop="processInstanceId" :show-overflow-tooltip="true" /> - + \ No newline at end of file diff --git a/src/views/crm/contract/detail/ContractChangeDetail.vue b/src/views/crm/contract/detail/ContractChangeDetail.vue new file mode 100644 index 000000000..2e13f3ea1 --- /dev/null +++ b/src/views/crm/contract/detail/ContractChangeDetail.vue @@ -0,0 +1,428 @@ + + diff --git a/src/views/crm/contract/detail/ContractDetail.vue b/src/views/crm/contract/detail/ContractDetail.vue new file mode 100644 index 000000000..60d3d8806 --- /dev/null +++ b/src/views/crm/contract/detail/ContractDetail.vue @@ -0,0 +1,842 @@ + + diff --git a/src/views/crm/contract/detail/index.vue b/src/views/crm/contract/detail/index.vue index 9d5e14ca4..feaca2572 100644 --- a/src/views/crm/contract/detail/index.vue +++ b/src/views/crm/contract/detail/index.vue @@ -1,73 +1,66 @@ diff --git a/src/views/crm/customer/CustomerForm.vue b/src/views/crm/customer/CustomerForm.vue index 561082a76..c48e8a9b2 100644 --- a/src/views/crm/customer/CustomerForm.vue +++ b/src/views/crm/customer/CustomerForm.vue @@ -10,14 +10,26 @@ - + + + - + @@ -58,7 +70,7 @@ - + - - - - - - - - - - + + + + + + + + + + + + + @@ -112,10 +122,8 @@ - - - + + - - + + + + - - + + + - - - - + + - - + + + + + + + + + + + + + + + - --> - + + + + + @@ -225,6 +288,7 @@ import * as AreaApi from '@/api/system/area' import { defaultProps } from '@/utils/tree' import * as UserApi from '@/api/system/user' import { useUserStore } from '@/store/modules/user' +import { json } from 'stream/consumers' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -238,6 +302,7 @@ const userOptions = ref([]) // 用户列表 const formData = ref({ id: undefined, name: undefined, + startDate: undefined, contactNextTime: undefined, ownerUserId: 0, mobile: undefined, @@ -252,8 +317,14 @@ const formData = ref({ source: undefined, remark: undefined, developer: undefined, - assist: undefined, + assist: [], + creditNo: undefined, clueDeveloper: undefined, + serviceStatus: undefined, + legalPersonName: undefined, + registerCapital: undefined, + website: undefined, + registeredAddress: undefined, }) const formRules = reactive({ name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }], @@ -261,6 +332,7 @@ const formRules = reactive({ developer: [{ required: true, message: '商务拓展人不能为空', trigger: 'change' }], cooperationType: [{ required: true, message: '合作类型不能为空', trigger: 'change' }], cooperationArea: [{ required: true, message: '合作地区不能为空', trigger: 'change' }], + website: [{ required: true, message: '网站不能为空', trigger: 'change' }], }) const formRef = ref() // 表单 Ref @@ -278,7 +350,8 @@ const open = async (type: string, id?: number) => { } finally { formLoading.value = false } - } + } + restaurants.value = await CustomerApi.getCompanyList({companyName: '小米科技有限责任公司'}) // 获得地区列表 areaList.value = await AreaApi.getAreaTree() // 获得用户列表 @@ -287,7 +360,7 @@ const open = async (type: string, id?: number) => { if (formType.value === 'create') { formData.value.ownerUserId = useUserStore().getUser.id formData.value.developer = useUserStore().getUser.id - formData.value.assist = useUserStore().getUser.id + // formData.value.assist = useUserStore().getUser.id } } @@ -319,11 +392,54 @@ const submitForm = async () => { } } +// const loadAll = async (val) => { +// restaurants.value = await CustomerApi.getCompanyList({ +// companyName: val +// }) +// } + +interface RestaurantItem { + value: string + link: string +} +let timeout: ReturnType +const restaurants = ref([]) +const querySearchAsync = async (queryString: string, cb: (arg: any) => void) => { + let data = await CustomerApi.getCompanyList({ + companyName: queryString + }) + restaurants.value = data.list.map(v => { + return Object.assign(v, {value: v.name}) + }) + const results = queryString + ? restaurants.value.filter(createFilter(queryString)) + : restaurants.value + + clearTimeout(timeout) + timeout = setTimeout(() => { + cb(results) + }, 3000 * Math.random()) +} +const createFilter = (queryString: string) => { + return (restaurant: RestaurantItem) => { + return ( + restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0 + ) + } +} + +const handleSelect = (item: Record) => { + formData.value.legalPersonName = item.legalPersonName + formData.value.registerCapital = item.regCapital + formData.value.startDate = item.regDate +} /** 重置表单 */ const resetForm = () => { formData.value = { id: undefined, name: undefined, + regCapital: undefined, + regDate: undefined, contactNextTime: undefined, ownerUserId: 0, mobile: undefined, @@ -338,7 +454,7 @@ const resetForm = () => { source: undefined, reamark: undefined, developer: undefined, - assist: undefined, + assist: [], clueDeveloper: undefined, } formRef.value?.resetFields() diff --git a/src/views/crm/customer/detail/CustomerDetailsInfo.vue b/src/views/crm/customer/detail/CustomerDetailsInfo.vue index fe240b9ba..c82b5c9f9 100644 --- a/src/views/crm/customer/detail/CustomerDetailsInfo.vue +++ b/src/views/crm/customer/detail/CustomerDetailsInfo.vue @@ -21,6 +21,9 @@ {{ customer.clueDeveloperName }} {{ customer.assistName }} {{ customer.industryId }} + {{ customer.maintainerName }} + {{ customer.contractorName }} + {{ customer.creditNo }} {{ customer.mobile }} {{ customer.telephone }} {{ customer.email }} diff --git a/src/views/crm/customer/detail/index.vue b/src/views/crm/customer/detail/index.vue index 05c2d48b0..50ed13220 100644 --- a/src/views/crm/customer/detail/index.vue +++ b/src/views/crm/customer/detail/index.vue @@ -63,6 +63,9 @@ + + + @@ -95,6 +98,7 @@ import ReturnVisitrecord from './returnvisitrecord/index.vue' // 回访 import ContactList from '@/views/crm/contact/components/ContactList.vue' // 联系人列表 import ContractList from '@/views/crm/contract/components/ContractList.vue' // 合同列表 import BusinessList from '@/views/crm/business/components/BusinessList.vue' // 商机列表 +import QuotationList from '@/views/crm/contract/components/QuotationList.vue' // 报价列表 import ReceivableList from '@/views/crm/receivable/components/ReceivableList.vue' // 回款列表 import ReceivablePlanList from '@/views/crm/receivable/plan/components/ReceivablePlanList.vue' // 回款计划列表 import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 团队成员列表(权限) diff --git a/src/views/crm/customer/detail/returnvisitrecord/ReturnVisitRecordForm.vue b/src/views/crm/customer/detail/returnvisitrecord/ReturnVisitRecordForm.vue index d3103677c..4f8327633 100644 --- a/src/views/crm/customer/detail/returnvisitrecord/ReturnVisitRecordForm.vue +++ b/src/views/crm/customer/detail/returnvisitrecord/ReturnVisitRecordForm.vue @@ -12,7 +12,7 @@ - 新增 + + 写回访 @@ -26,7 +25,19 @@ width="180px" /> - + + + { } } +const previewFile = (fileUrls) => { + // 假设 fileUrls 是一个字符串,包含文件的完整 URL + if (!fileUrls) { + message.error('没有附件'); + return; + } + + // 检查文件类型 + const fileExtension = fileUrls.split('.').pop().toLowerCase(); + switch (fileExtension) { + case 'pdf': + // 预览 PDF 文件 + window.open(fileUrls, '_blank'); + break; + case 'xlsx': + case 'xls': + // 预览 Excel 文件 + window.open(fileUrls, '_blank'); + break; + case 'doc': + case 'docx': + // 预览 Word 文件 + window.open(fileUrls, '_blank'); + break; + default: + message.error('不支持的文件类型'); + break; + } +}; + /** 初始化 **/ onMounted(() => { getList() diff --git a/src/views/crm/customer/index.vue b/src/views/crm/customer/index.vue index 86bddc0e8..bad06b5da 100644 --- a/src/views/crm/customer/index.vue +++ b/src/views/crm/customer/index.vue @@ -113,7 +113,7 @@ - + - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/views/crm/quotation/QuotationForm.vue b/src/views/crm/quotation/QuotationForm.vue index 02025e7d1..84eb1a28b 100644 --- a/src/views/crm/quotation/QuotationForm.vue +++ b/src/views/crm/quotation/QuotationForm.vue @@ -8,15 +8,11 @@ v-loading="formLoading" > - - - - - + - + + + + + + - + 风控信息 + + + + + + + + + + + + + + + - + - + + + - - + + - + - + - - + + - - + + - - + + - + - - + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + + 需求信息 - + - - + + - - + + - - + + - + + @@ -241,7 +265,7 @@ - + @@ -300,7 +324,7 @@ - + + + + + + + @@ -344,7 +374,7 @@ - +
@@ -359,16 +389,18 @@ import { QuotationApi, QuotationVO } from '@/api/crm/quotation' import { defaultProps, handleTree } from '@/utils/tree' import { BillTemplateApi, BillTemplateVO } from '@/api/crm/billtemplate' import QuotationProductForm from './components/QuotationProductForm.vue' +import * as ContractApi from '@/api/crm/contract' import * as CustomerApi from '@/api/crm/customer' import * as UserApi from '@/api/system/user' import * as DeptApi from '@/api/system/dept' import * as BusinessApi from '@/api/crm/business' -import {BillTemplateApi } from '@/api/crm/billtemplate' -import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils' +import { propTypes } from '@/utils/propTypes' /** CRM 方案报价 表单 */ defineOptions({ name: 'QuotationForm' }) - +const props = defineProps({ + id: propTypes.number.def(undefined), +}) const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 const customerList = ref([]) // 客户列表的数据 @@ -377,6 +409,8 @@ const templateOptions = ref([]) const businessList = ref([]) const deptTree = ref() // 部门树形结构 const deptList = ref() // 部门 +const orgList = ref([]) +const handleType = ref('') const invoiceTemplateList = ref([]) const { proxy }: any = getCurrentInstance(); @@ -430,13 +464,29 @@ const formData = ref({ bBankAccount: undefined, // 银行账号 bLegalRepresentative: undefined, // 法人代表 bBusinessLicenseNumber: undefined, // 营业执照号 - bBusinessLicense: undefined // 营业执照 + bBusinessLicense: undefined, // 营业执照 + creditAmount: undefined, + creditLimitNum: undefined, + quotationTimes:undefined, }) const formRules = reactive({ no: [{ required: true, message: '报价单编号不能为空', trigger: 'blur' }], customerId: [{ required: true, message: '客户id不能为空', trigger: 'change' }], businessId: [{ required: true, message: '商机编号不能为空', trigger: 'change' }], - invoiceTemplateId: [{ required: true, message: '票据模板Id不能为空', trigger: 'change' }] + invoiceTemplateId: [{ required: true, message: '票据模板Id不能为空', trigger: 'change' }], + actualCapital: [{ required: true, message: '实缴资金不能为空', trigger: 'blur' }], + socialEmployeeNum: [{ required: true, message: '参保人数不能为空', trigger: 'blur' }], + defendantRecord: [{ required: true, message: '被告记录不能为空', trigger: 'blur' }], + abnormalService: [{ required: true, message: '经营异常不能为空', trigger: 'blur' }], + equityPledge: [{ required: true, message: '股权出质不能为空', trigger: 'blur' }], + dishonestyRecord: [{ required: true, message: '失信记录不能为空', trigger: 'blur' }], + financeRecord: [{ required: true, message: '融资记录不能为空', trigger: 'blur' }], + judgmentRecord: [{ required: true, message: '被执行记录不能为空', trigger: 'blur' }], + paymentTerm: [{ required: true, message: '账期不能为空', trigger: 'change' }], + partnerCompanyId: [{ required: true, message: '合作主体不能为空', trigger: 'change' }], + creditMethod: [{ required: true, message: '授信方式不能为空', trigger: 'change' }], + creditCalcCycle: [{ required: true, message: '授信计算周期不能为空', trigger: 'change' }], + quotationTimes: [{ required: true, message: '第几次报价不能为空', trigger: 'change' }], }) const formRef = ref() // 表单 Ref @@ -446,6 +496,8 @@ const quotationProductFormRef = ref() const onBusinessChange = async (businessId: string) => { if (!businessId) return + + handleType.value = 1 try { formLoading.value = true; const res = await BusinessApi.getBusiness(businessId); @@ -473,6 +525,10 @@ const onCustomerChange = async (customerId: string) => { try { formLoading.value = true; const customerRes = await CustomerApi.getCustomer(customerId); + formData.value.actualCapital = customerRes.actualCapital + formData.value.socialEmployeeNum = customerRes.socialEmployeeNum + formData.value.startDate = customerRes.startDate + formData.value.actualCapital = customerRes.actualCapital formData.value.cooperationType = customerRes.cooperationType; formData.value.companyType = customerRes.companyType; formData.value.listingStatus = customerRes.listingStatus; @@ -488,6 +544,7 @@ const onCustomerChange = async (customerId: string) => { formData.value.dishonestRecord = customerRes.dishonestRecord; formData.value.financingRecord = customerRes.financingRecord; formData.value.enforcementRecord = customerRes.enforcementRecord; + formData.value.creditAmount = customerRes.creditAmount || 0; } catch (err) { console.error('获取客户详情失败:', err); } finally { @@ -499,18 +556,22 @@ const onPartnerChange = async (id: string) => { if (!id) return try { formLoading.value = true; - const res = await DeptApi.getDept(id); - formData.value.bBankName = res.bankName; - formData.value.bBankAccount = res.bankAccount; - formData.value.bLegalRepresentative = res.legalRepresentative; - formData.value.bBusinessLicenseNumber = res.businessLicenseNumber; - formData.value.bBusinessLicense = res.businessLicense; + const res = await ContractApi.getOrgInfo(id); + formData.value.bankName = res.bankName; + formData.value.bankAccount = res.bankAccount; + formData.value.legalRepresentative = res.legalRepresentative; + formData.value.businessLicenseNumber = res.businessLicenseNumber; + formData.value.businessLicense = res.businessLicense; + // formData.value.partnerCompanyId = res.partnerCompanyId; } catch (err) { } finally { formLoading.value = false; } } +const changeNum = (val) => { + formData.value.creditLimit = (Number(val) + (formData.value.creditAmount || 0)).toFixed(2) +} /** 打开弹窗 */ const open = async (type: string) => { formType.value = type @@ -565,6 +626,11 @@ const submitForm = async () => { } +const changeTemplate = async() => { + handleType.value = 1 + console.log('%csrc/views/crm/quotation/QuotationForm.vue:631 handleType.value,222', 'color: #007acc;', handleType.value,222); +} + const goBack = ()=> { proxy.$router.go(-1) } @@ -602,13 +668,12 @@ const resetForm = () => { const route = useRoute(); onMounted(async () => { - console.log('%csrc/views/crm/quotation/QuotationForm.vue:596 route', 'color: #007acc;', route); - formType.value = route.query.id; + formType.value = props.id || route.query.id; if (formType.value) open(formType.value) // 获得客户列表 - customerList.value = await CustomerApi.getCustomerSimpleList() + customerList.value = await CustomerApi.getSelfCustomerSimpleList() // 获得用户列表 userOptions.value = await UserApi.getSimpleUserList() //票据 @@ -617,8 +682,13 @@ onMounted(async () => { pageSize: 1000, }) templateOptions.value = data.list - businessList.value = await BusinessApi.getSimpleBusinessList() + businessList.value = await BusinessApi.getSelfSimpleBusinessList() // 获得部门树 deptTree.value = handleTree(await DeptApi.getSimpleDeptList()) + const org = await ContractApi.getOrg({ + pageNo: 1, + pageSize: 1000 + }) + orgList.value = org.list }); - \ No newline at end of file + diff --git a/src/views/crm/quotation/components/QuotationProductDetail.vue b/src/views/crm/quotation/components/QuotationProductDetail.vue index a5e105cfe..b837d1c9c 100644 --- a/src/views/crm/quotation/components/QuotationProductDetail.vue +++ b/src/views/crm/quotation/components/QuotationProductDetail.vue @@ -62,28 +62,57 @@ - + - + @@ -103,7 +132,9 @@ import * as BusinessApi from '@/api/crm/business' const props = defineProps<{ quotationId: undefined, // 报价编号(主表的关联字段) businessId: undefined, - billTemplateId: undefined + billTemplateId: undefined, + products: undefined + }>() const formLoading = ref(false) // 表单的加载中 const formData = ref([]) @@ -120,57 +151,21 @@ const formRules = reactive({ const formRef = ref() // 表单 Ref /** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.businessId, - async (val) => { - // 1. 重置表单 - formData.value = [] - // 2. val 非空,则加载数据 - if (!val) { - return; - } - try { - formLoading.value = true - // if(val.quotationId) { - // formData.value = await QuotationApi.getQuotationProductListByQuotationId(val.quotationId) - // } else if(val.businessId) { - const business = await BusinessApi.getBusiness(val); - formData.value = business.products - // } - } finally { - formLoading.value = false - } - }, - { immediate: true } -) watch( - () => props.billTemplateId, - async (val) => { - // 1. 重置表单 - formData.value = [] - // 2. val 非空,则加载数据 - if (!val) { + () => props.products, + (val) => { + if (!val || val.length === 0) { return; } - try { - formLoading.value = true - // if(val.quotationId) { - // formData.value = await QuotationApi.getQuotationProductListByQuotationId(val.quotationId) - // } else if(val.businessId) { - const business = await BillTemplateApi.getTemplateProduct({ - businessId: props.businessId, - billTemplateId: val, - }); - console.log('%csrc/views/crm/quotation/components/QuotationProductForm.vue:167 business.data', 'color: #007acc;', business.data); - formData.value = business - // } - } finally { - formLoading.value = false - } + nextTick(() => { + formData.value = val + console.log('%csrc/views/crm/quotation/components/QuotationProductDetail.vue:134 val', 'color: #007acc;', val); + }) }, { immediate: true } -) + +); /** 新增按钮操作 */ const handleAdd = () => { diff --git a/src/views/crm/quotation/components/QuotationProductForm.vue b/src/views/crm/quotation/components/QuotationProductForm.vue index 9307087ba..b31728904 100644 --- a/src/views/crm/quotation/components/QuotationProductForm.vue +++ b/src/views/crm/quotation/components/QuotationProductForm.vue @@ -8,12 +8,13 @@ :inline-message="true" > - - + + @@ -31,10 +32,10 @@ - + - + - + - + - +