commit
						929fa9a208
					
				|  | @ -0,0 +1,46 @@ | ||||||
|  | import request from '@/config/axios' | ||||||
|  | 
 | ||||||
|  | export interface ClueVO { | ||||||
|  |   id: number | ||||||
|  |   transformStatus: boolean | ||||||
|  |   followUpStatus: boolean | ||||||
|  |   name: string | ||||||
|  |   customerId: number | ||||||
|  |   contactNextTime: Date | ||||||
|  |   telephone: string | ||||||
|  |   mobile: string | ||||||
|  |   address: string | ||||||
|  |   ownerUserId: number | ||||||
|  |   contactLastTime: Date | ||||||
|  |   remark: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 查询线索列表
 | ||||||
|  | export const getCluePage = async (params) => { | ||||||
|  |   return await request.get({ url: `/crm/clue/page`, params }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 查询线索详情
 | ||||||
|  | export const getClue = async (id: number) => { | ||||||
|  |   return await request.get({ url: `/crm/clue/get?id=` + id }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 新增线索
 | ||||||
|  | export const createClue = async (data: ClueVO) => { | ||||||
|  |   return await request.post({ url: `/crm/clue/create`, data }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 修改线索
 | ||||||
|  | export const updateClue = async (data: ClueVO) => { | ||||||
|  |   return await request.put({ url: `/crm/clue/update`, data }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 删除线索
 | ||||||
|  | export const deleteClue = async (id: number) => { | ||||||
|  |   return await request.delete({ url: `/crm/clue/delete?id=` + id }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 导出线索 Excel
 | ||||||
|  | export const exportClue = async (params) => { | ||||||
|  |   return await request.download({ url: `/crm/clue/export-excel`, params }) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,53 @@ | ||||||
|  | import request from '@/config/axios' | ||||||
|  | 
 | ||||||
|  | export interface ContractVO { | ||||||
|  |   id: number | ||||||
|  |   name: string | ||||||
|  |   customerId: number | ||||||
|  |   businessId: number | ||||||
|  |   processInstanceId: number | ||||||
|  |   orderDate: Date | ||||||
|  |   ownerUserId: number | ||||||
|  |   no: string | ||||||
|  |   startTime: Date | ||||||
|  |   endTime: Date | ||||||
|  |   price: number | ||||||
|  |   discountPercent: number | ||||||
|  |   productPrice: number | ||||||
|  |   roUserIds: string | ||||||
|  |   rwUserIds: string | ||||||
|  |   contactId: number | ||||||
|  |   signUserId: number | ||||||
|  |   contactLastTime: Date | ||||||
|  |   remark: string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 查询合同列表
 | ||||||
|  | export const getContractPage = async (params) => { | ||||||
|  |   return await request.get({ url: `/crm/contract/page`, params }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 查询合同详情
 | ||||||
|  | export const getContract = async (id: number) => { | ||||||
|  |   return await request.get({ url: `/crm/contract/get?id=` + id }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 新增合同
 | ||||||
|  | export const createContract = async (data: ContractVO) => { | ||||||
|  |   return await request.post({ url: `/crm/contract/create`, data }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 修改合同
 | ||||||
|  | export const updateContract = async (data: ContractVO) => { | ||||||
|  |   return await request.put({ url: `/crm/contract/update`, data }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 删除合同
 | ||||||
|  | export const deleteContract = async (id: number) => { | ||||||
|  |   return await request.delete({ url: `/crm/contract/delete?id=` + id }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 导出合同 Excel
 | ||||||
|  | export const exportContract = async (params) => { | ||||||
|  |   return await request.download({ url: `/crm/contract/export-excel`, params }) | ||||||
|  | } | ||||||
|  | @ -1,13 +1,20 @@ | ||||||
| <template> | <template> | ||||||
|   <el-drawer v-model="drawerVisible" title="子任务" size="70%"> |   <el-drawer v-model="drawerVisible" title="子任务" size="70%"> | ||||||
|  |     <!-- 当前任务 --> | ||||||
|     <template #header> |     <template #header> | ||||||
|       <h4>【{{ baseTask.name }} 】审批人:{{ baseTask.assigneeUser?.nickname }}</h4> |       <h4>【{{ baseTask.name }} 】审批人:{{ baseTask.assigneeUser?.nickname }}</h4> | ||||||
|       <el-button style="margin-left: 5px" v-if="showSubSignButton(baseTask)" type="danger" plain @click="handleSubSign(baseTask)"> |       <el-button | ||||||
|         <Icon icon="ep:remove" /> |         style="margin-left: 5px" | ||||||
|         减签 |         v-if="isSubSignButtonVisible(baseTask)" | ||||||
|  |         type="danger" | ||||||
|  |         plain | ||||||
|  |         @click="handleSubSign(baseTask)" | ||||||
|  |       > | ||||||
|  |         <Icon icon="ep:remove" /> 减签 | ||||||
|       </el-button> |       </el-button> | ||||||
|     </template> |     </template> | ||||||
|     <el-table :data="tableData" style="width: 100%" row-key="id" border> |     <!-- 子任务列表 --> | ||||||
|  |     <el-table :data="baseTask.children" style="width: 100%" row-key="id" border> | ||||||
|       <el-table-column prop="assigneeUser.nickname" label="审批人" /> |       <el-table-column prop="assigneeUser.nickname" label="审批人" /> | ||||||
|       <el-table-column prop="assigneeUser.deptName" label="所在部门" /> |       <el-table-column prop="assigneeUser.deptName" label="所在部门" /> | ||||||
|       <el-table-column label="审批状态" prop="result"> |       <el-table-column label="审批状态" prop="result"> | ||||||
|  | @ -32,18 +39,17 @@ | ||||||
|       <el-table-column label="操作" prop="operation"> |       <el-table-column label="操作" prop="operation"> | ||||||
|         <template #default="scope"> |         <template #default="scope"> | ||||||
|           <el-button |           <el-button | ||||||
|             v-if="showSubSignButton(scope.row)" |             v-if="isSubSignButtonVisible(scope.row)" | ||||||
|             type="danger" |             type="danger" | ||||||
|             plain |             plain | ||||||
|             @click="handleSubSign(scope.row)" |             @click="handleSubSign(scope.row)" | ||||||
|           > |           > | ||||||
|             <Icon icon="ep:remove" /> |             <Icon icon="ep:remove" /> 减签 | ||||||
|             减签 |  | ||||||
|           </el-button> |           </el-button> | ||||||
|         </template> |         </template> | ||||||
|       </el-table-column> |       </el-table-column> | ||||||
|     </el-table> |     </el-table> | ||||||
|     <!--  减签   --> |     <!-- 减签 --> | ||||||
|     <TaskSubSignDialogForm ref="taskSubSignDialogForm" /> |     <TaskSubSignDialogForm ref="taskSubSignDialogForm" /> | ||||||
|   </el-drawer> |   </el-drawer> | ||||||
| </template> | </template> | ||||||
|  | @ -53,12 +59,11 @@ import { DICT_TYPE } from '@/utils/dict' | ||||||
| import { dateFormatter } from '@/utils/formatTime' | import { dateFormatter } from '@/utils/formatTime' | ||||||
| import TaskSubSignDialogForm from './TaskSubSignDialogForm.vue' | import TaskSubSignDialogForm from './TaskSubSignDialogForm.vue' | ||||||
| 
 | 
 | ||||||
| const message = useMessage() // 消息弹窗 | defineOptions({ name: 'ProcessInstanceChildrenTaskList' }) | ||||||
| defineOptions({ name: 'ProcessInstancechildrenList' }) |  | ||||||
| 
 | 
 | ||||||
|  | const message = useMessage() // 消息弹窗 | ||||||
| const drawerVisible = ref(false) // 抽屉的是否展示 | const drawerVisible = ref(false) // 抽屉的是否展示 | ||||||
| 
 | 
 | ||||||
| const tableData = ref<any[]>([]) //表格数据 |  | ||||||
| const baseTask = ref<object>({}) | const baseTask = ref<object>({}) | ||||||
| /** 打开弹窗 */ | /** 打开弹窗 */ | ||||||
| const open = async (task: any) => { | const open = async (task: any) => { | ||||||
|  | @ -67,30 +72,22 @@ const open = async (task: any) => { | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
|   baseTask.value = task |   baseTask.value = task | ||||||
|   //设置表格数据 |   // 展开抽屉 | ||||||
|   tableData.value = task.children |  | ||||||
|   //展开抽屉 |  | ||||||
|   drawerVisible.value = true |   drawerVisible.value = true | ||||||
| } | } | ||||||
| defineExpose({ open }) // 提供 openModal 方法,用于打开弹窗 | defineExpose({ open }) // 提供 openModal 方法,用于打开弹窗 | ||||||
| 
 | 
 | ||||||
| const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | /** 发起减签 */ | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 减签 |  | ||||||
|  */ |  | ||||||
| const taskSubSignDialogForm = ref() | const taskSubSignDialogForm = ref() | ||||||
| const handleSubSign = (item) => { | const handleSubSign = (item) => { | ||||||
|   taskSubSignDialogForm.value.open(item.id) |   taskSubSignDialogForm.value.open(item.id) | ||||||
|  |   // TODO @海洋:减签后,需要刷新下界面哈 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** 是否显示减签按钮 */ | ||||||
|  * 显示减签按钮 | const isSubSignButtonVisible = (task: any) => { | ||||||
|  * @param task |   if (task && task.children && !isEmpty(task.children)) { | ||||||
|  */ |     // 有子任务,且子任务有任意一个是 待处理 和 待前置任务完成 则显示减签按钮 | ||||||
| const showSubSignButton = (task:any) => { |  | ||||||
|   if(!isEmpty(task.children)){ |  | ||||||
|     //有子任务,且子任务有任意一个是 待处理 和 待前置任务完成 则显示减签按钮 |  | ||||||
|     const subTask = task.children.find((item) => item.result === 1 || item.result === 9) |     const subTask = task.children.find((item) => item.result === 1 || item.result === 9) | ||||||
|     return !isEmpty(subTask) |     return !isEmpty(subTask) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -22,12 +22,12 @@ | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
|     </el-form> |     </el-form> | ||||||
|     <template #footer> |     <template #footer> | ||||||
|       <el-button :disabled="formLoading" type="primary" @click="submitForm('before')" |       <el-button :disabled="formLoading" type="primary" @click="submitForm('before')"> | ||||||
|         >向前加签</el-button |         向前加签 | ||||||
|       > |       </el-button> | ||||||
|       <el-button :disabled="formLoading" type="primary" @click="submitForm('after')" |       <el-button :disabled="formLoading" type="primary" @click="submitForm('after')"> | ||||||
|         >向后加签</el-button |         向后加签 | ||||||
|       > |       </el-button> | ||||||
|       <el-button @click="dialogVisible = false">取 消</el-button> |       <el-button @click="dialogVisible = false">取 消</el-button> | ||||||
|     </template> |     </template> | ||||||
|   </Dialog> |   </Dialog> | ||||||
|  |  | ||||||
|  | @ -114,7 +114,7 @@ import TaskUpdateAssigneeForm from './TaskUpdateAssigneeForm.vue' | ||||||
| import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue' | import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue' | ||||||
| import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue' | import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue' | ||||||
| import TaskReturnDialog from './TaskReturnDialogForm.vue' | import TaskReturnDialog from './TaskReturnDialogForm.vue' | ||||||
| import TaskDelegateForm from './taskDelegateForm.vue' | import TaskDelegateForm from './TaskDelegateForm.vue' | ||||||
| import TaskAddSignDialogForm from './TaskAddSignDialogForm.vue' | import TaskAddSignDialogForm from './TaskAddSignDialogForm.vue' | ||||||
| import { registerComponent } from '@/utils/routerHelper' | import { registerComponent } from '@/utils/routerHelper' | ||||||
| import { isEmpty } from '@/utils/is' | import { isEmpty } from '@/utils/is' | ||||||
|  |  | ||||||
|  | @ -0,0 +1,165 @@ | ||||||
|  | <template> | ||||||
|  |   <Dialog :title="dialogTitle" v-model="dialogVisible"> | ||||||
|  |     <el-form | ||||||
|  |       ref="formRef" | ||||||
|  |       :model="formData" | ||||||
|  |       :rules="formRules" | ||||||
|  |       label-width="100px" | ||||||
|  |       v-loading="formLoading" | ||||||
|  |     > | ||||||
|  |       <el-form-item label="转化状态" prop="transformStatus"> | ||||||
|  |         <el-radio-group v-model="formData.transformStatus"> | ||||||
|  |           <el-radio | ||||||
|  |             v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" | ||||||
|  |             :key="dict.value" | ||||||
|  |             :label="dict.value" | ||||||
|  |           > | ||||||
|  |             {{ dict.label }} | ||||||
|  |           </el-radio> | ||||||
|  |         </el-radio-group> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="跟进状态" prop="followUpStatus"> | ||||||
|  |         <el-radio-group v-model="formData.followUpStatus"> | ||||||
|  |           <el-radio | ||||||
|  |             v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" | ||||||
|  |             :key="dict.value" | ||||||
|  |             :label="dict.value" | ||||||
|  |           > | ||||||
|  |             {{ dict.label }} | ||||||
|  |           </el-radio> | ||||||
|  |         </el-radio-group> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="线索名称" prop="name"> | ||||||
|  |         <el-input v-model="formData.name" placeholder="请输入线索名称" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <!-- TODO 客户选择 --> | ||||||
|  |       <el-form-item label="客户" prop="customerId"> | ||||||
|  |         <el-input v-model="formData.customerId" placeholder="请选择客户" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="下次联系时间" prop="contactNextTime"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="formData.contactNextTime" | ||||||
|  |           type="date" | ||||||
|  |           value-format="x" | ||||||
|  |           placeholder="选择下次联系时间" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="电话" prop="telephone"> | ||||||
|  |         <el-input v-model="formData.telephone" placeholder="请输入电话" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="手机号" prop="mobile"> | ||||||
|  |         <el-input v-model="formData.mobile" placeholder="请输入手机号" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="地址" prop="address"> | ||||||
|  |         <el-input v-model="formData.address" placeholder="请输入地址" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <!-- TODO 负责人选择 --> | ||||||
|  |       <el-form-item label="负责人" prop="ownerUserId"> | ||||||
|  |         <el-input v-model="formData.ownerUserId" placeholder="请输入负责人" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="备注" prop="remark"> | ||||||
|  |         <el-input v-model="formData.remark" placeholder="请输入备注" /> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  |     <template #footer> | ||||||
|  |       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> | ||||||
|  |       <el-button @click="dialogVisible = false">取 消</el-button> | ||||||
|  |     </template> | ||||||
|  |   </Dialog> | ||||||
|  | </template> | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict' | ||||||
|  | import * as ClueApi from '@/api/crm/clue' | ||||||
|  | 
 | ||||||
|  | const { t } = useI18n() // 国际化 | ||||||
|  | const message = useMessage() // 消息弹窗 | ||||||
|  | 
 | ||||||
|  | const dialogVisible = ref(false) // 弹窗的是否展示 | ||||||
|  | const dialogTitle = ref('') // 弹窗的标题 | ||||||
|  | const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||||
|  | const formType = ref('') // 表单的类型:create - 新增;update - 修改 | ||||||
|  | const formData = ref({ | ||||||
|  |   id: undefined, | ||||||
|  |   transformStatus: undefined, | ||||||
|  |   followUpStatus: undefined, | ||||||
|  |   name: undefined, | ||||||
|  |   customerId: undefined, | ||||||
|  |   contactNextTime: undefined, | ||||||
|  |   telephone: undefined, | ||||||
|  |   mobile: undefined, | ||||||
|  |   address: undefined, | ||||||
|  |   ownerUserId: undefined, | ||||||
|  |   contactLastTime: undefined, | ||||||
|  |   remark: undefined | ||||||
|  | }) | ||||||
|  | const formRules = reactive({ | ||||||
|  |   transformStatus: [{ required: true, message: '转化状态不能为空', trigger: 'blur' }], | ||||||
|  |   followUpStatus: [{ required: true, message: '跟进状态不能为空', trigger: 'blur' }], | ||||||
|  |   name: [{ required: true, message: '线索名称不能为空', trigger: 'blur' }], | ||||||
|  |   customerId: [{ required: true, message: '客户id不能为空', trigger: 'blur' }] | ||||||
|  | }) | ||||||
|  | const formRef = ref() // 表单 Ref | ||||||
|  | 
 | ||||||
|  | /** 打开弹窗 */ | ||||||
|  | const open = async (type: string, id?: number) => { | ||||||
|  |   dialogVisible.value = true | ||||||
|  |   dialogTitle.value = t('action.' + type) | ||||||
|  |   formType.value = type | ||||||
|  |   resetForm() | ||||||
|  |   // 修改时,设置数据 | ||||||
|  |   if (id) { | ||||||
|  |     formLoading.value = true | ||||||
|  |     try { | ||||||
|  |       formData.value = await ClueApi.getClue(id) | ||||||
|  |     } finally { | ||||||
|  |       formLoading.value = false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||||
|  | 
 | ||||||
|  | /** 提交表单 */ | ||||||
|  | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||||||
|  | const submitForm = async () => { | ||||||
|  |   // 校验表单 | ||||||
|  |   if (!formRef) return | ||||||
|  |   const valid = await formRef.value.validate() | ||||||
|  |   if (!valid) return | ||||||
|  |   // 提交请求 | ||||||
|  |   formLoading.value = true | ||||||
|  |   try { | ||||||
|  |     const data = formData.value as unknown as ClueApi.ClueVO | ||||||
|  |     if (formType.value === 'create') { | ||||||
|  |       await ClueApi.createClue(data) | ||||||
|  |       message.success(t('common.createSuccess')) | ||||||
|  |     } else { | ||||||
|  |       await ClueApi.updateClue(data) | ||||||
|  |       message.success(t('common.updateSuccess')) | ||||||
|  |     } | ||||||
|  |     dialogVisible.value = false | ||||||
|  |     // 发送操作成功的事件 | ||||||
|  |     emit('success') | ||||||
|  |   } finally { | ||||||
|  |     formLoading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置表单 */ | ||||||
|  | const resetForm = () => { | ||||||
|  |   formData.value = { | ||||||
|  |     id: undefined, | ||||||
|  |     transformStatus: undefined, | ||||||
|  |     followUpStatus: undefined, | ||||||
|  |     name: undefined, | ||||||
|  |     customerId: undefined, | ||||||
|  |     contactNextTime: undefined, | ||||||
|  |     telephone: undefined, | ||||||
|  |     mobile: undefined, | ||||||
|  |     address: undefined, | ||||||
|  |     ownerUserId: undefined, | ||||||
|  |     contactLastTime: undefined, | ||||||
|  |     remark: undefined | ||||||
|  |   } | ||||||
|  |   formRef.value?.resetFields() | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | @ -0,0 +1,318 @@ | ||||||
|  | <template> | ||||||
|  |   <ContentWrap> | ||||||
|  |     <!-- 搜索工作栏 --> | ||||||
|  |     <el-form | ||||||
|  |       class="-mb-15px" | ||||||
|  |       :model="queryParams" | ||||||
|  |       ref="queryFormRef" | ||||||
|  |       :inline="true" | ||||||
|  |       label-width="68px" | ||||||
|  |     > | ||||||
|  |       <el-form-item label="转化状态" prop="transformStatus"> | ||||||
|  |         <el-select | ||||||
|  |           v-model="queryParams.transformStatus" | ||||||
|  |           placeholder="请选择转化状态" | ||||||
|  |           clearable | ||||||
|  |           class="!w-240px" | ||||||
|  |         > | ||||||
|  |           <el-option | ||||||
|  |             v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" | ||||||
|  |             :key="dict.value" | ||||||
|  |             :label="dict.label" | ||||||
|  |             :value="dict.value" | ||||||
|  |           /> | ||||||
|  |         </el-select> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="跟进状态" prop="followUpStatus"> | ||||||
|  |         <el-select | ||||||
|  |           v-model="queryParams.followUpStatus" | ||||||
|  |           placeholder="请选择跟进状态" | ||||||
|  |           clearable | ||||||
|  |           class="!w-240px" | ||||||
|  |         > | ||||||
|  |           <el-option | ||||||
|  |             v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" | ||||||
|  |             :key="dict.value" | ||||||
|  |             :label="dict.label" | ||||||
|  |             :value="dict.value" | ||||||
|  |           /> | ||||||
|  |         </el-select> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="线索名称" prop="name"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.name" | ||||||
|  |           placeholder="请输入线索名称" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="客户id" prop="customerId"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.customerId" | ||||||
|  |           placeholder="请输入客户id" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="下次联系时间" prop="contactNextTime"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="queryParams.contactNextTime" | ||||||
|  |           value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |           type="daterange" | ||||||
|  |           start-placeholder="开始日期" | ||||||
|  |           end-placeholder="结束日期" | ||||||
|  |           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="电话" prop="telephone"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.telephone" | ||||||
|  |           placeholder="请输入电话" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="手机号" prop="mobile"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.mobile" | ||||||
|  |           placeholder="请输入手机号" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="地址" prop="address"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.address" | ||||||
|  |           placeholder="请输入地址" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="负责人" prop="ownerUserId"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.ownerUserId" | ||||||
|  |           placeholder="请输入负责人" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="最后跟进时间" prop="contactLastTime"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="queryParams.contactLastTime" | ||||||
|  |           value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |           type="daterange" | ||||||
|  |           start-placeholder="开始日期" | ||||||
|  |           end-placeholder="结束日期" | ||||||
|  |           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="创建时间" prop="createTime"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="queryParams.createTime" | ||||||
|  |           value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |           type="daterange" | ||||||
|  |           start-placeholder="开始日期" | ||||||
|  |           end-placeholder="结束日期" | ||||||
|  |           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item> | ||||||
|  |         <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> | ||||||
|  |         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> | ||||||
|  |         <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:clue:create']"> | ||||||
|  |           <Icon icon="ep:plus" class="mr-5px" /> 新增 | ||||||
|  |         </el-button> | ||||||
|  |         <el-button | ||||||
|  |           type="success" | ||||||
|  |           plain | ||||||
|  |           @click="handleExport" | ||||||
|  |           :loading="exportLoading" | ||||||
|  |           v-hasPermi="['crm:clue:export']" | ||||||
|  |         > | ||||||
|  |           <Icon icon="ep:download" class="mr-5px" /> 导出 | ||||||
|  |         </el-button> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  |   </ContentWrap> | ||||||
|  | 
 | ||||||
|  |   <!-- 列表 --> | ||||||
|  |   <ContentWrap> | ||||||
|  |     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> | ||||||
|  |       <el-table-column label="编号" align="center" prop="id" /> | ||||||
|  |       <el-table-column label="转化状态" align="center" prop="transformStatus"> | ||||||
|  |         <template #default="scope"> | ||||||
|  |           <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.transformStatus" /> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |       <el-table-column label="跟进状态" align="center" prop="followUpStatus"> | ||||||
|  |         <template #default="scope"> | ||||||
|  |           <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.followUpStatus" /> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |       <el-table-column label="线索名称" align="center" prop="name" /> | ||||||
|  |       <el-table-column label="客户id" align="center" prop="customerId" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="下次联系时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="contactNextTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="电话" align="center" prop="telephone" /> | ||||||
|  |       <el-table-column label="手机号" align="center" prop="mobile" /> | ||||||
|  |       <el-table-column label="地址" align="center" prop="address" /> | ||||||
|  |       <el-table-column label="负责人" align="center" prop="ownerUserId" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="最后跟进时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="contactLastTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="备注" align="center" prop="remark" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="创建时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="createTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="操作" align="center"> | ||||||
|  |         <template #default="scope"> | ||||||
|  |           <el-button | ||||||
|  |             link | ||||||
|  |             type="primary" | ||||||
|  |             @click="openForm('update', scope.row.id)" | ||||||
|  |             v-hasPermi="['crm:clue:update']" | ||||||
|  |           > | ||||||
|  |             编辑 | ||||||
|  |           </el-button> | ||||||
|  |           <el-button | ||||||
|  |             link | ||||||
|  |             type="danger" | ||||||
|  |             @click="handleDelete(scope.row.id)" | ||||||
|  |             v-hasPermi="['crm:clue:delete']" | ||||||
|  |           > | ||||||
|  |             删除 | ||||||
|  |           </el-button> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |     </el-table> | ||||||
|  |     <!-- 分页 --> | ||||||
|  |     <Pagination | ||||||
|  |       :total="total" | ||||||
|  |       v-model:page="queryParams.pageNo" | ||||||
|  |       v-model:limit="queryParams.pageSize" | ||||||
|  |       @pagination="getList" | ||||||
|  |     /> | ||||||
|  |   </ContentWrap> | ||||||
|  | 
 | ||||||
|  |   <!-- 表单弹窗:添加/修改 --> | ||||||
|  |   <ClueForm ref="formRef" @success="getList" /> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict' | ||||||
|  | import { dateFormatter } from '@/utils/formatTime' | ||||||
|  | import download from '@/utils/download' | ||||||
|  | import * as ClueApi from '@/api/crm/clue' | ||||||
|  | import ClueForm from './ClueForm.vue' | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'CrmClue' }) | ||||||
|  | 
 | ||||||
|  | const message = useMessage() // 消息弹窗 | ||||||
|  | const { t } = useI18n() // 国际化 | ||||||
|  | 
 | ||||||
|  | const loading = ref(true) // 列表的加载中 | ||||||
|  | const total = ref(0) // 列表的总页数 | ||||||
|  | const list = ref([]) // 列表的数据 | ||||||
|  | const queryParams = reactive({ | ||||||
|  |   pageNo: 1, | ||||||
|  |   pageSize: 10, | ||||||
|  |   transformStatus: null, | ||||||
|  |   followUpStatus: null, | ||||||
|  |   name: null, | ||||||
|  |   customerId: null, | ||||||
|  |   contactNextTime: [], | ||||||
|  |   telephone: null, | ||||||
|  |   mobile: null, | ||||||
|  |   address: null, | ||||||
|  |   ownerUserId: null, | ||||||
|  |   contactLastTime: [], | ||||||
|  |   createTime: [] | ||||||
|  | }) | ||||||
|  | const queryFormRef = ref() // 搜索的表单 | ||||||
|  | const exportLoading = ref(false) // 导出的加载中 | ||||||
|  | 
 | ||||||
|  | /** 查询列表 */ | ||||||
|  | const getList = async () => { | ||||||
|  |   loading.value = true | ||||||
|  |   try { | ||||||
|  |     const data = await ClueApi.getCluePage(queryParams) | ||||||
|  |     list.value = data.list | ||||||
|  |     total.value = data.total | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   queryParams.pageNo = 1 | ||||||
|  |   getList() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   queryFormRef.value.resetFields() | ||||||
|  |   handleQuery() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 添加/修改操作 */ | ||||||
|  | const formRef = ref() | ||||||
|  | const openForm = (type: string, id?: number) => { | ||||||
|  |   formRef.value.open(type, id) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 删除按钮操作 */ | ||||||
|  | const handleDelete = async (id: number) => { | ||||||
|  |   try { | ||||||
|  |     // 删除的二次确认 | ||||||
|  |     await message.delConfirm() | ||||||
|  |     // 发起删除 | ||||||
|  |     await ClueApi.deleteClue(id) | ||||||
|  |     message.success(t('common.delSuccess')) | ||||||
|  |     // 刷新列表 | ||||||
|  |     await getList() | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 导出按钮操作 */ | ||||||
|  | const handleExport = async () => { | ||||||
|  |   try { | ||||||
|  |     // 导出的二次确认 | ||||||
|  |     await message.exportConfirm() | ||||||
|  |     // 发起导出 | ||||||
|  |     exportLoading.value = true | ||||||
|  |     const data = await ClueApi.exportClue(queryParams) | ||||||
|  |     download.excel(data, '线索.xls') | ||||||
|  |   } catch { | ||||||
|  |   } finally { | ||||||
|  |     exportLoading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 初始化 **/ | ||||||
|  | onMounted(() => { | ||||||
|  |   getList() | ||||||
|  | }) | ||||||
|  | </script> | ||||||
|  | @ -0,0 +1,228 @@ | ||||||
|  | <template> | ||||||
|  |   <Dialog :title="dialogTitle" v-model="dialogVisible"> | ||||||
|  |     <el-form | ||||||
|  |       ref="formRef" | ||||||
|  |       :model="formData" | ||||||
|  |       :rules="formRules" | ||||||
|  |       label-width="100px" | ||||||
|  |       v-loading="formLoading" | ||||||
|  |     > | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="合同名称" prop="name"> | ||||||
|  |             <el-input v-model="formData.name" placeholder="请输入合同名称" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="客户" prop="customerId"> | ||||||
|  |             <el-input v-model="formData.customerId" placeholder="请选择对应客户" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  | 
 | ||||||
|  |       <el-form-item label="商机名称" prop="businessId"> | ||||||
|  |         <el-input v-model="formData.businessId" placeholder="请选择对应商机" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="工作流" prop="processInstanceId"> | ||||||
|  |         <el-input v-model="formData.processInstanceId" placeholder="请选择工作流" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="下单日期" prop="orderDate"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="formData.orderDate" | ||||||
|  |           type="date" | ||||||
|  |           value-format="x" | ||||||
|  |           placeholder="选择下单日期" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="负责人" prop="ownerUserId"> | ||||||
|  |         <el-input v-model="formData.ownerUserId" placeholder="请选择负责人" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="合同编号" prop="no"> | ||||||
|  |         <el-input v-model="formData.no" placeholder="请输入合同编号" /> | ||||||
|  |       </el-form-item> | ||||||
|  | 
 | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="开始时间" prop="startTime"> | ||||||
|  |             <el-date-picker | ||||||
|  |               v-model="formData.startTime" | ||||||
|  |               type="date" | ||||||
|  |               value-format="x" | ||||||
|  |               placeholder="选择开始时间" | ||||||
|  |             /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="结束时间" prop="endTime"> | ||||||
|  |             <el-date-picker | ||||||
|  |               v-model="formData.endTime" | ||||||
|  |               type="date" | ||||||
|  |               value-format="x" | ||||||
|  |               placeholder="选择结束时间" | ||||||
|  |             /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  | 
 | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="8"> | ||||||
|  |           <el-form-item label="合同金额" prop="price"> | ||||||
|  |             <el-input v-model="formData.price" placeholder="请输入合同金额" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="8"> | ||||||
|  |           <el-form-item label="整单折扣" prop="discountPercent"> | ||||||
|  |             <el-input v-model="formData.discountPercent" placeholder="请输入整单折扣" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="8"> | ||||||
|  |           <el-form-item label="产品总金额" prop="productPrice"> | ||||||
|  |             <el-input v-model="formData.productPrice" placeholder="请输入产品总金额" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  | 
 | ||||||
|  |       <el-form-item label="只读权限的用户" prop="roUserIds"> | ||||||
|  |         <el-input v-model="formData.roUserIds" placeholder="请输入只读权限的用户" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="读写权限的用户" prop="rwUserIds"> | ||||||
|  |         <el-input v-model="formData.rwUserIds" placeholder="请输入读写权限的用户" /> | ||||||
|  |       </el-form-item> | ||||||
|  | 
 | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="联系人编号" prop="contactId"> | ||||||
|  |             <el-input v-model="formData.contactId" placeholder="请输入联系人编号" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <el-form-item label="公司签约人" prop="signUserId"> | ||||||
|  |             <el-input v-model="formData.signUserId" placeholder="请输入公司签约人" /> | ||||||
|  |           </el-form-item> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  | 
 | ||||||
|  |       <el-form-item label="最后跟进时间" prop="contactLastTime"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="formData.contactLastTime" | ||||||
|  |           type="date" | ||||||
|  |           value-format="x" | ||||||
|  |           placeholder="选择最后跟进时间" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="备注" prop="remark"> | ||||||
|  |         <el-input v-model="formData.remark" placeholder="请输入备注" /> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  |     <template #footer> | ||||||
|  |       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> | ||||||
|  |       <el-button @click="dialogVisible = false">取 消</el-button> | ||||||
|  |     </template> | ||||||
|  |   </Dialog> | ||||||
|  | </template> | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import * as ContractApi from '@/api/crm/contract' | ||||||
|  | 
 | ||||||
|  | const { t } = useI18n() // 国际化 | ||||||
|  | const message = useMessage() // 消息弹窗 | ||||||
|  | 
 | ||||||
|  | const dialogVisible = ref(false) // 弹窗的是否展示 | ||||||
|  | const dialogTitle = ref('') // 弹窗的标题 | ||||||
|  | const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||||
|  | const formType = ref('') // 表单的类型:create - 新增;update - 修改 | ||||||
|  | const formData = ref({ | ||||||
|  |   id: undefined, | ||||||
|  |   name: undefined, | ||||||
|  |   customerId: undefined, | ||||||
|  |   businessId: undefined, | ||||||
|  |   processInstanceId: undefined, | ||||||
|  |   orderDate: undefined, | ||||||
|  |   ownerUserId: undefined, | ||||||
|  |   no: undefined, | ||||||
|  |   startTime: undefined, | ||||||
|  |   endTime: undefined, | ||||||
|  |   price: undefined, | ||||||
|  |   discountPercent: undefined, | ||||||
|  |   productPrice: undefined, | ||||||
|  |   roUserIds: undefined, | ||||||
|  |   rwUserIds: undefined, | ||||||
|  |   contactId: undefined, | ||||||
|  |   signUserId: undefined, | ||||||
|  |   contactLastTime: undefined, | ||||||
|  |   remark: undefined | ||||||
|  | }) | ||||||
|  | const formRules = reactive({ | ||||||
|  |   name: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }] | ||||||
|  | }) | ||||||
|  | const formRef = ref() // 表单 Ref | ||||||
|  | 
 | ||||||
|  | /** 打开弹窗 */ | ||||||
|  | const open = async (type: string, id?: number) => { | ||||||
|  |   dialogVisible.value = true | ||||||
|  |   dialogTitle.value = t('action.' + type) | ||||||
|  |   formType.value = type | ||||||
|  |   resetForm() | ||||||
|  |   // 修改时,设置数据 | ||||||
|  |   if (id) { | ||||||
|  |     formLoading.value = true | ||||||
|  |     try { | ||||||
|  |       formData.value = await ContractApi.getContract(id) | ||||||
|  |     } finally { | ||||||
|  |       formLoading.value = false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||||
|  | 
 | ||||||
|  | /** 提交表单 */ | ||||||
|  | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||||||
|  | const submitForm = async () => { | ||||||
|  |   // 校验表单 | ||||||
|  |   if (!formRef) return | ||||||
|  |   const valid = await formRef.value.validate() | ||||||
|  |   if (!valid) return | ||||||
|  |   // 提交请求 | ||||||
|  |   formLoading.value = true | ||||||
|  |   try { | ||||||
|  |     const data = formData.value as unknown as ContractApi.ContractVO | ||||||
|  |     if (formType.value === 'create') { | ||||||
|  |       await ContractApi.createContract(data) | ||||||
|  |       message.success(t('common.createSuccess')) | ||||||
|  |     } else { | ||||||
|  |       await ContractApi.updateContract(data) | ||||||
|  |       message.success(t('common.updateSuccess')) | ||||||
|  |     } | ||||||
|  |     dialogVisible.value = false | ||||||
|  |     // 发送操作成功的事件 | ||||||
|  |     emit('success') | ||||||
|  |   } finally { | ||||||
|  |     formLoading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置表单 */ | ||||||
|  | const resetForm = () => { | ||||||
|  |   formData.value = { | ||||||
|  |     id: undefined, | ||||||
|  |     name: undefined, | ||||||
|  |     customerId: undefined, | ||||||
|  |     businessId: undefined, | ||||||
|  |     processInstanceId: undefined, | ||||||
|  |     orderDate: undefined, | ||||||
|  |     ownerUserId: undefined, | ||||||
|  |     no: undefined, | ||||||
|  |     startTime: undefined, | ||||||
|  |     endTime: undefined, | ||||||
|  |     price: undefined, | ||||||
|  |     discountPercent: undefined, | ||||||
|  |     productPrice: undefined, | ||||||
|  |     roUserIds: undefined, | ||||||
|  |     rwUserIds: undefined, | ||||||
|  |     contactId: undefined, | ||||||
|  |     signUserId: undefined, | ||||||
|  |     contactLastTime: undefined, | ||||||
|  |     remark: undefined | ||||||
|  |   } | ||||||
|  |   formRef.value?.resetFields() | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | @ -0,0 +1,228 @@ | ||||||
|  | import type { CrudSchema } from '@/hooks/web/useCrudSchemas' | ||||||
|  | import { dateFormatter } from '@/utils/formatTime' | ||||||
|  | 
 | ||||||
|  | // 表单校验
 | ||||||
|  | export const rules = reactive({ | ||||||
|  |   name: [required] | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // TODO @dbh52:不使用 crud 模式哈,使用标准的 ep 代码哈;主要后续 crud schema 可能会改
 | ||||||
|  | // CrudSchema https://doc.iocoder.cn/vue3/crud-schema/
 | ||||||
|  | const crudSchemas = reactive<CrudSchema[]>([ | ||||||
|  |   { | ||||||
|  |     label: '合同编号', | ||||||
|  |     field: 'id', | ||||||
|  |     isForm: false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '合同名称', | ||||||
|  |     field: 'name', | ||||||
|  |     isSearch: true | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '客户编号', | ||||||
|  |     field: 'customerId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '商机编号', | ||||||
|  |     field: 'businessId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '工作流编号', | ||||||
|  |     field: 'processInstanceId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '下单日期', | ||||||
|  |     field: 'orderDate', | ||||||
|  |     formatter: dateFormatter, | ||||||
|  |     isSearch: true, | ||||||
|  |     search: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||||
|  |         type: 'daterange', | ||||||
|  |         defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     form: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         type: 'datetime', | ||||||
|  |         valueFormat: 'x' | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '负责人的用户编号', | ||||||
|  |     field: 'ownerUserId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '创建时间', | ||||||
|  |     field: 'createTime', | ||||||
|  |     formatter: dateFormatter, | ||||||
|  |     isSearch: true, | ||||||
|  |     search: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||||
|  |         type: 'daterange', | ||||||
|  |         defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     isForm: false | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '合同编号', | ||||||
|  |     field: 'no', | ||||||
|  |     isSearch: true | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '开始时间', | ||||||
|  |     field: 'startTime', | ||||||
|  |     formatter: dateFormatter, | ||||||
|  |     isSearch: true, | ||||||
|  |     search: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||||
|  |         type: 'daterange', | ||||||
|  |         defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     form: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         type: 'datetime', | ||||||
|  |         valueFormat: 'x' | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '结束时间', | ||||||
|  |     field: 'endTime', | ||||||
|  |     formatter: dateFormatter, | ||||||
|  |     isSearch: true, | ||||||
|  |     search: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||||
|  |         type: 'daterange', | ||||||
|  |         defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     form: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         type: 'datetime', | ||||||
|  |         valueFormat: 'x' | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '合同金额', | ||||||
|  |     field: 'price', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '整单折扣', | ||||||
|  |     field: 'discountPercent', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '产品总金额', | ||||||
|  |     field: 'productPrice', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '只读权限的用户编号数组', | ||||||
|  |     field: 'roUserIds', | ||||||
|  |     isSearch: true | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '读写权限的用户编号数组', | ||||||
|  |     field: 'rwUserIds', | ||||||
|  |     isSearch: true | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '联系人编号', | ||||||
|  |     field: 'contactId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '备注', | ||||||
|  |     field: 'remark', | ||||||
|  |     isSearch: true | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '公司签约人', | ||||||
|  |     field: 'signUserId', | ||||||
|  |     isSearch: true, | ||||||
|  |     form: { | ||||||
|  |       component: 'InputNumber', | ||||||
|  |       value: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '最后跟进时间', | ||||||
|  |     field: 'contactLastTime', | ||||||
|  |     formatter: dateFormatter, | ||||||
|  |     isSearch: true, | ||||||
|  |     search: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||||
|  |         type: 'daterange', | ||||||
|  |         defaultTime: [new Date('1 00:00:00'), new Date('1 23:59:59')] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     form: { | ||||||
|  |       component: 'DatePicker', | ||||||
|  |       componentProps: { | ||||||
|  |         type: 'datetime', | ||||||
|  |         valueFormat: 'x' | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '操作', | ||||||
|  |     field: 'action', | ||||||
|  |     isForm: false | ||||||
|  |   } | ||||||
|  | ]) | ||||||
|  | export const { allSchemas } = useCrudSchemas(crudSchemas) | ||||||
|  | @ -0,0 +1,253 @@ | ||||||
|  | <template> | ||||||
|  |   <ContentWrap> | ||||||
|  |     <!-- 搜索工作栏 --> | ||||||
|  |     <el-form | ||||||
|  |       class="-mb-15px" | ||||||
|  |       :model="queryParams" | ||||||
|  |       ref="queryFormRef" | ||||||
|  |       :inline="true" | ||||||
|  |       label-width="68px" | ||||||
|  |     > | ||||||
|  |       <el-form-item label="合同名称" prop="name"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.name" | ||||||
|  |           placeholder="请输入合同名称" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="客户编号" prop="customerId"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.customerId" | ||||||
|  |           placeholder="请输入客户编号" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="商机编号" prop="businessId"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.businessId" | ||||||
|  |           placeholder="请输入商机编号" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="下单日期" prop="orderDate"> | ||||||
|  |         <el-date-picker | ||||||
|  |           v-model="queryParams.orderDate" | ||||||
|  |           value-format="YYYY-MM-DD HH:mm:ss" | ||||||
|  |           type="daterange" | ||||||
|  |           start-placeholder="开始日期" | ||||||
|  |           end-placeholder="结束日期" | ||||||
|  |           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="合同编号" prop="no"> | ||||||
|  |         <el-input | ||||||
|  |           v-model="queryParams.no" | ||||||
|  |           placeholder="请输入合同编号" | ||||||
|  |           clearable | ||||||
|  |           @keyup.enter="handleQuery" | ||||||
|  |           class="!w-240px" | ||||||
|  |         /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item> | ||||||
|  |         <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> | ||||||
|  |         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> | ||||||
|  |         <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:contract:create']"> | ||||||
|  |           <Icon icon="ep:plus" class="mr-5px" /> 新增 | ||||||
|  |         </el-button> | ||||||
|  |         <el-button | ||||||
|  |           type="success" | ||||||
|  |           plain | ||||||
|  |           @click="handleExport" | ||||||
|  |           :loading="exportLoading" | ||||||
|  |           v-hasPermi="['crm:contract:export']" | ||||||
|  |         > | ||||||
|  |           <Icon icon="ep:download" class="mr-5px" /> 导出 | ||||||
|  |         </el-button> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  |   </ContentWrap> | ||||||
|  | 
 | ||||||
|  |   <!-- 列表 --> | ||||||
|  |   <ContentWrap> | ||||||
|  |     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> | ||||||
|  |       <el-table-column label="合同编号" align="center" prop="id" /> | ||||||
|  |       <el-table-column label="合同名称" align="center" prop="name" /> | ||||||
|  |       <el-table-column label="客户名称" align="center" prop="customerId" /> | ||||||
|  |       <el-table-column label="商机名称" align="center" prop="businessId" /> | ||||||
|  |       <el-table-column label="工作流名称" align="center" prop="processInstanceId" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="下单时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="orderDate" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="负责人" align="center" prop="ownerUserId" /> | ||||||
|  |       <el-table-column label="合同编号" align="center" prop="no" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="开始时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="startTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="结束时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="endTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="合同金额" align="center" prop="price" /> | ||||||
|  |       <el-table-column label="整单折扣" align="center" prop="discountPercent" /> | ||||||
|  |       <el-table-column label="产品总金额" align="center" prop="productPrice" /> | ||||||
|  |       <el-table-column label="联系人" align="center" prop="contactId" /> | ||||||
|  |       <el-table-column label="公司签约人" align="center" prop="signUserId" /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="最后跟进时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="contactLastTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column | ||||||
|  |         label="创建时间" | ||||||
|  |         align="center" | ||||||
|  |         prop="createTime" | ||||||
|  |         :formatter="dateFormatter" | ||||||
|  |         width="180px" | ||||||
|  |       /> | ||||||
|  |       <el-table-column label="备注" align="center" prop="remark" /> | ||||||
|  | 
 | ||||||
|  |       <el-table-column label="操作" width="120px"> | ||||||
|  |         <template #default="scope"> | ||||||
|  |           <el-button | ||||||
|  |             link | ||||||
|  |             type="primary" | ||||||
|  |             @click="openForm('update', scope.row.id)" | ||||||
|  |             v-hasPermi="['crm:contract:update']" | ||||||
|  |           > | ||||||
|  |             编辑 | ||||||
|  |           </el-button> | ||||||
|  |           <el-button | ||||||
|  |             link | ||||||
|  |             type="danger" | ||||||
|  |             @click="handleDelete(scope.row.id)" | ||||||
|  |             v-hasPermi="['crm:contract:delete']" | ||||||
|  |           > | ||||||
|  |             删除 | ||||||
|  |           </el-button> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |     </el-table> | ||||||
|  |     <!-- 分页 --> | ||||||
|  |     <Pagination | ||||||
|  |       :total="total" | ||||||
|  |       v-model:page="queryParams.pageNo" | ||||||
|  |       v-model:limit="queryParams.pageSize" | ||||||
|  |       @pagination="getList" | ||||||
|  |     /> | ||||||
|  |   </ContentWrap> | ||||||
|  | 
 | ||||||
|  |   <!-- 表单弹窗:添加/修改 --> | ||||||
|  |   <ContractForm ref="formRef" @success="getList" /> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { dateFormatter } from '@/utils/formatTime' | ||||||
|  | import download from '@/utils/download' | ||||||
|  | import * as ContractApi from '@/api/crm/contract' | ||||||
|  | import ContractForm from './ContractForm.vue' | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'Contract' }) | ||||||
|  | 
 | ||||||
|  | const message = useMessage() // 消息弹窗 | ||||||
|  | const { t } = useI18n() // 国际化 | ||||||
|  | 
 | ||||||
|  | const loading = ref(true) // 列表的加载中 | ||||||
|  | const total = ref(0) // 列表的总页数 | ||||||
|  | const list = ref([]) // 列表的数据 | ||||||
|  | const queryParams = reactive({ | ||||||
|  |   pageNo: 1, | ||||||
|  |   pageSize: 10, | ||||||
|  |   name: null, | ||||||
|  |   customerId: null, | ||||||
|  |   businessId: null, | ||||||
|  |   orderDate: [], | ||||||
|  |   no: null, | ||||||
|  |   discountPercent: null, | ||||||
|  |   productPrice: null | ||||||
|  | }) | ||||||
|  | const queryFormRef = ref() // 搜索的表单 | ||||||
|  | const exportLoading = ref(false) // 导出的加载中 | ||||||
|  | 
 | ||||||
|  | /** 查询列表 */ | ||||||
|  | const getList = async () => { | ||||||
|  |   loading.value = true | ||||||
|  |   try { | ||||||
|  |     const data = await ContractApi.getContractPage(queryParams) | ||||||
|  |     list.value = data.list | ||||||
|  |     total.value = data.total | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   queryParams.pageNo = 1 | ||||||
|  |   getList() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   queryFormRef.value.resetFields() | ||||||
|  |   handleQuery() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 添加/修改操作 */ | ||||||
|  | const formRef = ref() | ||||||
|  | const openForm = (type: string, id?: number) => { | ||||||
|  |   formRef.value.open(type, id) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 删除按钮操作 */ | ||||||
|  | const handleDelete = async (id: number) => { | ||||||
|  |   try { | ||||||
|  |     // 删除的二次确认 | ||||||
|  |     await message.delConfirm() | ||||||
|  |     // 发起删除 | ||||||
|  |     await ContractApi.deleteContract(id) | ||||||
|  |     message.success(t('common.delSuccess')) | ||||||
|  |     // 刷新列表 | ||||||
|  |     await getList() | ||||||
|  |   } catch {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 导出按钮操作 */ | ||||||
|  | const handleExport = async () => { | ||||||
|  |   try { | ||||||
|  |     // 导出的二次确认 | ||||||
|  |     await message.exportConfirm() | ||||||
|  |     // 发起导出 | ||||||
|  |     exportLoading.value = true | ||||||
|  |     const data = await ContractApi.exportContract(queryParams) | ||||||
|  |     download.excel(data, '合同.xls') | ||||||
|  |   } catch { | ||||||
|  |   } finally { | ||||||
|  |     exportLoading.value = false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 初始化 **/ | ||||||
|  | onMounted(() => { | ||||||
|  |   getList() | ||||||
|  | }) | ||||||
|  | </script> | ||||||
|  | @ -47,12 +47,7 @@ | ||||||
|       <el-form-item> |       <el-form-item> | ||||||
|         <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" />搜索 </el-button> |         <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" />搜索 </el-button> | ||||||
|         <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" />重置 </el-button> |         <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" />重置 </el-button> | ||||||
|         <el-button |         <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['pay:app:create']"> | ||||||
|           type="primary" |  | ||||||
|           plain |  | ||||||
|           @click="openForm('create')" |  | ||||||
|           v-hasPermi="['system:tenant:create']" |  | ||||||
|         > |  | ||||||
|           <Icon icon="ep:plus" class="mr-5px" /> 新增 |           <Icon icon="ep:plus" class="mr-5px" /> 新增 | ||||||
|         </el-button> |         </el-button> | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
|  | @ -266,7 +261,7 @@ | ||||||
|             link |             link | ||||||
|             type="primary" |             type="primary" | ||||||
|             @click="openForm('update', scope.row.id)" |             @click="openForm('update', scope.row.id)" | ||||||
|             v-hasPermi="['system:tenant:update']" |             v-hasPermi="['pay:app:update']" | ||||||
|           > |           > | ||||||
|             编辑 |             编辑 | ||||||
|           </el-button> |           </el-button> | ||||||
|  | @ -274,7 +269,7 @@ | ||||||
|             link |             link | ||||||
|             type="danger" |             type="danger" | ||||||
|             @click="handleDelete(scope.row.id)" |             @click="handleDelete(scope.row.id)" | ||||||
|             v-hasPermi="['system:tenant:delete']" |             v-hasPermi="['pay:app:delete']" | ||||||
|           > |           > | ||||||
|             删除 |             删除 | ||||||
|           </el-button> |           </el-button> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 芋道源码
						芋道源码