pull/781/head
zy 2025-05-09 21:11:10 +08:00
parent 6e82fc67bb
commit 747be37cea
9 changed files with 221 additions and 101 deletions

View File

@ -75,6 +75,11 @@ export const QuotationApi = {
return await request.put({ url: `/crm/quotation/submit?id=${id}` })
},
// 客户确认
enterQuotation: async (data: QuotationVO) => {
return await request.post({ url: `/crm/quotation/customer-confirm`, data })
},
// ==================== 子表CRM 报价产品关联) ====================
// 获得CRM 报价产品关联列表

View File

@ -202,6 +202,7 @@ export enum DICT_TYPE {
// ========== CRM - 客户管理模块 ==========
CRM_AUDIT_STATUS = 'crm_audit_status', // CRM 审批状态
CRM_CONFIRM_STATUS = 'crm_confirm_status', // CRM 客户确认状态
CRM_BIZ_TYPE = 'crm_biz_type', // CRM 业务类型
CRM_BUSINESS_END_STATUS_TYPE = 'crm_business_end_status_type', // CRM 商机结束状态类型
CRM_RECEIVABLE_RETURN_TYPE = 'crm_receivable_return_type', // CRM 回款的还款方式

View File

@ -18,15 +18,16 @@
</el-col>
<el-col :span="8" v-if="formType">
<el-form-item label="合同编号" prop="no">
<el-input v-model="formData.no" placeholder="请输入合同编号" />
<el-input disabled v-model="formData.no" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户名称" prop="customerId">
<el-select
v-model="formData.customerId"
disabled
placeholder=""
placeholder="请选择客户名称"
:disabled="formType"
@change="onCustomerChange"
class="w-1/1"
>
<el-option
@ -43,8 +44,9 @@
<el-select
@change="handleQuotationChange"
v-model="formData.quotationId"
placeholder="请选择报价单编号"
placeholder=""
class="w-1/1"
disabled
>
<el-option
v-for="item in quotationList"
@ -328,6 +330,7 @@
v-model="formData.startTime"
type="date"
value-format="x"
format="YYYY-MM-DD"
placeholder="选择合同签订日期"
style="width: 100%"
/>
@ -339,6 +342,7 @@
v-model="formData.endTime"
type="date"
value-format="x"
format="YYYY-MM-DD"
placeholder="选择合同结束时间"
style="width: 100%"
/>
@ -753,7 +757,7 @@ const handleQuotationChange = async (quotationId: number) => {
const customerRes = await ContractApi.quotationTimes(quotation.id);
formData.value.quotationTimes = customerRes.quotationTimes;
await onCustomerChange(quotation.customerId);
// await onCustomerChange(quotation.customerId);
await onPartnerChange(quotation.partnerCompanyId);
} catch (err) {
} finally {
@ -786,6 +790,9 @@ const onCustomerChange = async (customerId: string) => {
formData.value.financingInfo = customerRes.financingInfo;
formData.value.socialEmployeeNum = customerRes.socialEmployeeNum;
formData.value.registeredAddress = customerRes.registeredAddress;
formData.value.quotationId = customerRes.quotationId;
await handleQuotationChange(customerRes.quotationId);
} catch (err) {
console.error('获取客户详情失败:', err);
} finally {

View File

@ -52,11 +52,11 @@
</el-table-column>
<el-table-column label="岗位" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.deptName`" :rules="formRules.deptName" class="mb-0px!" v-if="!type">
<el-input v-model="row.deptName" placeholder="请输入岗位" />
<el-form-item :prop="`${$index}.postName`" :rules="formRules.postName" class="mb-0px!" v-if="!type">
<el-input v-model="row.postName" placeholder="请输入岗位" />
</el-form-item>
<div v-else>
{{row.deptName}}
{{row.postName}}
</div>
</template>
</el-table-column>
@ -185,7 +185,7 @@ const handleAdd = () => {
userId: undefined,
name: undefined,
authType: undefined,
deptName: undefined,
postName: undefined,
userRank: undefined,
authDesc: undefined,
phoneNumber: undefined,
@ -207,8 +207,8 @@ const changeUser = (i, val) => {
let arr = props.userOptions.filter(v => v.id === val)
if(arr.length) {
formData.value[i].name = arr[0].nickname
formData.value[i].deptName = arr[0].deptName
formData.value[i].postId = arr[0].deptId
formData.value[i].postName = arr[0].postName
formData.value[i].postId = arr[0].postId
}
}
const getList = (val: []) => {
@ -223,7 +223,7 @@ const getList = (val: []) => {
"name": item.name,
"authType": item.post,
"postId": item.userRank,
"deptName": item.deptName,
"postName": item.postName,
"userRank": item.mobile,
"authDesc": item.authDesc,
"wechat":item. wechat,

View File

@ -246,7 +246,7 @@
</el-button>
<el-button
v-if="scope.row.auditStatus !== 0 && scope.row.auditStatus !== 10"
v-if="scope.row.auditStatus !== 0 && scope.row.auditStatus !== 2 && scope.row.auditStatus !== 10"
v-hasPermi="['crm:contract:delete']"
link
type="danger"
@ -255,11 +255,13 @@
删除
</el-button>
<el-dropdown
v-if="scope.row.auditStatus === 0"
v-if="scope.row.auditStatus === 0 || scope.row.auditStatus === 2"
@command="(command) => handleCommand(command, scope.row)"
v-hasPermi="[
'crm:contract:update',
'crm:contract:delete'
'crm:contract:delete',
'crm:contract:print',
'crm:contract:change'
]"
>
<el-button type="primary" link><Icon icon="ep:d-arrow-right" /> 更多</el-button>
@ -273,19 +275,19 @@
</el-dropdown-item>
<el-dropdown-item
command="handleChange"
v-if="checkPermi(['crm:contract:update']) && scope.row.auditStatus === 0"
v-if="checkPermi(['crm:contract:change']) && scope.row.auditStatus === 0"
>
合同变更
</el-dropdown-item>
<el-dropdown-item
command="handlePrint"
v-if="checkPermi(['crm:contract:update']) && scope.row.auditStatus === 0"
v-if="checkPermi(['crm:contract:print']) && scope.row.auditStatus === 2"
>
打印合同
</el-dropdown-item>
<el-dropdown-item
command="handleDelete"
v-if="checkPermi(['crm:contract:delete']) && scope.row.auditStatus === 0"
v-if="checkPermi(['crm:contract:delete']) && (scope.row.auditStatus === 0 || scope.row.auditStatus === 2)"
>
删除
</el-dropdown-item>
@ -402,7 +404,7 @@ const handleCommand = (command: string, row: UserApi.UserVO) => {
handleChange(row)
break
case 'handlePrint':
getPrintTemplate(row)
onPrintContract(row)
break
case 'handleDelete':
handleDelete(row.id)
@ -461,32 +463,33 @@ const onPrintContract = async (row: ContractApi.ContractVO) => {
throw new Error('返回的合同文件为空')
}
const contentType = res.type.toLowerCase()
let fileType = 'application/msword' // 使 .doc MIME
let extension = '.doc'
// const contentType = res.type.toLowerCase()
// let fileType = 'application/msword' // 使 .doc MIME
// let extension = '.doc'
if (contentType.includes('wordprocessingml')) {
fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' // .docx MIME
extension = '.docx'
}
// blob
const blob = new Blob([res], { type: fileType })
// if (contentType.includes('wordprocessingml')) {
// fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' // .docx MIME
// extension = '.docx'
// }
// // blob
// const blob = new Blob([res], { type: fileType })
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
const disposition = res.headers['content-disposition']
let fileName = '合同.docx'
if (disposition && disposition.includes('filename=')) {
const match = disposition.match(/filename="?([^"]+)"?/)
if (match?.[1]) {
fileName = decodeURIComponent(match[1])
}
}
link.click()
window.URL.revokeObjectURL(url)
// const url = window.URL.createObjectURL(blob)
// const link = document.createElement('a')
// link.href = url
// const disposition = res.headers['content-disposition']
// let fileName = '.docx'
// if (disposition && disposition.includes('filename=')) {
// const match = disposition.match(/filename="?([^"]+)"?/)
// if (match?.[1]) {
// fileName = decodeURIComponent(match[1])
// }
// }
// link.click()
console.log('%csrc/views/crm/contract/index.vue:489 res.data', 'color: #007acc;', res);
window.open(res)
message.success('提交审核成功!')
// message.success('')
await getList()
} catch (error) {
console.error('合同下载失败', error)

View File

@ -1,60 +1,107 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<Dialog :title="dialogTitle" v-model="dialogVisible" width="50%">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="164px"
v-loading="formLoading"
>
<el-form-item label="产品ID" prop="projectId">
<el-input v-model="formData.projectId" placeholder="请输入产品ID" />
</el-form-item>
<el-form-item label="产品编号" prop="projectCode">
<el-input v-model="formData.projectCode" placeholder="请输入产品编号" />
</el-form-item>
<el-form-item label="客单价" prop="customerPrice">
<el-input v-model="formData.customerPrice" placeholder="请输入客单价" />
</el-form-item>
<el-form-item label="采购成本" prop="purchaseCost">
<el-input v-model="formData.purchaseCost" placeholder="请输入采购成本" />
</el-form-item>
<el-form-item label="代理费前返比例/金额" prop="agentFeePreReturn">
<el-input v-model="formData.agentFeePreReturn" placeholder="请输入代理费前返比例/金额" />
</el-form-item>
<el-form-item label="代理费后返比例/金额" prop="agentFeePostReturn">
<el-input v-model="formData.agentFeePostReturn" placeholder="请输入代理费后返比例/金额" />
</el-form-item>
<el-form-item label="线上溢价率" prop="onlineMarkupRate">
<el-input v-model="formData.onlineMarkupRate" placeholder="请输入线上溢价率" />
</el-form-item>
<el-form-item label="线下溢价率" prop="offlineMarkupRate">
<el-input v-model="formData.offlineMarkupRate" placeholder="请输入线下溢价率" />
</el-form-item>
<el-form-item label="税费成本" prop="taxCost">
<el-input v-model="formData.taxCost" placeholder="请输入税费成本" />
</el-form-item>
<el-form-item label="管理成本" prop="managementCost">
<el-input v-model="formData.managementCost" placeholder="请输入管理成本" />
</el-form-item>
<el-form-item label="结算对账成本" prop="settlementReconciliationCost">
<el-input v-model="formData.settlementReconciliationCost" placeholder="请输入结算对账成本" />
</el-form-item>
<el-form-item label="结算开票成本" prop="settlementInvoiceCost">
<el-input v-model="formData.settlementInvoiceCost" placeholder="请输入结算开票成本" />
</el-form-item>
<el-form-item label="顾问订单成本" prop="consultantOrderCost">
<el-input v-model="formData.consultantOrderCost" placeholder="请输入顾问订单成本" />
</el-form-item>
<el-form-item label="溢价分佣" prop="markupCommission">
<el-input v-model="formData.markupCommission" placeholder="请输入溢价分佣" />
</el-form-item>
<el-form-item label="顾问管理" prop="consultantManagement">
<el-input v-model="formData.consultantManagement" placeholder="请输入顾问管理" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="产品名称" prop="projectId">
<el-select
v-model="formData.projectId"
@change="changeProduct"
clearable
filterable
placeholder="请选择产品名称"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产品编号" prop="projectCode">
<el-input v-model="formData.projectCode" disabled placeholder="" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客单价" prop="customerPrice">
<el-input v-model="formData.customerPrice" placeholder="请输入客单价" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采购成本" prop="purchaseCost">
<el-input v-model="formData.purchaseCost" placeholder="请输入采购成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="代理费前返比例/金额" prop="agentFeePreReturn">
<el-input v-model="formData.agentFeePreReturn" placeholder="请输入代理费前返比例/金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="代理费后返比例/金额" prop="agentFeePostReturn">
<el-input v-model="formData.agentFeePostReturn" placeholder="请输入代理费后返比例/金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="线上溢价率" prop="onlineMarkupRate">
<el-input v-model="formData.onlineMarkupRate" placeholder="请输入线上溢价率" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="线下溢价率" prop="offlineMarkupRate">
<el-input v-model="formData.offlineMarkupRate" placeholder="请输入线下溢价率" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="税费成本" prop="taxCost">
<el-input v-model="formData.taxCost" placeholder="请输入税费成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="管理成本" prop="managementCost">
<el-input v-model="formData.managementCost" placeholder="请输入管理成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结算对账成本" prop="settlementReconciliationCost">
<el-input v-model="formData.settlementReconciliationCost" placeholder="请输入结算对账成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结算开票成本" prop="settlementInvoiceCost">
<el-input v-model="formData.settlementInvoiceCost" placeholder="请输入结算开票成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="顾问订单成本" prop="consultantOrderCost">
<el-input v-model="formData.consultantOrderCost" placeholder="请输入顾问订单成本" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="溢价分佣" prop="markupCommission">
<el-input v-model="formData.markupCommission" placeholder="请输入溢价分佣" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="顾问管理" prop="consultantManagement">
<el-input v-model="formData.consultantManagement" placeholder="请输入顾问管理" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
@ -67,7 +114,9 @@ import { ProductProcurementCostApi, ProductProcurementCostVO } from '@/api/crm/p
/** 产品采购成本 表单 */
defineOptions({ name: 'ProductProcurementCostForm' })
import * as ProductApi from '@/api/crm/product'
const productList = ref<ProductApi.ProductVO[]>([]) //
const { t } = useI18n() //
const message = useMessage() //
@ -78,6 +127,9 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
projectId: undefined,
projectCode: undefined,
category: undefined,
detailType: undefined,
unit: undefined,
customerPrice: undefined,
purchaseCost: undefined,
agentFeePreReturn: undefined,
@ -117,6 +169,7 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
console.log('%csrc/views/crm/productprocurementcost/ProductProcurementCostForm.vue:172 id', 'color: #007acc;', id);
//
if (id) {
formLoading.value = true
@ -129,6 +182,16 @@ const open = async (type: string, id?: number) => {
}
defineExpose({ open }) // open
const changeProduct = (val) => {
let arr = productList.value.filter(v => v.id === val)
if (arr.length) {
formData.value.projectCode = arr[0]['projectCode']
formData.value.category = arr[0]['category']
formData.value.detailType = arr[0]['detailType']
formData.value.unit = arr[0]['unit']
}
}
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
@ -175,4 +238,8 @@ const resetForm = () => {
}
formRef.value?.resetFields()
}
onMounted( async() => {
productList.value = await ProductApi.getProductSimpleList()
})
</script>

View File

@ -87,12 +87,12 @@
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" min-width="120px">
<el-table-column label="操作" align="center" fixed="right" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
@click="openForm('update', scope.row.projectId)"
v-hasPermi="['crm:product-procurement-cost:update']"
>
编辑

View File

@ -6,7 +6,7 @@
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="90px"
label-width="110px"
>
<el-form-item label="报价单编号" prop="no">
<el-input
@ -47,6 +47,21 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户确认状态" prop="confirmStatus">
<el-select
v-model="queryParams.confirmStatus"
placeholder="请选择客户确认状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CONFIRM_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
@ -143,6 +158,11 @@
<dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
</template>
</el-table-column>
<el-table-column label="客户确认状态" align="center" prop="confirmStatus" width="110">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CONFIRM_STATUS" :value="scope.row.confirmStatus" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
@ -180,11 +200,17 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
command="handleSubmit"
v-if="checkPermi(['crm:contract:update']) && scope.row.auditStatus === 0"
>
提交审核
</el-dropdown-item>
command="handleSubmit"
v-if="checkPermi(['crm:contract:update']) && scope.row.auditStatus === 0"
>
提交审核
</el-dropdown-item>
<el-dropdown-item
command="handleEnter"
v-if="checkPermi(['crm:quotation:customerConfirm']) && scope.row.auditStatus == 2 && scope.row.confirmStatus == 1"
>
客户确认
</el-dropdown-item>
<el-dropdown-item
command="handleProcessDetail"
v-if="checkPermi(['crm:customer-suggestion:query'])"
@ -248,6 +274,7 @@ const queryParams = reactive({
customerId: undefined,
ownerUserId: undefined,
partnerCompanyId: undefined,
confirmStatus: undefined,
createTime: []
})
const queryFormRef = ref() //
@ -314,6 +341,9 @@ const handleCommand = (command: string, row: UserApi.UserVO) => {
case 'handleProcessDetail':
handleProcessDetail(row)
break
case 'handleEnter':
handleEnter(row)
break
default:
break
}
@ -350,6 +380,12 @@ const handleProcessDetail = (row) => {
}
})
}
const handleEnter = async (row) => {
await QuotationApi.enterQuotation({id: row.id})
message.success('操作成功!')
}
const getName = (opt, val) => {
const arr = opt.filter(v => v.id == val)
return arr.length ? arr[0]['nickname'] : ''

View File

@ -69,7 +69,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位">
<el-form-item label="岗位" prop="postIds">
<el-select v-model="formData.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postList"
@ -131,6 +131,7 @@ const formRules = reactive<FormRules>({
username: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
nickname: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }],
postIds: [{ required: true, message: '岗位不能为空', trigger: 'blur' }],
email: [
{
type: 'email',