pull/781/head
zy 2025-04-28 17:17:43 +08:00
parent 9bd370647f
commit 33c57d2328
17 changed files with 156 additions and 96 deletions

View File

@ -4,7 +4,7 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://localhost:48080'
VITE_BASE_URL='http://172.22.3.6:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

View File

@ -534,6 +534,28 @@ const remainingRouter: AppRouteRecordRaw[] = [
},
component: () => import('@/views/crm/business/detail/index.vue')
},
{
path: 'business/bill-templete-add',
name: 'BillTempleteAdd',
meta: {
title: '票据模版新增',
noCache: true,
hidden: true,
activeMenu: '/crm/business'
},
component: () => import('@/views/crm/billtemplate/BillTemplateForm.vue')
},
{
path: 'business/bill-templete-edit',
name: 'BillTempleteEdit',
meta: {
title: '票据模版编辑',
noCache: true,
hidden: true,
activeMenu: '/crm/business'
},
component: () => import('@/views/crm/billtemplate/BillTemplateForm.vue')
},
{
path: 'business/add',
name: 'CrmBusinessAdd',

View File

@ -226,6 +226,9 @@ export enum DICT_TYPE {
CRM_COMPLAINT_METHOD = "crm_complaint_method", // 投诉方式
CRM_COMPLAINT_LEVEL = "crm_complaint_level", // 投诉级别
// 商机账期
PAYMENT_TERM = "payment_term", // 投诉级别
// ========== ERP - 企业资源计划模块 ==========
ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态

View File

@ -1,5 +1,5 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1280">
<ContentWrap class="mt-10px">
<el-form
ref="formRef"
:model="formData"
@ -34,20 +34,21 @@
ref="productFormRef"
:products="formData.products"
:disabled="disabled"
@success="setList"
/>
</el-tab-pane>
</el-tabs>
</ContentWrap>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
<div style="text-align: right">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="goBack"> </el-button>
</div>
</ContentWrap>
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
import * as BusinessApi from '@/api/crm/business'
import { BillTemplateApi, BillTemplateVO } from '@/api/crm/billtemplate'
import * as BusinessStatusApi from '@/api/crm/business/status'
import * as CustomerApi from '@/api/crm/customer'
import * as UserApi from '@/api/system/user'
@ -56,6 +57,7 @@ import { useUserStore } from '@/store/modules/user'
import { defaultProps, handleTree } from '@/utils/tree'
import BusinessProductForm from './components/index.vue'
import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils'
const { proxy }: any = getCurrentInstance();
const deptTree = ref() //
const { t } = useI18n() //
@ -88,7 +90,9 @@ const formData = ref({
creditMethod: undefined,
creditCalcCycle: undefined,
creditLimit: undefined,
techSupport: undefined
techSupport: undefined,
products: [],
})
const formRules = reactive({
name: [{ required: true, message: '票据模版不能为空', trigger: 'blur' }],
@ -105,34 +109,18 @@ const customerList = ref([]) // 客户列表的数据
const subTabsName = ref('product')
const productFormRef = ref()
/** 计算 discountPrice、totalPrice 价格 */
watch(
() => formData.value,
(val) => {
if (!val) {
return
}
const totalOnlinePrice = val.products.reduce((prev, curr) => prev + curr.onlinePrice, 0)
const totalOfflinePrice = val.products.reduce((prev, curr) => prev + curr.offlinePrice, 0)
//
formData.value.onlinePrice = totalOnlinePrice
formData.value.offlinePrice = totalOfflinePrice
formData.value.totalPrice = totalOnlinePrice + totalOfflinePrice
},
{ deep: true }
)
const setList = (newProducts) => {
formData.value.productItems = newProducts;
};
/** 打开弹窗 */
const open = async (type: string, id?: number, customerId?: number, contactId?: number) => {
const open = async (id?: number, customerId?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await BusinessApi.getBusiness(id)
formData.value = await BillTemplateApi.getBillTemplate(id)
formData.value.products = formData.value.productItems
} finally {
formLoading.value = false
}
@ -141,22 +129,7 @@ const open = async (type: string, id?: number, customerId?: number, contactId?:
formData.value.customerId = customerId
formData.value.customerDefault = true //
}
// contactId
if (contactId) {
formData.value.contactId = contactId
}
}
//
customerList.value = await CustomerApi.getCustomerSimpleList()
//
statusTypeList.value = await BusinessStatusApi.getBusinessStatusTypeSimpleList()
//
userOptions.value = await UserApi.getSimpleUserList()
//
deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
//
if (formType.value === 'create') {
formData.value.ownerUserId = useUserStore().getUser.id
}
}
defineExpose({ open }) // open
@ -178,22 +151,29 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as BusinessApi.BusinessVO
if (formType.value === 'create') {
await BusinessApi.createBusiness(data)
const data = formData.value as unknown as BillTemplateApi.BillTemplateVO
if (!formType.value) {
await BillTemplateApi.createBillTemplate(data)
message.success(t('common.createSuccess'))
} else {
await BusinessApi.updateBusiness(data)
await BillTemplateApi.updateBillTemplate(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
goBack()
} finally {
formLoading.value = false
}
}
const { push } = useRouter()
const goBack = ()=> {
push({ name: 'BillTemplate' })
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
@ -210,4 +190,12 @@ const resetForm = () => {
}
formRef.value?.resetFields()
}
const route = useRoute();
onMounted(async () => {
const customerId = route.query.customerId;
formType.value = route.query.id;
if (formType.value) open(formType.value, customerId)
});
</script>

View File

@ -10,7 +10,7 @@
>
<el-table :data="formData" class="-mt-10px">
<el-table-column label="序号" type="index" align="center" width="60" />
<el-table-column label="产品名称" align="center" prop="name" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="产品类型" align="center" prop="category" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_PRODUCT_CATEGORY" :value="scope.row.category" />
@ -23,9 +23,9 @@
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="unit">
<el-table-column label="单位" align="center" prop="productUnit">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.unit" />
<dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.productUnit" />
</template>
</el-table-column>
<el-table-column label="产品票据" fixed="right" min-width="140">
@ -128,28 +128,29 @@ watch(
{ immediate: true }
)
/** 监听合同产品变化,计算合同产品总价 */
watch(
() => formData.value,
(val) => {
if (!val || val.length === 0) {
return
}
//
val.forEach((item) => {
if (item.offlinePrice != null && item.onlinePrice != null) {
item.totalPrice = item.offlinePrice + item.onlinePrice
} else {
item.totalPrice = 0
}
})
},
{ deep: true }
)
const emit = defineEmits(['success']) // success
const getList = (val: []) => {
formData.value = val
console.log('%csrc/views/crm/billtemplate/components/index.vue:133 object', 'color: #007acc;', formData.value);
for(let i = formData.value.length - 1; i >= 0; i--) {
let obj = formData.value[i]
if(!val.some(v => v.id === obj.productId)) formData.value.splice(i, 1)
}
val.forEach(item => {
if(!formData.value.some(v => v.productId === item.id)) {
formData.value.push({
"productId": item.id,
"category": item.category,
"productName": item.name,
"detailType": item.detailType,
"productUnit": item.unit,
"onlinePrice": '',
"offlinePrice": '',
"count": ''
})
}
})
emit('success', formData.value)
}
// /** */

View File

@ -49,7 +49,7 @@
<el-button
type="primary"
plain
@click="openForm('create')"
@click="openFormAdd"
v-hasPermi="['crm:bill-template:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
@ -90,7 +90,7 @@
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
@click="openFormEdit(scope.row)"
v-hasPermi="['crm:bill-template:update']"
>
编辑
@ -115,8 +115,6 @@
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<BillTemplateForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
@ -124,7 +122,6 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { BillTemplateApi, BillTemplateVO } from '@/api/crm/billtemplate'
import BillTemplateForm from './BillTemplateForm.vue'
/** 票据模版 列表 */
defineOptions({ name: 'BillTemplate' })
@ -170,9 +167,14 @@ const resetQuery = () => {
}
/** 添加/修改操作 */
const { push } = useRouter()
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
const openFormEdit = (row: Object) => {
push({ name: 'BillTempleteEdit', query: { id: row.id, customerId: row.customerId } })
}
const openFormAdd = () => {
push({ name: 'BillTempleteAdd' })
}
/** 删除按钮操作 */
@ -207,4 +209,7 @@ const handleExport = async () => {
onMounted(() => {
getList()
})
onActivated(()=>{
getList()
})
</script>

View File

@ -121,9 +121,9 @@
</el-col>
<el-col :span="8">
<el-form-item label="账期" prop="paymentTerm">
<el-select v-model="formData.paymentTerm" placeholder="请选择账期">
<el-select v-model="formData.paymentTerm" @change="changePayment" placeholder="请选择账期">
<el-option
v-for="dict in getStrDictOptions('payment_term')"
v-for="dict in getStrDictOptions(DICT_TYPE.PAYMENT_TERM)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@ -145,28 +145,29 @@
</el-col>
<el-col :span="8">
<el-form-item label="授信计算周期" prop="creditCalcCycle">
<el-select v-model="formData.creditCalcCycle" placeholder="请选择授信计算周期">
<!-- <el-select v-model="formData.creditCalcCycle" placeholder="请选择授信计算周期">
<el-option
v-for="dict in getIntDictOptions('credit_calc_cycle')"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-select> -->
<el-input v-model="formData.creditCalcCycle" disabled placeholder="授信计算周期" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="授信额度" prop="creditLimit">
<el-input v-model="formData.creditLimit" placeholder="请输入授信额度" />
<el-input v-model="formData.creditLimit" disabled placeholder="授信额度" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否技术需求支持" prop="techSupport">
<el-form-item label="技术需求支持" prop="techSupport">
<el-radio-group v-model="formData.techSupport">
<el-radio
v-for="dict in getBoolDictOptions('tech_support')"
:key="dict.value"
:label="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
@ -222,8 +223,10 @@
</el-col>
</el-row>
</el-form>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="goBack"> </el-button>
<div style="text-align: right">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="goBack"> </el-button>
</div>
</ContentWrap>
</template>
@ -239,6 +242,7 @@ import { useUserStore } from '@/store/modules/user';
import { defaultProps, handleTree } from '@/utils/tree';
import BusinessProductForm from './components/BusinessProductForm.vue';
import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils';
import { number } from 'vue-types';
const { proxy }: any = getCurrentInstance();
const { t } = useI18n();
@ -316,12 +320,21 @@ watch(
{ deep: true }
);
watch(
() => formData.value.totalPrice,
(newProducts) => {
console.log('%csrc/views/crm/business/BusinessForm.vue:326 111', 'color: #007acc;', 111);
formData.value.creditLimit = parseInt(newProducts / 365 * formData.value.creditCalcCycle)
},
{ deep: true }
);
const open = async (id?: number, customerId?: number) => {
if (id) {
formLoading.value = true;
try {
const data = await BusinessApi.getBusiness(id);
console.log('%csrc/views/crm/business/BusinessForm.vue:325 data', 'color: #007acc;', data);
formData.value = {
...data,
products: data.products || []
@ -345,6 +358,15 @@ const setList = (newProducts) => {
formData.value.products = newProducts;
};
//
const changePayment = (val) => {
const currentDate = new Date(); //
const currentMonth = currentDate.getMonth() + 1; // 01
const daysInMonth = new Date(currentDate.getFullYear(), currentMonth, 0).getDate(); //
formData.value.creditCalcCycle = (val > 2 ? parseInt(daysInMonth + Number(val)) : 0)
formData.value.creditLimit = parseInt(formData.value.totalPrice / 365 * formData.value.creditCalcCycle)
}
const { push } = useRouter()
const submitForm = async () => {
@ -392,6 +414,7 @@ const resetForm = () => {
const route = useRoute();
onMounted(async () => {
console.log('%csrc/views/crm/business/BusinessForm.vue:406 getStrDictOptions(DICT_TYPE.PAYMENT_TERM)', 'color: #007acc;', getStrDictOptions(DICT_TYPE.PAYMENT_TERM));
const customerId = route.query.customerId;
formType.value = route.query.id;
if (formType.value) open(formType.value, customerId)

View File

@ -57,8 +57,6 @@
/>
</ContentWrap>
<!-- 表单弹窗添加 -->
<BusinessForm ref="formRef" @success="getList" />
<!-- 关联商机选择弹框 -->
<BusinessListModal
ref="businessModalRef"
@ -129,13 +127,13 @@ const handleQuery = () => {
}
/** 添加操作 */
const { push } = useRouter()
const formRef = ref()
const openForm = () => {
formRef.value.open('create', null, props.customerId, props.contactId)
push({ name: 'CrmBusinessAdd' })
}
/** 打开联系人详情 */
const { push } = useRouter()
const openDetail = (id: number) => {
push({ name: 'CrmBusinessDetail', params: { id } })
}

View File

@ -272,4 +272,7 @@ const handleExport = async () => {
onMounted(() => {
getList()
})
onActivated(()=>{
getList()
})
</script>

View File

@ -45,7 +45,9 @@ const getList = async () => {
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -47,7 +47,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -42,7 +42,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -45,7 +45,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -45,7 +45,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -46,7 +46,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -44,7 +44,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>

View File

@ -28,6 +28,7 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 999,
customerInfoId: ''
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
@ -45,7 +46,9 @@ const getList = async () => {
}
/** 初始化 **/
const { params } = useRoute()
onMounted(() => {
queryParams.customerInfoId = params.id
getList()
})
</script>