|
@@ -0,0 +1,280 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="yd-page-container">
|
|
|
|
|
+ <wd-navbar
|
|
|
|
|
+ :title="getTitle"
|
|
|
|
|
+ left-arrow placeholder safe-area-inset-top fixed
|
|
|
|
|
+ @click-left="handleBack"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <view>
|
|
|
|
|
+ <wd-form ref="formRef" :model="formData" :rules="formRules">
|
|
|
|
|
+ <wd-cell-group border>
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.name"
|
|
|
|
|
+ label="客户名称"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ prop="name"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入客户名称"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-select-picker
|
|
|
|
|
+ v-model="formData.source"
|
|
|
|
|
+ label="客户来源"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ :columns="sourceDictOptions"
|
|
|
|
|
+ value-key="value"
|
|
|
|
|
+ label-key="label"
|
|
|
|
|
+ type="radio"
|
|
|
|
|
+ placeholder="请选择"
|
|
|
|
|
+ />
|
|
|
|
|
+ <UserPicker v-model="formData.ownerUserId" label="负责人" type="radio" />
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.mobile"
|
|
|
|
|
+ label="手机号"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ prop="mobile"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入手机号"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.telephone"
|
|
|
|
|
+ label="固定电话"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入固定电话"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.email"
|
|
|
|
|
+ label="邮箱"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ prop="email"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入邮箱"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.wechat"
|
|
|
|
|
+ label="微信"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入微信"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-input
|
|
|
|
|
+ v-model="formData.qq"
|
|
|
|
|
+ label="QQ"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请输入QQ"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-select-picker
|
|
|
|
|
+ v-model="formData.industryId"
|
|
|
|
|
+ label="客户行业"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ :columns="industryDictOptions"
|
|
|
|
|
+ value-key="value"
|
|
|
|
|
+ label-key="label"
|
|
|
|
|
+ type="radio"
|
|
|
|
|
+ placeholder="请选择"
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-select-picker
|
|
|
|
|
+ v-model="formData.level"
|
|
|
|
|
+ label="客户级别"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ :columns="levelDictOptions"
|
|
|
|
|
+ value-key="value"
|
|
|
|
|
+ label-key="label"
|
|
|
|
|
+ type="radio"
|
|
|
|
|
+ placeholder="请选择"
|
|
|
|
|
+ />
|
|
|
|
|
+ <AreaPicker v-model="formData.areaId" label="地址" />
|
|
|
|
|
+ <wd-textarea
|
|
|
|
|
+ v-model="formData.detailAddress"
|
|
|
|
|
+ label="详细地址"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ placeholder="请输入详细地址"
|
|
|
|
|
+ :maxlength="200"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ clearable
|
|
|
|
|
+ />
|
|
|
|
|
+ <wd-cell title="下次联系时间" title-width="180rpx" center>
|
|
|
|
|
+ <wd-datetime-picker
|
|
|
|
|
+ v-model="contactNextTimeValue"
|
|
|
|
|
+ type="datetime"
|
|
|
|
|
+ :min-date="minDate"
|
|
|
|
|
+ @confirm="handleDateTimeConfirm"
|
|
|
|
|
+ />
|
|
|
|
|
+ </wd-cell>
|
|
|
|
|
+ <wd-textarea
|
|
|
|
|
+ v-model="formData.remark"
|
|
|
|
|
+ label="备注"
|
|
|
|
|
+ label-width="180rpx"
|
|
|
|
|
+ placeholder="请输入备注"
|
|
|
|
|
+ :maxlength="200"
|
|
|
|
|
+ show-word-limit
|
|
|
|
|
+ clearable
|
|
|
|
|
+ />
|
|
|
|
|
+ </wd-cell-group>
|
|
|
|
|
+ </wd-form>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="yd-detail-footer">
|
|
|
|
|
+ <wd-button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ block
|
|
|
|
|
+ :loading="formLoading"
|
|
|
|
|
+ @click="handleSubmit"
|
|
|
|
|
+ >
|
|
|
|
|
+ 保存
|
|
|
|
|
+ </wd-button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
|
|
|
|
|
+import type { CustomerVO } from '@/api/crm/customer'
|
|
|
|
|
+import { computed, onMounted, ref } from 'vue'
|
|
|
|
|
+import { useToast } from 'wot-design-uni'
|
|
|
|
|
+import { createCustomer, getCustomer, updateCustomer } from '@/api/crm/customer'
|
|
|
|
|
+import { AreaPicker, UserPicker } from '@/components/system-select'
|
|
|
|
|
+import { getIntDictOptions } from '@/hooks/useDict'
|
|
|
|
|
+import { useUserStore } from '@/store/user'
|
|
|
|
|
+import { navigateBackPlus } from '@/utils'
|
|
|
|
|
+import { DICT_TYPE } from '@/utils/constants'
|
|
|
|
|
+import { isEmail, isMobile } from '@/utils/validator'
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps<{
|
|
|
|
|
+ id?: number | any
|
|
|
|
|
+}>()
|
|
|
|
|
+
|
|
|
|
|
+definePage({
|
|
|
|
|
+ style: {
|
|
|
|
|
+ navigationBarTitleText: '',
|
|
|
|
|
+ navigationStyle: 'custom',
|
|
|
|
|
+ },
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const toast = useToast()
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
|
|
+const getTitle = computed(() => props.id ? '编辑客户' : '新增客户')
|
|
|
|
|
+const formLoading = ref(false)
|
|
|
|
|
+const minDate = new Date()
|
|
|
|
|
+
|
|
|
|
|
+const formData = ref<Partial<CustomerVO>>({
|
|
|
|
|
+ id: undefined,
|
|
|
|
|
+ name: undefined,
|
|
|
|
|
+ contactNextTime: undefined,
|
|
|
|
|
+ ownerUserId: undefined,
|
|
|
|
|
+ mobile: undefined,
|
|
|
|
|
+ telephone: undefined,
|
|
|
|
|
+ qq: undefined,
|
|
|
|
|
+ wechat: undefined,
|
|
|
|
|
+ email: undefined,
|
|
|
|
|
+ areaId: undefined,
|
|
|
|
|
+ detailAddress: undefined,
|
|
|
|
|
+ industryId: undefined,
|
|
|
|
|
+ level: undefined,
|
|
|
|
|
+ source: undefined,
|
|
|
|
|
+ remark: undefined,
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const contactNextTimeValue = ref<number | null>(null)
|
|
|
|
|
+
|
|
|
|
|
+const formRules = {
|
|
|
|
|
+ name: [{ required: true, message: '客户名称不能为空' }],
|
|
|
|
|
+ ownerUserId: [{ required: true, message: '负责人不能为空' }],
|
|
|
|
|
+ mobile: [
|
|
|
|
|
+ { required: true, message: '手机号不能为空' },
|
|
|
|
|
+ { validator: (value: string) => isMobile(value), message: '请输入正确的手机号' },
|
|
|
|
|
+ ],
|
|
|
|
|
+ email: [{ required: false, validator: (value: string) => !value || isEmail(value), message: '请输入正确的邮箱地址' }],
|
|
|
|
|
+}
|
|
|
|
|
+const formRef = ref<FormInstance>()
|
|
|
|
|
+
|
|
|
|
|
+const sourceDictOptions = computed(() => getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE))
|
|
|
|
|
+const industryDictOptions = computed(() => getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY))
|
|
|
|
|
+const levelDictOptions = computed(() => getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL))
|
|
|
|
|
+
|
|
|
|
|
+function handleDateTimeConfirm({ value }: { value: number | null }) {
|
|
|
|
|
+ formData.value.contactNextTime = value ? new Date(value) : undefined
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function handleBack() {
|
|
|
|
|
+ navigateBackPlus('/pages-crm/customer/index')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function getDetail() {
|
|
|
|
|
+ if (!props.id) {
|
|
|
|
|
+ formData.value.ownerUserId = userStore.userInfo?.id
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = await getCustomer(Number(props.id))
|
|
|
|
|
+ formData.value = {
|
|
|
|
|
+ id: data.id,
|
|
|
|
|
+ name: data.name,
|
|
|
|
|
+ contactNextTime: data.contactNextTime ? new Date(data.contactNextTime) : undefined,
|
|
|
|
|
+ ownerUserId: data.ownerUserId,
|
|
|
|
|
+ mobile: data.mobile,
|
|
|
|
|
+ telephone: data.telephone,
|
|
|
|
|
+ qq: data.qq,
|
|
|
|
|
+ wechat: data.wechat,
|
|
|
|
|
+ email: data.email,
|
|
|
|
|
+ areaId: data.areaId,
|
|
|
|
|
+ detailAddress: data.detailAddress,
|
|
|
|
|
+ industryId: data.industryId,
|
|
|
|
|
+ level: data.level,
|
|
|
|
|
+ source: data.source,
|
|
|
|
|
+ remark: data.remark,
|
|
|
|
|
+ }
|
|
|
|
|
+ if (data.contactNextTime) {
|
|
|
|
|
+ contactNextTimeValue.value = new Date(data.contactNextTime).getTime()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function prepareFormData(): Partial<CustomerVO> {
|
|
|
|
|
+ const data = { ...formData.value }
|
|
|
|
|
+ if (Array.isArray(data.source)) {
|
|
|
|
|
+ data.source = data.source[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Array.isArray(data.industryId)) {
|
|
|
|
|
+ data.industryId = data.industryId[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Array.isArray(data.level)) {
|
|
|
|
|
+ data.level = data.level[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Array.isArray(data.ownerUserId)) {
|
|
|
|
|
+ data.ownerUserId = data.ownerUserId[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ if (Array.isArray(data.areaId)) {
|
|
|
|
|
+ data.areaId = data.areaId[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ return data
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function handleSubmit() {
|
|
|
|
|
+ const { valid } = await formRef.value?.validate()
|
|
|
|
|
+ if (!valid) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ formLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const submitData = prepareFormData()
|
|
|
|
|
+ if (props.id) {
|
|
|
|
|
+ await updateCustomer(submitData as CustomerVO)
|
|
|
|
|
+ toast.success('修改成功')
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await createCustomer(submitData as CustomerVO)
|
|
|
|
|
+ toast.success('新增成功')
|
|
|
|
|
+ }
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ handleBack()
|
|
|
|
|
+ }, 500)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ formLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ getDetail()
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|