style:客户管理-

main
黄伟杰 6 days ago
parent c3e8288b52
commit d07354c9a5

@ -8,8 +8,9 @@ VITE_DEV=true
# 线上环境
# VITE_BASE_URL='https://besure.ngsk.tech:7001'
# 本地联调
# VITE_BASE_URL='http://192.168.5.142:48081'
VITE_BASE_URL='http://192.168.43.233:48081'
VITE_BASE_URL='http://192.168.5.37:48081'
# VITE_BASE_URL='http://47.106.185.127:8089'
# VITE_BASE_URL='http://192.168.43.233:48081'
# VITE_BASE_URL='http://192.168.5.5:48081'

@ -64,6 +64,147 @@ export default {
no: 'No',
code: 'Auto-generate on Save'
},
MesCustomer: {
fields: {
id: 'ID',
name: 'Customer Name',
customerCode: 'Customer Code',
contactName: 'Contact',
source: 'Customer Source',
mobile: 'Contact Mobile',
telephone: 'Contact Phone',
email: 'Contact Email',
ownerUser: 'Owner',
wechat: 'WeChat',
qq: 'QQ',
industry: 'Customer Industry',
industryBelong: 'Industry',
level: 'Customer Level',
address: 'Address',
detailAddress: 'Detailed Address',
contactNextTime: 'Next Contact Time',
remark: 'Remark',
lockStatus: 'Lock Status',
dealStatus: 'Deal Status',
contactLastTime: 'Last Follow-up Time',
contactLastContent: 'Last Follow-up Record',
poolDay: 'Days Before Pool',
ownerDept: 'Owner Department',
creator: 'Creator',
createTime: 'Create Time',
updateTime: 'Update Time',
operate: 'Operation'
},
placeholders: {
name: 'Please enter customer name',
customerCode: 'Please enter customer code',
contactName: 'Please enter contact',
source: 'Please select customer source',
mobile: 'Please enter contact mobile',
telephone: 'Please enter contact phone',
email: 'Please enter contact email',
wechat: 'Please enter WeChat',
qq: 'Please enter QQ',
industry: 'Please select customer industry',
industryBelong: 'Please select industry',
level: 'Please select customer level',
city: 'Please select city',
detailAddress: 'Please enter detailed address',
contactNextTime: 'Select next contact time',
remark: 'Please enter remark'
},
tabs: {
owner: 'My Customers',
participant: 'Participated',
subordinate: 'Subordinates',
followUp: 'Follow-up Records',
basicInfo: 'Basic Info',
contacts: 'Contacts',
team: 'Team Members',
business: 'Business Opportunities',
contract: 'Contracts',
receivable: 'Receivables',
operateLog: 'Operation Logs',
systemInfo: 'System Info'
},
actions: {
transfer: 'Transfer',
updateDealStatus: 'Change Deal Status',
unlock: 'Unlock',
lock: 'Lock',
receive: 'Receive',
distribute: 'Distribute',
putPool: 'Move to Pool',
downloadTemplate: 'Download template'
},
status: {
dealDone: 'Closed',
dealUndone: 'Not Closed'
},
import: {
title: 'Customer Import',
dragText: 'Drag file here, or',
clickText: 'click to upload',
updateSupport: 'Update existing customer data if the customer name already exists',
formatLimit: 'Only xls and xlsx files are allowed.'
},
messages: {
customerCodeRequired: 'Customer code is required',
nameRequired: 'Customer name is required',
ownerRequired: 'Owner is required',
uploadFileRequired: 'Please upload a file',
uploadFailed: 'Upload failed, please upload again!',
uploadFileLimit: 'Only one file can be uploaded!',
uploadCreateCount: 'Created successfully: {count};',
uploadUpdateCount: 'Updated successfully: {count};',
uploadFailureCount: 'Failed to update: {count};',
updateDealStatusConfirm: 'Change deal status to [{status}]?',
updateDealStatusSuccess: 'Deal status updated successfully',
lockConfirm: 'Lock customer [{name}]?',
lockSuccess: 'Customer [{name}] locked successfully',
unlockConfirm: 'Unlock customer [{name}]?',
unlockSuccess: 'Customer [{name}] unlocked successfully',
receiveConfirm: 'Receive customer [{name}]?',
receiveSuccess: 'Customer [{name}] received successfully',
putPoolConfirm: 'Move customer [{name}] to the pool?',
putPoolSuccess: 'Customer [{name}] moved to the pool successfully',
customerRequired: 'Invalid parameter: customer is required!',
distributeSuccess: 'Customer distributed successfully',
poolEnabledRequired: 'Customer pool enabled setting is required',
ruleTypeRequired: 'Rule type is required',
maxCountRequired: 'Max count is required'
},
filenames: {
customerExport: 'Customer.xls',
importTemplate: 'CustomerImportTemplate.xls'
},
poolConfig: {
title: 'Customer Pool Rule Settings',
ruleSetting: 'Customer Pool Rule Settings',
notifySetting: 'Advance Reminder Settings',
noFollowPrefix: 'days without follow-up or',
noDealSuffix: 'days without deal',
notifyPrefix: 'Remind',
notifySuffix: 'days in advance'
},
limitConfig: {
customerQuantityLimit: 'Owned Customer Limit',
customerLockLimit: 'Locked Customer Limit',
ruleUsers: 'Applicable Users',
ruleDepts: 'Applicable Departments',
customerQuantityMax: 'Owned Customer Max',
customerLockMax: 'Locked Customer Max',
dealCountEnabled: 'Closed customers count toward owned customers',
maxCountPlaceholder: 'Please enter max count',
deptPlaceholder: 'Please select applicable departments'
},
pool: {
exportFilename: 'CustomerPool.xls'
},
units: {
days: 'days'
}
},
ReportDashboard: {
DashboardList: {
searchNameLabel: 'Name',
@ -4257,6 +4398,8 @@ export default {
tabStoredLabel: 'Stored',
tableCodeColumn: 'Code',
tableTaskNameColumn: 'Task Name',
tableCustomerNameColumn: 'Customer Name',
tableOrderDateColumn: 'Order Date',
tableDeliveryDateColumn: 'Delivery Date',
tableTaskTypeColumn: 'Type',
@ -4273,6 +4416,11 @@ export default {
detailTabTaskDetailLabel: 'Task Detail',
dialogTaskNameLabel: 'Task Name',
dialogTaskNamePlaceholder: 'Please enter task name',
dialogCustomerLabel: 'Customer',
dialogCustomerPlaceholder: 'Please select customer',
selectCustomerDialogTitle: 'Select Customer',
dialogCodeLabel: 'Task Code',
dialogCodeTooltip: 'Task code',
dialogCodePlaceholder: 'Code will be generated automatically after saving',
@ -4288,6 +4436,8 @@ export default {
dialogSubmitButtonText: 'Confirm',
dialogCancelButtonText: 'Cancel',
validatorTaskNameRequired: 'Task name cannot be empty',
validatorCustomerRequired: 'Customer cannot be empty',
validatorDeliveryDateRequired: 'Delivery date cannot be empty',
validatorTaskTypeRequired: 'Task type cannot be empty',
validatorIsUrgentRequired: 'Urgent flag cannot be empty',

@ -64,6 +64,147 @@ export default {
no: '否',
code: '编码保存后自动生成'
},
MesCustomer: {
fields: {
id: '编号',
name: '客户名称',
customerCode: '客户编码',
contactName: '联系人',
source: '客户来源',
mobile: '联系人手机',
telephone: '联系人电话',
email: '联系人邮箱',
ownerUser: '负责人',
wechat: '微信',
qq: 'QQ',
industry: '客户行业',
industryBelong: '所属行业',
level: '客户级别',
address: '地址',
detailAddress: '详细地址',
contactNextTime: '下次联系时间',
remark: '备注',
lockStatus: '锁定状态',
dealStatus: '成交状态',
contactLastTime: '最后跟进时间',
contactLastContent: '最后跟进记录',
poolDay: '距离进入公海天数',
ownerDept: '所属部门',
creator: '创建人',
createTime: '创建时间',
updateTime: '更新时间',
operate: '操作'
},
placeholders: {
name: '请输入客户名称',
customerCode: '请输入客户编码',
contactName: '请输入联系人',
source: '请选择客户来源',
mobile: '请输入联系人手机',
telephone: '请输入联系人电话',
email: '请输入联系人邮箱',
wechat: '请输入微信',
qq: '请输入 QQ',
industry: '请选择客户行业',
industryBelong: '请选择所属行业',
level: '请选择客户级别',
city: '请选择城市',
detailAddress: '请输入详细地址',
contactNextTime: '选择下次联系时间',
remark: '请输入备注'
},
tabs: {
owner: '我负责的',
participant: '我参与的',
subordinate: '下属负责的',
followUp: '跟进记录',
basicInfo: '基本信息',
contacts: '联系人',
team: '团队成员',
business: '商机',
contract: '合同',
receivable: '回款',
operateLog: '操作日志',
systemInfo: '系统信息'
},
actions: {
transfer: '转移',
updateDealStatus: '更改成交状态',
unlock: '解锁',
lock: '锁定',
receive: '领取',
distribute: '分配',
putPool: '放入公海',
downloadTemplate: '下载模板'
},
status: {
dealDone: '已成交',
dealUndone: '未成交'
},
import: {
title: '客户导入',
dragText: '将文件拖到此处,或',
clickText: '点击上传',
updateSupport: '是否更新已经存在的客户数据(“客户名称”重复)',
formatLimit: '仅允许导入 xls、xlsx 格式文件。'
},
messages: {
customerCodeRequired: '客户编码不能为空',
nameRequired: '客户名称不能为空',
ownerRequired: '负责人不能为空',
uploadFileRequired: '请上传文件',
uploadFailed: '上传失败,请您重新上传!',
uploadFileLimit: '最多只能上传一个文件!',
uploadCreateCount: '上传成功数量:{count};',
uploadUpdateCount: '更新成功数量:{count};',
uploadFailureCount: '更新失败数量:{count};',
updateDealStatusConfirm: '确定更新成交状态为【{status}】吗?',
updateDealStatusSuccess: '更新成交状态成功',
lockConfirm: '确定锁定客户【{name}】 吗?',
lockSuccess: '锁定客户【{name}】成功',
unlockConfirm: '确定解锁客户【{name}】 吗?',
unlockSuccess: '解锁客户【{name}】成功',
receiveConfirm: '确定领取客户【{name}】 吗?',
receiveSuccess: '领取客户【{name}】成功',
putPoolConfirm: '确定将客户【{name}】放入公海吗?',
putPoolSuccess: '客户【{name}】放入公海成功',
customerRequired: '参数错误,客户不能为空!',
distributeSuccess: '分配客户成功',
poolEnabledRequired: '是否启用客户公海不能为空',
ruleTypeRequired: '规则类型不能为空',
maxCountRequired: '数量上限不能为空'
},
filenames: {
customerExport: '客户.xls',
importTemplate: '客户导入模版.xls'
},
poolConfig: {
title: '客户公海规则设置',
ruleSetting: '客户公海规则设置',
notifySetting: '提前提醒设置',
noFollowPrefix: '天不跟进或',
noDealSuffix: '天未成交',
notifyPrefix: '提前',
notifySuffix: '天提醒'
},
limitConfig: {
customerQuantityLimit: '拥有客户数限制',
customerLockLimit: '锁定客户数限制',
ruleUsers: '规则适用人群',
ruleDepts: '规则适用部门',
customerQuantityMax: '拥有客户数上限',
customerLockMax: '锁定客户数上限',
dealCountEnabled: '成交客户是否占用拥有客户数',
maxCountPlaceholder: '请输入数量上限',
deptPlaceholder: '请选择规则适用部门'
},
pool: {
exportFilename: '客户公海.xls'
},
units: {
days: '天'
}
},
ReportDashboard: {
DashboardList: {
searchNameLabel: '名称',
@ -4110,6 +4251,8 @@ export default {
tabStoredLabel: '入库',
tableCodeColumn: '编码',
tableTaskNameColumn: '任务单名称',
tableCustomerNameColumn: '客户名称',
tableOrderDateColumn: '下达日期',
tableDeliveryDateColumn: '交货日期',
tableTaskTypeColumn: '类型',
@ -4126,6 +4269,11 @@ export default {
detailTabTaskDetailLabel: '任务单明细',
dialogTaskNameLabel: '任务单名称',
dialogTaskNamePlaceholder: '请输入任务单名称',
dialogCustomerLabel: '客户',
dialogCustomerPlaceholder: '请选择客户',
selectCustomerDialogTitle: '选择客户',
dialogCodeLabel: '任务单编码',
dialogCodeTooltip: '任务单编码',
dialogCodePlaceholder: '编码保存后自动生成',
@ -4141,6 +4289,8 @@ export default {
dialogSubmitButtonText: '确 定',
dialogCancelButtonText: '取 消',
validatorTaskNameRequired: '任务单名称不能为空',
validatorCustomerRequired: '客户不能为空',
validatorDeliveryDateRequired: '交货日期不能为空',
validatorTaskTypeRequired: '任务类型不能为空',
validatorIsUrgentRequired: '是否急单不能为空',

@ -9,13 +9,13 @@
>
<el-row>
<el-col :span="12">
<el-form-item label="客户名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入客户名称" />
<el-form-item :label="t('MesCustomer.fields.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('MesCustomer.placeholders.name')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户来源" prop="source">
<el-select v-model="formData.source" placeholder="请选择客户来源" class="w-1/1">
<el-form-item :label="t('MesCustomer.fields.source')" prop="source">
<el-select v-model="formData.source" :placeholder="t('MesCustomer.placeholders.source')" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
:key="dict.value"
@ -28,11 +28,11 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="客户编码" prop="customerCode">
<el-form-item :label="t('MesCustomer.fields.customerCode')" prop="customerCode">
<div class="customer-code-field">
<el-input
v-model="formData.customerCode"
placeholder="请输入客户编码"
:placeholder="t('MesCustomer.placeholders.customerCode')"
:disabled="Boolean(formData.isCode) || formType === 'update'"
/>
<el-switch
@ -44,19 +44,19 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人" prop="contactName">
<el-input v-model="formData.contactName" placeholder="请输入联系人" />
<el-form-item :label="t('MesCustomer.fields.contactName')" prop="contactName">
<el-input v-model="formData.contactName" :placeholder="t('MesCustomer.placeholders.contactName')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="联系人手机" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系人手机" />
<el-form-item :label="t('MesCustomer.fields.mobile')" prop="mobile">
<el-input v-model="formData.mobile" :placeholder="t('MesCustomer.placeholders.mobile')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="ownerUserId">
<el-form-item :label="t('MesCustomer.fields.ownerUser')" prop="ownerUserId">
<el-select
v-model="formData.ownerUserId"
:disabled="formType !== 'create'"
@ -74,32 +74,32 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="联系人电话" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入联系人电话" />
<el-form-item :label="t('MesCustomer.fields.telephone')" prop="telephone">
<el-input v-model="formData.telephone" :placeholder="t('MesCustomer.placeholders.telephone')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系人邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入联系人邮箱" />
<el-form-item :label="t('MesCustomer.fields.email')" prop="email">
<el-input v-model="formData.email" :placeholder="t('MesCustomer.placeholders.email')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="微信" prop="wechat">
<el-input v-model="formData.wechat" placeholder="请输入微信" />
<el-form-item :label="t('MesCustomer.fields.wechat')" prop="wechat">
<el-input v-model="formData.wechat" :placeholder="t('MesCustomer.placeholders.wechat')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="QQ" prop="qq">
<el-input v-model="formData.qq" placeholder="请输入 QQ" />
<el-form-item :label="t('MesCustomer.fields.qq')" prop="qq">
<el-input v-model="formData.qq" :placeholder="t('MesCustomer.placeholders.qq')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="客户行业" prop="industryId">
<el-select v-model="formData.industryId" placeholder="请选择客户行业" class="w-1/1">
<el-form-item :label="t('MesCustomer.fields.industry')" prop="industryId">
<el-select v-model="formData.industryId" :placeholder="t('MesCustomer.placeholders.industry')" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
:key="dict.value"
@ -110,8 +110,8 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户级别" prop="level">
<el-select v-model="formData.level" placeholder="请选择客户级别" class="w-1/1">
<el-form-item :label="t('MesCustomer.fields.level')" prop="level">
<el-select v-model="formData.level" :placeholder="t('MesCustomer.placeholders.level')" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
:key="dict.value"
@ -124,7 +124,7 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="地址" prop="areaId">
<el-form-item :label="t('MesCustomer.fields.address')" prop="areaId">
<el-cascader
v-model="formData.areaId"
:options="areaList"
@ -132,22 +132,22 @@
class="w-1/1"
clearable
filterable
placeholder="请选择城市"
:placeholder="t('MesCustomer.placeholders.city')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="详细地址" prop="detailAddress">
<el-input v-model="formData.detailAddress" placeholder="请输入详细地址" />
<el-form-item :label="t('MesCustomer.fields.detailAddress')" prop="detailAddress">
<el-input v-model="formData.detailAddress" :placeholder="t('MesCustomer.placeholders.detailAddress')" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="下次联系时间" prop="contactNextTime">
<el-form-item :label="t('MesCustomer.fields.contactNextTime')" prop="contactNextTime">
<el-date-picker
v-model="formData.contactNextTime"
placeholder="选择下次联系时间"
:placeholder="t('MesCustomer.placeholders.contactNextTime')"
type="datetime"
value-format="x"
class="!w-1/1"
@ -155,15 +155,15 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('MesCustomer.fields.remark')" prop="remark">
<el-input type="textarea" v-model="formData.remark" :placeholder="t('MesCustomer.placeholders.remark')" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="submitForm">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -210,16 +210,16 @@ const validateCustomerCode = (_rule, value, callback) => {
return
}
if (value === undefined || value === null || String(value).trim() === '') {
callback(new Error('客户编码不能为空'))
callback(new Error(t('MesCustomer.messages.customerCodeRequired')))
return
}
callback()
}
const formRules = reactive({
name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
name: [{ required: true, message: t('MesCustomer.messages.nameRequired'), trigger: 'blur' }],
customerCode: [{ validator: validateCustomerCode, trigger: ['blur', 'change'] }],
ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }]
ownerUserId: [{ required: true, message: t('MesCustomer.messages.ownerRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref

@ -1,8 +1,8 @@
<!-- 客户导入窗口 -->
<template>
<Dialog v-model="dialogVisible" title="客户导入" width="400">
<Dialog v-model="dialogVisible" :title="t('MesCustomer.import.title')" width="400">
<div class="flex items-center my-10px">
<span class="mr-10px">负责人</span>
<span class="mr-10px">{{ t('MesCustomer.fields.ownerUser') }}</span>
<el-select v-model="ownerUserId" class="!w-240px" clearable>
<el-option
v-for="item in userOptions"
@ -24,28 +24,32 @@
drag
>
<Icon icon="ep:upload" />
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__text">
{{ t('MesCustomer.import.dragText') }}<em>{{ t('MesCustomer.import.clickText') }}</em>
</div>
<template #tip>
<div class="el-upload__tip text-center">
<div class="el-upload__tip">
<el-checkbox v-model="updateSupport" />
是否更新已经存在的客户数据客户名称重复
{{ t('MesCustomer.import.updateSupport') }}
</div>
<span>仅允许导入 xlsxlsx 格式文件</span>
<span>{{ t('MesCustomer.import.formatLimit') }}</span>
<el-link
:underline="false"
style="font-size: 12px; vertical-align: baseline"
type="primary"
@click="importTemplate"
>
下载模板
{{ t('MesCustomer.actions.downloadTemplate') }}
</el-link>
</div>
</template>
</el-upload>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="submitForm">
{{ t('common.ok') }}
</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -59,6 +63,7 @@ import { useUserStore } from '@/store/modules/user'
defineOptions({ name: 'SystemUserImportForm' })
const message = useMessage() //
const { t } = useI18n() //
const dialogVisible = ref(false) //
const formLoading = ref(false) //
@ -81,7 +86,7 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const submitForm = async () => {
if (fileList.value.length == 0) {
message.error('请上传文件')
message.error(t('MesCustomer.messages.uploadFileRequired'))
return
}
@ -110,15 +115,17 @@ const submitFormSuccess = (response: any) => {
}
//
const data = response.data
let text = '上传成功数量:' + data.createCustomerNames.length + ';'
let text = t('MesCustomer.messages.uploadCreateCount', { count: data.createCustomerNames.length })
for (let customerName of data.createCustomerNames) {
text += '< ' + customerName + ' >'
}
text += '更新成功数量:' + data.updateCustomerNames.length + ';'
text += t('MesCustomer.messages.uploadUpdateCount', { count: data.updateCustomerNames.length })
for (const customerName of data.updateCustomerNames) {
text += '< ' + customerName + ' >'
}
text += '更新失败数量:' + Object.keys(data.failureCustomerNames).length + ';'
text += t('MesCustomer.messages.uploadFailureCount', {
count: Object.keys(data.failureCustomerNames).length
})
for (const customerName in data.failureCustomerNames) {
text += '< ' + customerName + ': ' + data.failureCustomerNames[customerName] + ' >'
}
@ -131,7 +138,7 @@ const submitFormSuccess = (response: any) => {
/** 上传错误提示 */
const submitFormError = (): void => {
message.error('上传失败,请您重新上传!')
message.error(t('MesCustomer.messages.uploadFailed'))
formLoading.value = false
}
@ -147,12 +154,12 @@ const resetForm = async () => {
/** 文件数超出提示 */
const handleExceed = (): void => {
message.error('最多只能上传一个文件!')
message.error(t('MesCustomer.messages.uploadFileLimit'))
}
/** 下载模板操作 */
const importTemplate = async () => {
const res = await CustomerApi.importCustomerTemplate()
download.excel(res, '客户导入模版.xls')
download.excel(res, t('MesCustomer.filenames.importTemplate'))
}
</script>

@ -17,14 +17,14 @@
</div>
<ContentWrap class="mt-10px">
<el-descriptions :column="5" direction="vertical">
<el-descriptions-item label="客户级别">
<el-descriptions-item :label="t('MesCustomer.fields.level')">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="customer.level" />
</el-descriptions-item>
<el-descriptions-item label="成交状态">
{{ customer.dealStatus ? '已成交' : '未成交' }}
<el-descriptions-item :label="t('MesCustomer.fields.dealStatus')">
{{ customer.dealStatus ? t('MesCustomer.status.dealDone') : t('MesCustomer.status.dealUndone') }}
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
<el-descriptions-item :label="t('MesCustomer.fields.ownerUser')">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.createTime')">
{{ formatDate(customer.createTime) }}
</el-descriptions-item>
</el-descriptions>
@ -36,6 +36,7 @@ import * as CustomerApi from '@/api/mes/customer'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'MesCustomerDetailsHeader' })
const { t } = useI18n() //
defineProps<{
customer: CustomerApi.CustomerVO //
loading: boolean //

@ -3,53 +3,53 @@
<el-collapse v-model="activeNames" class="">
<el-collapse-item name="basicInfo">
<template #title>
<span class="text-base font-bold">基本信息</span>
<span class="text-base font-bold">{{ t('MesCustomer.tabs.basicInfo') }}</span>
</template>
<el-descriptions :column="4">
<el-descriptions-item label="客户名称">
<el-descriptions-item :label="t('MesCustomer.fields.name')">
{{ customer.name }}
</el-descriptions-item>
<el-descriptions-item label="客户来源">
<el-descriptions-item :label="t('MesCustomer.fields.source')">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="customer.source" />
</el-descriptions-item>
<el-descriptions-item label="手机">{{ customer.mobile }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ customer.telephone }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ customer.email }}</el-descriptions-item>
<el-descriptions-item label="地址">
<el-descriptions-item :label="t('MesCustomer.fields.mobile')">{{ customer.mobile }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.telephone')">{{ customer.telephone }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.email')">{{ customer.email }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.address')">
{{ customer.areaName }} {{ customer.detailAddress }}
</el-descriptions-item>
<el-descriptions-item label="QQ">{{ customer.qq }}</el-descriptions-item>
<el-descriptions-item label="微信">{{ customer.wechat }}</el-descriptions-item>
<el-descriptions-item label="客户行业">
<el-descriptions-item :label="t('MesCustomer.fields.wechat')">{{ customer.wechat }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.industry')">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="customer.industryId" />
</el-descriptions-item>
<el-descriptions-item label="客户级别">
<el-descriptions-item :label="t('MesCustomer.fields.level')">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="customer.level" />
</el-descriptions-item>
<el-descriptions-item label="下次联系时间">
<el-descriptions-item :label="t('MesCustomer.fields.contactNextTime')">
{{ formatDate(customer.contactNextTime) }}
</el-descriptions-item>
<el-descriptions-item label="备注">{{ customer.remark }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.remark')">{{ customer.remark }}</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
<el-collapse-item name="systemInfo">
<template #title>
<span class="text-base font-bold">系统信息</span>
<span class="text-base font-bold">{{ t('MesCustomer.tabs.systemInfo') }}</span>
</template>
<el-descriptions :column="4">
<el-descriptions-item label="负责人">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="最后跟进记录">
<el-descriptions-item :label="t('MesCustomer.fields.ownerUser')">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.contactLastContent')">
{{ customer.contactLastContent }}
</el-descriptions-item>
<el-descriptions-item label="最后跟进时间">
<el-descriptions-item :label="t('MesCustomer.fields.contactLastTime')">
{{ formatDate(customer.contactLastTime) }}
</el-descriptions-item>
<el-descriptions-item label="">&nbsp;</el-descriptions-item>
<el-descriptions-item label="创建人">{{ customer.creatorName }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
<el-descriptions-item :label="t('MesCustomer.fields.creator')">{{ customer.creatorName }}</el-descriptions-item>
<el-descriptions-item :label="t('MesCustomer.fields.createTime')">
{{ formatDate(customer.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="更新时间">
<el-descriptions-item :label="t('MesCustomer.fields.updateTime')">
{{ formatDate(customer.updateTime) }}
</el-descriptions-item>
</el-descriptions>
@ -63,6 +63,7 @@ import { DICT_TYPE } from '@/utils/dict'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'MesCustomerDetailsInfo' })
const { t } = useI18n() //
const { customer } = defineProps<{
customer: CustomerApi.CustomerVO //
}>()

@ -6,49 +6,51 @@
type="primary"
@click="openForm"
>
编辑
{{ t('action.update') }}
</el-button>
<el-button v-if="permissionListRef?.validateOwnerUser" type="primary" @click="transfer">
转移
{{ t('MesCustomer.actions.transfer') }}
</el-button>
<el-button v-if="permissionListRef?.validateWrite" @click="handleUpdateDealStatus">
更改成交状态
{{ t('MesCustomer.actions.updateDealStatus') }}
</el-button>
<el-button
v-if="customer.lockStatus && permissionListRef?.validateOwnerUser"
@click="handleUnlock"
>
解锁
{{ t('MesCustomer.actions.unlock') }}
</el-button>
<el-button
v-if="!customer.lockStatus && permissionListRef?.validateOwnerUser"
@click="handleLock"
>
锁定
{{ t('MesCustomer.actions.lock') }}
</el-button>
<el-button v-if="!customer.ownerUserId" type="primary" @click="handleReceive">
{{ t('MesCustomer.actions.receive') }}
</el-button>
<el-button v-if="!customer.ownerUserId" type="primary" @click="handleReceive"> </el-button>
<el-button v-if="!customer.ownerUserId" type="primary" @click="handleDistributeForm">
分配
{{ t('MesCustomer.actions.distribute') }}
</el-button>
<el-button
v-if="customer.ownerUserId && permissionListRef?.validateOwnerUser"
@click="handlePutPool"
>
放入公海
{{ t('MesCustomer.actions.putPool') }}
</el-button>
</CustomerDetailsHeader>
<el-col>
<el-tabs>
<el-tab-pane label="跟进记录">
<el-tab-pane :label="t('MesCustomer.tabs.followUp')">
<FollowUpList :biz-id="customerId" :biz-type="CUSTOMER_BIZ_TYPE" />
</el-tab-pane>
<el-tab-pane label="基本信息">
<el-tab-pane :label="t('MesCustomer.tabs.basicInfo')">
<CustomerDetailsInfo :customer="customer" />
</el-tab-pane>
<el-tab-pane label="联系人" lazy>
<el-tab-pane :label="t('MesCustomer.tabs.contacts')" lazy>
<ContactList :biz-id="customer.id!" :biz-type="CUSTOMER_BIZ_TYPE" />
</el-tab-pane>
<el-tab-pane label="团队成员">
<el-tab-pane :label="t('MesCustomer.tabs.team')">
<PermissionList
ref="permissionListRef"
:biz-id="customer.id!"
@ -57,17 +59,17 @@
@quit-team="close"
/>
</el-tab-pane>
<el-tab-pane label="商机" lazy>
<el-tab-pane :label="t('MesCustomer.tabs.business')" lazy>
<BusinessList :biz-id="customer.id!" :biz-type="CUSTOMER_BIZ_TYPE" />
</el-tab-pane>
<el-tab-pane label="合同" lazy>
<el-tab-pane :label="t('MesCustomer.tabs.contract')" lazy>
<ContractList :biz-id="customer.id!" :biz-type="CUSTOMER_BIZ_TYPE" />
</el-tab-pane>
<el-tab-pane label="回款" lazy>
<el-tab-pane :label="t('MesCustomer.tabs.receivable')" lazy>
<ReceivablePlanList :customer-id="customer.id!" @create-receivable="createReceivable" />
<ReceivableList ref="receivableListRef" :customer-id="customer.id!" />
</el-tab-pane>
<el-tab-pane label="操作日志">
<el-tab-pane :label="t('MesCustomer.tabs.operateLog')">
<OperateLogV2 :log-list="logList" />
</el-tab-pane>
</el-tabs>
@ -103,6 +105,7 @@ const CUSTOMER_BIZ_TYPE = 2
const customerId = ref(0) //
const loading = ref(true) //
const message = useMessage() //
const { t } = useI18n() //
const { delView } = useTagsViewStore() //
const { push, currentRoute } = useRouter() //
@ -131,10 +134,14 @@ const handleUpdateDealStatus = async () => {
const dealStatus = !customer.value.dealStatus
try {
//
await message.confirm(`确定更新成交状态为【${dealStatus ? '已成交' : '未成交'}】吗?`)
await message.confirm(
t('MesCustomer.messages.updateDealStatusConfirm', {
status: dealStatus ? t('MesCustomer.status.dealDone') : t('MesCustomer.status.dealUndone')
})
)
//
await CustomerApi.updateCustomerDealStatus(customerId.value, dealStatus)
message.success(`更新成交状态成功`)
message.success(t('MesCustomer.messages.updateDealStatusSuccess'))
//
await getCustomer()
} catch {}
@ -148,25 +155,25 @@ const transfer = () => {
/** 锁定客户 */
const handleLock = async () => {
await message.confirm(`确定锁定客户【${customer.value.name}】 吗?`)
await message.confirm(t('MesCustomer.messages.lockConfirm', { name: customer.value.name }))
await CustomerApi.lockCustomer(unref(customerId.value), true)
message.success(`锁定客户【${customer.value.name}】成功`)
message.success(t('MesCustomer.messages.lockSuccess', { name: customer.value.name }))
await getCustomer()
}
/** 解锁客户 */
const handleUnlock = async () => {
await message.confirm(`确定解锁客户【${customer.value.name}】 吗?`)
await message.confirm(t('MesCustomer.messages.unlockConfirm', { name: customer.value.name }))
await CustomerApi.lockCustomer(unref(customerId.value), false)
message.success(`解锁客户【${customer.value.name}】成功`)
message.success(t('MesCustomer.messages.unlockSuccess', { name: customer.value.name }))
await getCustomer()
}
/** 领取客户 */
const handleReceive = async () => {
await message.confirm(`确定领取客户【${customer.value.name}】 吗?`)
await message.confirm(t('MesCustomer.messages.receiveConfirm', { name: customer.value.name }))
await CustomerApi.receiveCustomer([unref(customerId.value)])
message.success(`领取客户【${customer.value.name}】成功`)
message.success(t('MesCustomer.messages.receiveSuccess', { name: customer.value.name }))
await getCustomer()
}
@ -178,9 +185,9 @@ const handleDistributeForm = async () => {
/** 客户放入公海 */
const handlePutPool = async () => {
await message.confirm(`确定将客户【${customer.value.name}】放入公海吗?`)
await message.confirm(t('MesCustomer.messages.putPoolConfirm', { name: customer.value.name }))
await CustomerApi.putCustomerPool(unref(customerId.value))
message.success(`客户【${customer.value.name}】放入公海成功`)
message.success(t('MesCustomer.messages.putPoolSuccess', { name: customer.value.name }))
//
close()
}
@ -213,7 +220,7 @@ const close = () => {
const { params } = useRoute()
onMounted(() => {
if (!params.id) {
message.warning('参数错误,客户不能为空!')
message.warning(t('MesCustomer.messages.customerRequired'))
close()
return
}

@ -11,30 +11,30 @@
class="-mb-15px"
min-label-width="68px"
>
<el-form-item label="客户名称" prop="name">
<el-form-item :label="t('MesCustomer.fields.name')" prop="name">
<el-input
v-model="queryParams.name"
class="!w-240px"
clearable
placeholder="请输入客户名称"
:placeholder="t('MesCustomer.placeholders.name')"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="联系人手机" prop="mobile">
<el-form-item :label="t('MesCustomer.fields.mobile')" prop="mobile">
<el-input
v-model="queryParams.mobile"
class="!w-240px"
clearable
placeholder="请输入联系人手机"
:placeholder="t('MesCustomer.placeholders.mobile')"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="所属行业" prop="industryId">
<el-form-item :label="t('MesCustomer.fields.industryBelong')" prop="industryId">
<el-select
v-model="queryParams.industryId"
class="!w-240px"
clearable
placeholder="请选择所属行业"
:placeholder="t('MesCustomer.placeholders.industryBelong')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
@ -44,12 +44,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户级别" prop="level">
<el-form-item :label="t('MesCustomer.fields.level')" prop="level">
<el-select
v-model="queryParams.level"
class="!w-240px"
clearable
placeholder="请选择客户级别"
:placeholder="t('MesCustomer.placeholders.level')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
@ -59,12 +59,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户来源" prop="source">
<el-form-item :label="t('MesCustomer.fields.source')" prop="source">
<el-select
v-model="queryParams.source"
class="!w-240px"
clearable
placeholder="请选择客户来源"
:placeholder="t('MesCustomer.placeholders.source')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
@ -77,19 +77,19 @@
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
{{ t('common.reset') }}
</el-button>
<el-button v-hasPermi="['mes:customer:create']" type="primary" @click="openForm('create')">
<Icon class="mr-5px" icon="ep:plus" />
新增
{{ t('action.create') }}
</el-button>
<!-- <el-button v-hasPermi="['mes:customer:import']" plain type="warning" @click="handleImport">
<Icon icon="ep:upload" />
导入
{{ t('action.import') }}
</el-button> -->
<el-button
v-hasPermi="['mes:customer:export']"
@ -99,7 +99,7 @@
@click="handleExport"
>
<Icon class="mr-5px" icon="ep:download" />
导出
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -108,32 +108,32 @@
<!-- 列表 -->
<ContentWrap>
<!-- <el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="我负责的" name="1" />
<el-tab-pane label="我参与的" name="2" />
<el-tab-pane label="下属负责的" name="3" />
<el-tab-pane :label="t('MesCustomer.tabs.owner')" name="1" />
<el-tab-pane :label="t('MesCustomer.tabs.participant')" name="2" />
<el-tab-pane :label="t('MesCustomer.tabs.subordinate')" name="3" />
</el-tabs> -->
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" fixed="left" label="客户名称" prop="name" width="160" sortable>
<el-table-column align="center" fixed="left" :label="t('MesCustomer.fields.name')" prop="name" width="160" sortable>
<template #default="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column align="center" fixed="left" label="客户编码" prop="customerCode" width="140" sortable />
<el-table-column align="center" label="联系人" prop="contactName" width="120" />
<el-table-column align="center" label="客户来源" prop="source" width="100">
<el-table-column align="center" fixed="left" :label="t('MesCustomer.fields.customerCode')" prop="customerCode" width="140" sortable />
<el-table-column align="center" :label="t('MesCustomer.fields.contactName')" prop="contactName" width="120" />
<el-table-column align="center" :label="t('MesCustomer.fields.source')" prop="source" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template>
</el-table-column>
<el-table-column align="center" label="联系人手机" prop="mobile" width="120" />
<el-table-column align="center" label="联系人电话" prop="telephone" width="130" />
<el-table-column align="center" label="联系人邮箱" prop="email" width="180" />
<el-table-column align="center" label="客户级别" prop="level" width="135">
<el-table-column align="center" :label="t('MesCustomer.fields.mobile')" prop="mobile" width="120" />
<el-table-column align="center" :label="t('MesCustomer.fields.telephone')" prop="telephone" width="130" />
<el-table-column align="center" :label="t('MesCustomer.fields.email')" prop="email" width="180" />
<el-table-column align="center" :label="t('MesCustomer.fields.level')" prop="level" width="135">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
</template>
</el-table-column>
<el-table-column align="center" label="客户行业" prop="industryId" width="100">
<el-table-column align="center" :label="t('MesCustomer.fields.industry')" prop="industryId" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
@ -141,17 +141,17 @@
<el-table-column
:formatter="dateFormatter"
align="center"
label="下次联系时间"
:label="t('MesCustomer.fields.contactNextTime')"
prop="contactNextTime"
width="180px"
sortable />
<el-table-column align="center" label="备注" prop="remark" width="200" />
<el-table-column align="center" label="锁定状态" prop="lockStatus" sortable>
<el-table-column align="center" :label="t('MesCustomer.fields.remark')" prop="remark" width="200" />
<el-table-column align="center" :label="t('MesCustomer.fields.lockStatus')" prop="lockStatus" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" />
</template>
</el-table-column>
<el-table-column align="center" label="成交状态" prop="dealStatus" sortable>
<el-table-column align="center" :label="t('MesCustomer.fields.dealStatus')" prop="dealStatus" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template>
@ -159,33 +159,33 @@
<el-table-column
:formatter="dateFormatter"
align="center"
label="最后跟进时间"
:label="t('MesCustomer.fields.contactLastTime')"
prop="contactLastTime"
width="180px"
sortable />
<el-table-column align="center" label="最后跟进记录" prop="contactLastContent" width="200" />
<el-table-column align="center" label="地址" prop="detailAddress" width="180" />
<el-table-column align="center" label="距离进入公海天数" prop="poolDay" width="140">
<template #default="scope"> {{ scope.row.poolDay }} </template>
<el-table-column align="center" :label="t('MesCustomer.fields.contactLastContent')" prop="contactLastContent" width="200" />
<el-table-column align="center" :label="t('MesCustomer.fields.address')" prop="detailAddress" width="180" />
<el-table-column align="center" :label="t('MesCustomer.fields.poolDay')" prop="poolDay" width="140">
<template #default="scope"> {{ scope.row.poolDay }} {{ t('MesCustomer.units.days') }}</template>
</el-table-column>
<el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" sortable />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" sortable />
<el-table-column align="center" :label="t('MesCustomer.fields.ownerUser')" prop="ownerUserName" width="100px" sortable />
<el-table-column align="center" :label="t('MesCustomer.fields.ownerDept')" prop="ownerUserDeptName" width="100px" sortable />
<el-table-column
:formatter="dateFormatter"
align="center"
label="更新时间"
:label="t('MesCustomer.fields.updateTime')"
prop="updateTime"
width="180px"
sortable />
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
:label="t('MesCustomer.fields.createTime')"
prop="createTime"
width="180px"
sortable />
<el-table-column align="center" label="创建人" prop="creatorName" width="100px" sortable />
<el-table-column align="center" fixed="right" label="操作" min-width="150">
<el-table-column align="center" :label="t('MesCustomer.fields.creator')" prop="creatorName" width="100px" sortable />
<el-table-column align="center" fixed="right" :label="t('MesCustomer.fields.operate')" min-width="150">
<template #default="scope">
<el-button
v-hasPermi="['mes:customer:update']"
@ -193,7 +193,7 @@
type="primary"
@click="openForm('update', scope.row.id)"
>
编辑
{{ t('action.update') }}
</el-button>
<el-button
v-hasPermi="['mes:customer:delete']"
@ -201,7 +201,7 @@
type="danger"
@click="handleDelete(scope.row.id)"
>
删除
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
@ -321,7 +321,7 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await CustomerApi.exportCustomer(queryParams)
download.excel(data, '客户.xls')
download.excel(data, t('MesCustomer.filenames.customerExport'))
} catch {
} finally {
exportLoading.value = false

@ -7,7 +7,7 @@
label-width="200px"
v-loading="formLoading"
>
<el-form-item label="规则适用人群" prop="userIds">
<el-form-item :label="t('MesCustomer.limitConfig.ruleUsers')" prop="userIds">
<el-select multiple filterable v-model="formData.userIds">
<el-option
v-for="item in userOptions"
@ -17,7 +17,7 @@
/>
</el-select>
</el-form-item>
<el-form-item label="规则适用部门" prop="deptIds">
<el-form-item :label="t('MesCustomer.limitConfig.ruleDepts')" prop="deptIds">
<el-tree-select
v-model="formData.deptIds"
:data="deptTree"
@ -26,21 +26,21 @@
filterable
check-strictly
node-key="id"
placeholder="请选择规则适用部门"
:placeholder="t('MesCustomer.limitConfig.deptPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="
formData.type === LimitConfType.CUSTOMER_QUANTITY_LIMIT
? '拥有客户数上限'
: '锁定客户数上限'
? t('MesCustomer.limitConfig.customerQuantityMax')
: t('MesCustomer.limitConfig.customerLockMax')
"
prop="maxCount"
>
<el-input-number v-model="formData.maxCount" placeholder="请输入数量上限" />
<el-input-number v-model="formData.maxCount" :placeholder="t('MesCustomer.limitConfig.maxCountPlaceholder')" />
</el-form-item>
<el-form-item
label="成交客户是否占用拥有客户数"
:label="t('MesCustomer.limitConfig.dealCountEnabled')"
v-if="formData.type === LimitConfType.CUSTOMER_QUANTITY_LIMIT"
prop="dealCountEnabled"
>
@ -48,8 +48,8 @@
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -78,8 +78,8 @@ const formData = ref({
dealCountEnabled: false
})
const formRules = reactive({
type: [{ required: true, message: '规则类型不能为空', trigger: 'change' }],
maxCount: [{ required: true, message: '数量上限不能为空', trigger: 'blur' }]
type: [{ required: true, message: t('MesCustomer.messages.ruleTypeRequired'), trigger: 'change' }],
maxCount: [{ required: true, message: t('MesCustomer.messages.maxCountRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref
const deptTree = ref() //

@ -1,12 +1,12 @@
<template>
<el-button plain @click="handleQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 刷新 </el-button>
<el-button plain @click="handleQuery"> <Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reload') }} </el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['mes:customer-limit-config:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.create') }}
</el-button>
<el-table
v-loading="loading"
@ -15,27 +15,29 @@
:show-overflow-tooltip="true"
class="mt-4"
>
<el-table-column label="编号" align="center" prop="id" />
<el-table-column :label="t('MesCustomer.fields.id')" align="center" prop="id" />
<el-table-column
label="规则适用人群"
:label="t('MesCustomer.limitConfig.ruleUsers')"
align="center"
:formatter="(row) => row.users?.map((user: any) => user.nickname).join('')"
/>
<el-table-column
label="规则适用部门"
:label="t('MesCustomer.limitConfig.ruleDepts')"
align="center"
:formatter="(row) => row.depts?.map((dept: any) => dept.name).join('')"
/>
<el-table-column
:label="
confType === LimitConfType.CUSTOMER_QUANTITY_LIMIT ? '拥有客户数上限' : '锁定客户数上限'
confType === LimitConfType.CUSTOMER_QUANTITY_LIMIT
? t('MesCustomer.limitConfig.customerQuantityMax')
: t('MesCustomer.limitConfig.customerLockMax')
"
align="center"
prop="maxCount"
/>
<el-table-column
v-if="confType === LimitConfType.CUSTOMER_QUANTITY_LIMIT"
label="成交客户是否占用拥有客户数"
:label="t('MesCustomer.limitConfig.dealCountEnabled')"
align="center"
prop="dealCountEnabled"
min-width="100"
@ -45,13 +47,13 @@
</template>
</el-table-column>
<el-table-column
label="创建时间"
:label="t('MesCustomer.fields.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
sortable />
<el-table-column label="操作" align="center" min-width="110" fixed="right">
<el-table-column :label="t('MesCustomer.fields.operate')" align="center" min-width="110" fixed="right">
<template #default="scope">
<el-button
link
@ -59,7 +61,7 @@
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:customer-limit-config:update']"
>
编辑
{{ t('action.update') }}
</el-button>
<el-button
link
@ -67,7 +69,7 @@
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:customer-limit-config:delete']"
>
删除
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>

@ -5,10 +5,10 @@
<!-- 列表 -->
<ContentWrap>
<el-tabs>
<el-tab-pane label="拥有客户数限制">
<el-tab-pane :label="t('MesCustomer.limitConfig.customerQuantityLimit')">
<CustomerLimitConfigList :confType="LimitConfType.CUSTOMER_QUANTITY_LIMIT" />
</el-tab-pane>
<el-tab-pane label="锁定客户数限制">
<el-tab-pane :label="t('MesCustomer.limitConfig.customerLockLimit')">
<CustomerLimitConfigList :confType="LimitConfType.CUSTOMER_LOCK_LIMIT" />
</el-tab-pane>
</el-tabs>
@ -19,4 +19,5 @@ import CustomerLimitConfigList from './CustomerLimitConfigList.vue'
import { LimitConfType } from '@/api/mes/customer/limitConfig'
defineOptions({ name: 'MesCustomerLimitConfig' })
const { t } = useI18n() //
</script>

@ -1,5 +1,5 @@
<template>
<Dialog v-model="dialogVisible" title="分配客户">
<Dialog v-model="dialogVisible" :title="t('MesCustomer.actions.distribute')">
<el-form
ref="formRef"
v-loading="formLoading"
@ -7,7 +7,7 @@
:rules="formRules"
label-width="100px"
>
<el-form-item label="负责人" prop="ownerUserId">
<el-form-item :label="t('MesCustomer.fields.ownerUser')" prop="ownerUserId">
<el-select v-model="formData.ownerUserId" class="w-1/1">
<el-option
v-for="item in userOptions"
@ -19,8 +19,8 @@
</el-form-item>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="submitForm">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -40,7 +40,7 @@ const formData = ref({
ownerUserId: undefined
})
const formRules = reactive({
ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }]
ownerUserId: [{ required: true, message: t('MesCustomer.messages.ownerRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref
@ -65,7 +65,7 @@ const submitForm = async () => {
formLoading.value = true
try {
await CustomerApi.distributeCustomer([formData.value.id], formData.value.ownerUserId)
message.success('分配客户成功')
message.success(t('MesCustomer.messages.distributeSuccess'))
dialogVisible.value = false
//
emit('success')

@ -11,30 +11,30 @@
class="-mb-15px"
label-width="68px"
>
<el-form-item label="客户名称" prop="name">
<el-form-item :label="t('MesCustomer.fields.name')" prop="name">
<el-input
v-model="queryParams.name"
class="!w-240px"
clearable
placeholder="请输入客户名称"
:placeholder="t('MesCustomer.placeholders.name')"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="手机" prop="mobile">
<el-form-item :label="t('MesCustomer.fields.mobile')" prop="mobile">
<el-input
v-model="queryParams.mobile"
class="!w-240px"
clearable
placeholder="请输入手机"
:placeholder="t('MesCustomer.placeholders.mobile')"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="所属行业" prop="industryId">
<el-form-item :label="t('MesCustomer.fields.industryBelong')" prop="industryId">
<el-select
v-model="queryParams.industryId"
class="!w-240px"
clearable
placeholder="请选择所属行业"
:placeholder="t('MesCustomer.placeholders.industryBelong')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
@ -44,12 +44,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户级别" prop="level">
<el-form-item :label="t('MesCustomer.fields.level')" prop="level">
<el-select
v-model="queryParams.level"
class="!w-240px"
clearable
placeholder="请选择客户级别"
:placeholder="t('MesCustomer.placeholders.level')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
@ -59,12 +59,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="客户来源" prop="source">
<el-form-item :label="t('MesCustomer.fields.source')" prop="source">
<el-select
v-model="queryParams.source"
class="!w-240px"
clearable
placeholder="请选择客户来源"
:placeholder="t('MesCustomer.placeholders.source')"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
@ -77,11 +77,11 @@
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery(undefined)">
<Icon class="mr-5px" icon="ep:refresh" />
重置
{{ t('common.reset') }}
</el-button>
<el-button
v-hasPermi="['mes:customer:export']"
@ -91,7 +91,7 @@
@click="handleExport"
>
<Icon class="mr-5px" icon="ep:download" />
导出
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -100,27 +100,27 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" label="客户名称" fixed="left" prop="name" width="160" sortable>
<el-table-column align="center" :label="t('MesCustomer.fields.name')" fixed="left" prop="name" width="160" sortable>
<template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="客户来源" prop="source" width="100">
<el-table-column align="center" :label="t('MesCustomer.fields.source')" prop="source" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template>
</el-table-column>
<el-table-column label="手机" align="center" prop="mobile" width="120" />
<el-table-column label="电话" align="center" prop="telephone" width="130" />
<el-table-column label="邮箱" align="center" prop="email" width="180" />
<el-table-column align="center" label="客户级别" prop="level" width="135">
<el-table-column :label="t('MesCustomer.fields.mobile')" align="center" prop="mobile" width="120" />
<el-table-column :label="t('MesCustomer.fields.telephone')" align="center" prop="telephone" width="130" />
<el-table-column :label="t('MesCustomer.fields.email')" align="center" prop="email" width="180" />
<el-table-column align="center" :label="t('MesCustomer.fields.level')" prop="level" width="135">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
</template>
</el-table-column>
<el-table-column align="center" label="客户行业" prop="industryId" width="100">
<el-table-column align="center" :label="t('MesCustomer.fields.industry')" prop="industryId" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
@ -128,12 +128,12 @@
<el-table-column
:formatter="dateFormatter"
align="center"
label="下次联系时间"
:label="t('MesCustomer.fields.contactNextTime')"
prop="contactNextTime"
width="180px"
sortable />
<el-table-column align="center" label="备注" prop="remark" width="200" />
<el-table-column align="center" label="成交状态" prop="dealStatus" sortable>
<el-table-column align="center" :label="t('MesCustomer.fields.remark')" prop="remark" width="200" />
<el-table-column align="center" :label="t('MesCustomer.fields.dealStatus')" prop="dealStatus" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template>
@ -141,26 +141,26 @@
<el-table-column
:formatter="dateFormatter"
align="center"
label="最后跟进时间"
:label="t('MesCustomer.fields.contactLastTime')"
prop="contactLastTime"
width="180px"
sortable />
<el-table-column align="center" label="最后跟进记录" prop="contactLastContent" width="200" />
<el-table-column align="center" :label="t('MesCustomer.fields.contactLastContent')" prop="contactLastContent" width="200" />
<el-table-column
:formatter="dateFormatter"
align="center"
label="更新时间"
:label="t('MesCustomer.fields.updateTime')"
prop="updateTime"
width="180px"
sortable />
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
:label="t('MesCustomer.fields.createTime')"
prop="createTime"
width="180px"
sortable />
<el-table-column align="center" label="创建人" prop="creatorName" width="100px" sortable />
<el-table-column align="center" :label="t('MesCustomer.fields.creator')" prop="creatorName" width="100px" sortable />
</el-table>
<!-- 分页 -->
<Pagination
@ -181,6 +181,7 @@ import * as CustomerApi from '@/api/mes/customer'
defineOptions({ name: 'MesCustomerPool' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const total = ref(0) //
@ -248,7 +249,7 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await CustomerApi.exportCustomer(queryParams.value)
download.excel(data, '客户公海.xls')
download.excel(data, t('MesCustomer.pool.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -14,43 +14,43 @@
<!-- 操作 -->
<template #header>
<div class="flex items-center justify-between">
<CardTitle title="客户公海规则设置" />
<CardTitle :title="t('MesCustomer.poolConfig.title')" />
<el-button
type="primary"
@click="onSubmit"
v-hasPermi="['mes:customer-pool-config:update']"
>
保存
{{ t('common.save') }}
</el-button>
</div>
</template>
<!-- 表单 -->
<el-form-item label="客户公海规则设置" prop="enabled">
<el-form-item :label="t('MesCustomer.poolConfig.ruleSetting')" prop="enabled">
<el-radio-group v-model="formData.enabled" @change="changeEnable" class="ml-4">
<el-radio :value="false" size="large">不启用</el-radio>
<el-radio :value="true" size="large">启用</el-radio>
<el-radio :value="false" size="large">{{ t('common.no') }}</el-radio>
<el-radio :value="true" size="large">{{ t('common.yes') }}</el-radio>
</el-radio-group>
</el-form-item>
<div v-if="formData.enabled">
<el-form-item>
<el-input-number class="mr-2" v-model="formData.contactExpireDays" />
天不跟进或
{{ t('MesCustomer.poolConfig.noFollowPrefix') }}
<el-input-number class="mx-2" v-model="formData.dealExpireDays" />
天未成交
{{ t('MesCustomer.poolConfig.noDealSuffix') }}
</el-form-item>
<el-form-item label="提前提醒设置" prop="notifyEnabled">
<el-form-item :label="t('MesCustomer.poolConfig.notifySetting')" prop="notifyEnabled">
<el-radio-group
v-model="formData.notifyEnabled"
@change="changeNotifyEnable"
class="ml-4"
>
<el-radio :value="false" size="large">不提醒</el-radio>
<el-radio :value="true" size="large">提醒</el-radio>
<el-radio :value="false" size="large">{{ t('common.no') }}</el-radio>
<el-radio :value="true" size="large">{{ t('common.yes') }}</el-radio>
</el-radio-group>
</el-form-item>
<div v-if="formData.notifyEnabled">
<el-form-item>
提前 <el-input-number class="mx-2" v-model="formData.notifyDays" /> 天提醒
{{ t('MesCustomer.poolConfig.notifyPrefix') }} <el-input-number class="mx-2" v-model="formData.notifyDays" /> {{ t('MesCustomer.poolConfig.notifySuffix') }}
</el-form-item>
</div>
</div>
@ -76,7 +76,7 @@ const formData = ref({
notifyDays: undefined
})
const formRules = reactive({
enabled: [{ required: true, message: '是否启用客户公海不能为空', trigger: 'blur' }]
enabled: [{ required: true, message: t('MesCustomer.messages.poolEnabledRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref

Loading…
Cancel
Save