Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/views/crm/business/BusinessForm.vue
pull/781/head
苑坤 2025-04-28 14:54:47 +08:00
commit d762e636dd
6 changed files with 175 additions and 137 deletions

View File

@ -99,6 +99,7 @@ const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) //
/** 打开弹窗 */
const open = async (data: []) => {
console.log('%csrc/components/product/index.vue:102 data', 'color: #007acc;', data);
dialogVisible.value = true
multipleSelection.value = data
await getList()
@ -148,7 +149,13 @@ const submitForm = async () => {
emit('success', multipleSelection.value)
}
const setSelections = async () => {
const selections = multipleSelection.value
const selections = multipleSelection.value.map(item => {
return {
id: item.productId
}
})
console.log('%csrc/components/product/index.vue:153 list.value', 'color: #007acc;', list.value);
if (selections && selections.length > 0) {
list.value.forEach((row: any) => {
if (selections.some(item => item.id === row.id)) {

View File

@ -535,7 +535,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
component: () => import('@/views/crm/business/detail/index.vue')
},
{
path: 'business/add/:id',
path: 'business/add',
name: 'CrmBusinessAdd',
meta: {
title: '商机新增',
@ -545,6 +545,17 @@ const remainingRouter: AppRouteRecordRaw[] = [
},
component: () => import('@/views/crm/business/BusinessForm.vue')
},
{
path: 'business/edit',
name: 'CrmBusinesseEdit',
meta: {
title: '商机编辑',
noCache: true,
hidden: true,
activeMenu: '/crm/business'
},
component: () => import('@/views/crm/business/BusinessForm.vue')
},
{
path: 'contract/detail/:id',
name: 'CrmContractDetail',

View File

@ -23,7 +23,7 @@
</template>
</el-table-column>
<el-table-column label="产品单位" align="center" prop="unit">
<el-table-column label="单位" align="center" prop="unit">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_PRODUCT_UNIT" :value="scope.row.unit" />
</template>

View File

@ -17,7 +17,7 @@
<el-form-item label="负责人" prop="ownerUserId">
<el-select
v-model="formData.ownerUserId"
:disabled="formType !== 'create'"
:disabled="formType"
placeholder="请选择负责人"
class="w-1/1"
>
@ -34,7 +34,7 @@
<el-form-item label="需求提交人" prop="requestorUserId">
<el-select
v-model="formData.requestorUserId"
:disabled="formType !== 'create'"
:disabled="formType"
placeholder="请选择需求提交人"
class="w-1/1"
>
@ -85,7 +85,7 @@
placeholder="请选择商机状态组"
clearable
class="w-1/1"
:disabled="formType !== 'create'"
:disabled="formType"
>
<el-option
v-for="item in statusTypeList"
@ -185,8 +185,9 @@
<el-tab-pane label="产品清单" name="product">
<BusinessProductForm
ref="productFormRef"
v-model="formData.products"
:products="formData.products"
:disabled="disabled"
@success="setList"
/>
</el-tab-pane>
</el-tabs>
@ -222,30 +223,31 @@
</el-row>
</el-form>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="goBack"> </el-button>
</ContentWrap>
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
import * as BusinessApi from '@/api/crm/business'
import * as BusinessStatusApi from '@/api/crm/business/status'
import * as CustomerApi from '@/api/crm/customer'
import * as UserApi from '@/api/system/user'
import * as DeptApi from '@/api/system/dept'
import { useUserStore } from '@/store/modules/user'
import { defaultProps, handleTree } from '@/utils/tree'
import BusinessProductForm from './components/BusinessProductForm.vue'
import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils'
const deptTree = ref() //
const { proxy }: any = getCurrentInstance();
const { t } = useI18n() //
const message = useMessage() //
import { ref, watch, onMounted } from 'vue';
import { getIntDictOptions, getStrDictOptions, DICT_TYPE, getBoolDictOptions } from '@/utils/dict';
import * as BusinessApi from '@/api/crm/business';
import * as BusinessStatusApi from '@/api/crm/business/status';
import * as CustomerApi from '@/api/crm/customer';
import * as UserApi from '@/api/system/user';
import * as DeptApi from '@/api/system/dept';
import { useUserStore } from '@/store/modules/user';
import { defaultProps, handleTree } from '@/utils/tree';
import BusinessProductForm from './components/BusinessProductForm.vue';
import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils';
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const { proxy }: any = getCurrentInstance();
const { t } = useI18n();
const message = useMessage();
const dialogVisible = ref(false);
const dialogTitle = ref('');
const formLoading = ref(false);
const formType = ref('');
const formData = ref({
id: undefined,
name: undefined,
@ -260,116 +262,118 @@ const formData = ref({
statusId: undefined,
endStatus: undefined,
dealTime: undefined,
onlinePrice: undefined,
offlinePrice: undefined,
totalProductPrice: undefined,
discountPercent: undefined,
totalPrice: undefined,
onlinePrice: 0,
offlinePrice: 0,
totalProductPrice: 0,
totalPrice: 0,
saleStage: undefined,
paymentTerm: undefined,
creditMethod: undefined,
creditCalcCycle: undefined,
creditLimit: undefined,
techSupport: undefined,
products: [],
})
products: []
});
const formRules = reactive({
name: [{ required: true, message: '商机名称不能为空', trigger: 'blur' }],
customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }],
statusTypeId: [{ required: true, message: '商机状态组不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const userOptions = ref<UserApi.UserVO[]>([]) //
const statusTypeList = ref([]) //
const customerList = ref([]) //
});
const formRef = ref();
const userOptions = ref<UserApi.UserVO[]>([]);
const statusTypeList = ref([]);
const customerList = ref([]);
const deptTree = ref();
/** 子表的表单 */
const subTabsName = ref('product')
const productFormRef = ref()
const subTabsName = ref('product');
const productFormRef = ref();
/** 计算 discountPrice、totalPrice 价格 */
watch(
() => formData.value.products,
(val) => {
if (!val) {
return
(newProducts) => {
if (!Array.isArray(newProducts)) {
console.warn('formData.value.products is not an array');
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
let totalOnlinePrice = 0;
let totalOfflinePrice = 0;
for (const product of newProducts) {
if (typeof product.onlinePrice === 'number') {
totalOnlinePrice += product.onlinePrice;
}
if (typeof product.offlinePrice === 'number') {
totalOfflinePrice += product.offlinePrice;
}
}
formData.value.onlinePrice = totalOnlinePrice.toFixed(2)
formData.value.offlinePrice = totalOfflinePrice.toFixed(2)
let all = totalOnlinePrice + totalOfflinePrice
formData.value.totalPrice = all.toFixed(2)
},
{ deep: true }
)
/** 打开弹窗 */
const open = async (type: string, id?: number, customerId?: number, contactId?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
resetForm()
//
);
const open = async (id?: number, customerId?: number) => {
if (id) {
formLoading.value = true
formLoading.value = true;
try {
formData.value = await BusinessApi.getBusiness(id)
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 || []
};
} finally {
formLoading.value = false
formLoading.value = false;
}
} else {
if (customerId) {
formData.value.customerId = customerId
formData.value.customerDefault = true //
}
// contactId
if (contactId) {
formData.value.contactId = contactId
formData.value.customerId = customerId;
formData.value.customerDefault = true;
}
}
//
if (formType.value === 'create') {
formData.value.ownerUserId = useUserStore().getUser.id
if (!formType.value) {
formData.value.ownerUserId = useUserStore().getUser.id;
}
}
defineExpose({ open }) // open
};
const setList = (newProducts) => {
formData.value.products = newProducts;
};
const { push } = useRouter()
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
// console.log('%csrc/views/crm/business/BusinessForm.vue:346 productFormRef.value.formData', 'color: #007acc;', productFormRef.value);
// formData.value.products = productFormRef.value.formData;
//
if (!productFormRef.value) return;
const valid = await productFormRef.value.validate();
formData.value.products = valid
if (!valid) return;
//
formLoading.value = true
try {
const data = formData.value as unknown as BusinessApi.BusinessVO
if (formType.value === 'create') {
await BusinessApi.createBusiness(data)
message.success(t('common.createSuccess'))
} else {
await BusinessApi.updateBusiness(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
formLoading.value = true;
try {
const data = formData.value as unknown as BusinessApi.BusinessVO;
if (!formType.value) {
await BusinessApi.createBusiness(data);
message.success(t('common.createSuccess'));
} else {
await BusinessApi.updateBusiness(data);
message.success(t('common.updateSuccess'));
}
dialogVisible.value = false;
goBack()
} finally {
formLoading.value = false;
}
};
const goBack = ()=> {
proxy.$router.go(-1)
}
const resetForm = () => {
formData.value = {
id: undefined,
@ -378,24 +382,22 @@ const resetForm = () => {
ownerUserId: undefined,
statusTypeId: undefined,
dealTime: undefined,
totalPrice: undefined,
totalPrice: 0,
products: [],
contactId: undefined,
customerDefault: false
}
formRef.value?.resetFields()
}
/** 初始化 */
const { params } = useRoute()
};
formRef.value?.resetFields();
};
const route = useRoute();
onMounted(async () => {
formType.value = params.id
//
customerList.value = await CustomerApi.getCustomerSimpleList()
//
statusTypeList.value = await BusinessStatusApi.getBusinessStatusTypeSimpleList()
//
userOptions.value = await UserApi.getSimpleUserList()
//
deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
})
const customerId = route.query.customerId;
formType.value = route.query.id;
if (formType.value) open(formType.value, customerId)
customerList.value = await CustomerApi.getCustomerSimpleList();
statusTypeList.value = await BusinessStatusApi.getBusinessStatusTypeSimpleList();
userOptions.value = await UserApi.getSimpleUserList();
deptTree.value = handleTree(await DeptApi.getSimpleDeptList());
});
</script>

View File

@ -10,25 +10,21 @@
>
<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="产品分类" min-width="150">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.productCategoryId" />
</el-form-item>
<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" />
</template>
</el-table-column>
<el-table-column label="条码" min-width="150">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.productNo" />
</el-form-item>
<el-table-column label="产品明细" align="center" prop="detailType" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_PRODUCT_DETAIL_TYPE" :value="scope.row.detailType" />
</template>
</el-table-column>
<el-table-column label="单位" min-width="80">
<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">
@ -82,7 +78,7 @@ import { ref, watch, onMounted, defineProps, defineExpose, reactive } from 'vue'
import * as ProductApi from '@/api/crm/product';
import { erpPriceInputFormatter, erpPriceMultiply } from '@/utils';
import ProductForm from '@/components/product/index.vue'
import { DICT_TYPE } from '@/utils/dict';
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict';
const formLoading = ref(false); //
@ -144,10 +140,28 @@ watch(
// };
// formData.value.push(newRow);
// };
const emit = defineEmits(['update:products']);
const emit = defineEmits(['success']) // success
const getList = (val: []) => {
formData.value = val
emit('update:products', val);
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)
}
const productRef = ref() // Ref
const handleAdd = () => {

View File

@ -26,7 +26,7 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
<el-button v-hasPermi="['crm:business:create']" type="primary" @click="openForm('create')">
<el-button v-hasPermi="['crm:business:create']" type="primary" @click="openFormAdd()">
<Icon class="mr-5px" icon="ep:plus" />
新增
</el-button>
@ -136,7 +136,7 @@
v-hasPermi="['crm:business:update']"
link
type="primary"
@click="openForm('update', scope.row.id)"
@click="openFormEdit(scope.row)"
>
编辑
</el-button>
@ -232,8 +232,12 @@ const openCustomerDetail = (id: number) => {
/** 添加/修改操作 */
const formRef = ref()
const openForm = (id: number) => {
push({ name: 'CrmBusinessAdd', params: { id: 'create' } })
const openFormEdit = (row: Object) => {
push({ name: 'CrmBusinesseEdit', query: { id: row.id, customerId: row.customerId } })
}
const openFormAdd = () => {
push({ name: 'CrmBusinessAdd' })
}
/** 删除按钮操作 */