Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
owen
2024-01-05 15:26:41 +08:00
64 changed files with 1121 additions and 569 deletions

View File

@@ -1,13 +1,13 @@
<template>
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="请假类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择请假类型" clearable>
<el-select v-model="formData.type" clearable placeholder="请选择请假类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
:key="dict.value"
@@ -18,27 +18,27 @@
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
clearable
v-model="formData.startTime"
clearable
placeholder="请选择开始时间"
type="datetime"
value-format="x"
placeholder="请选择开始时间"
/>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
clearable
v-model="formData.endTime"
clearable
placeholder="请选择结束时间"
type="datetime"
value-format="x"
placeholder="请选择结束时间"
/>
</el-form-item>
<el-form-item label="原因" prop="reason">
<el-input v-model="formData.reason" type="textarea" placeholder="请输请假原因" />
<el-input v-model="formData.reason" placeholder="请输请假原因" type="textarea" />
</el-form-item>
<el-form-item>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
</el-form-item>
</el-form>
</template>
@@ -50,9 +50,6 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
defineOptions({ name: 'BpmOALeaveCreate' })
const message = useMessage() // 消息弹窗
const { delView } = useTagsViewStore() // 视图操作
const { currentRoute } = useRouter() // 路由
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formData = ref({
type: undefined,
@@ -67,7 +64,8 @@ const formRules = reactive({
endTime: [{ required: true, message: '请假结束时间不能为空', trigger: 'change' }]
})
const formRef = ref() // 表单 Ref
const { delView } = useTagsViewStore() // 视图操作
const { push, currentRoute } = useRouter() // 路由
/** 提交表单 */
const submitForm = async () => {
// 校验表单
@@ -82,6 +80,7 @@ const submitForm = async () => {
message.success('发起成功')
// 关闭当前 Tab
delView(unref(currentRoute))
await push({ name: 'BpmOALeave' })
} finally {
formLoading.value = false
}

View File

@@ -2,18 +2,18 @@
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
:model="queryParams"
class="-mb-15px"
label-width="68px"
>
<el-form-item label="请假类型" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择请假类型"
clearable
class="!w-240px"
clearable
placeholder="请选择请假类型"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
@@ -26,16 +26,16 @@
<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"
end-placeholder="结束日期"
start-placeholder="开始日期"
type="daterange"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item label="结果" prop="result">
<el-select v-model="queryParams.result" placeholder="请选择结果" clearable class="!w-240px">
<el-select v-model="queryParams.result" class="!w-240px" clearable placeholder="请选择结果">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)"
:key="dict.value"
@@ -47,17 +47,24 @@
<el-form-item label="原因" prop="reason">
<el-input
v-model="queryParams.reason"
placeholder="请输入原因"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
clearable
placeholder="请输入原因"
@keyup.enter="handleQuery"
/>
</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" plain @click="handleCreate()">
<Icon icon="ep:plus" class="mr-5px" /> 发起请假
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
<el-button plain type="primary" @click="handleCreate()">
<Icon class="mr-5px" icon="ep:plus" />
发起请假
</el-button>
</el-form-item>
</el-form>
@@ -66,63 +73,63 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="申请编号" align="center" prop="id" />
<el-table-column label="状态" align="center" prop="result">
<el-table-column align="center" label="申请编号" prop="id" />
<el-table-column align="center" label="状态" prop="result">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="scope.row.result" />
</template>
</el-table-column>
<el-table-column
label="开始时间"
:formatter="dateFormatter"
align="center"
label="开始时间"
prop="startTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column
label="结束时间"
:formatter="dateFormatter"
align="center"
label="结束时间"
prop="endTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="请假类型" align="center" prop="type">
<el-table-column align="center" label="请假类型" prop="type">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="原因" align="center" prop="reason" />
<el-table-column align="center" label="原因" prop="reason" />
<el-table-column
label="申请时间"
:formatter="dateFormatter"
align="center"
label="申请时间"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center" width="200">
<el-table-column align="center" label="操作" width="200">
<template #default="scope">
<el-button
v-hasPermi="['bpm:oa-leave:query']"
link
type="primary"
@click="handleDetail(scope.row)"
v-hasPermi="['bpm:oa-leave:query']"
>
详情
</el-button>
<el-button
v-hasPermi="['bpm:oa-leave:query']"
link
type="primary"
@click="handleProcessDetail(scope.row)"
v-hasPermi="['bpm:oa-leave:query']"
>
进度
</el-button>
<el-button
v-if="scope.row.result === 1"
v-hasPermi="['bpm:oa-leave:create']"
link
type="danger"
@click="cancelLeave(scope.row)"
v-hasPermi="['bpm:oa-leave:create']"
v-if="scope.row.result === 1"
>
取消
</el-button>
@@ -131,9 +138,9 @@
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
@@ -228,6 +235,14 @@ const handleProcessDetail = (row) => {
})
}
// fix: 列表不刷新的问题。
watch(
() => router.currentRoute.value,
() => {
getList()
}
)
/** 初始化 **/
onMounted(() => {
getList()

View File

@@ -62,12 +62,12 @@
</el-row>
</el-popover>
</el-form-item>
<!-- TODO @ljlleoidea 红色的报错可以解决下 -->
<el-form-item label="商机状态类型" prop="statusTypeId">
<el-select
v-model="formData.statusTypeId"
placeholder="请选择商机状态类型"
clearable
size="small"
@change="changeBusinessStatusType"
>
<el-option
@@ -79,7 +79,7 @@
</el-select>
</el-form-item>
<el-form-item label="商机状态" prop="statusId">
<el-select v-model="formData.statusId" placeholder="请选择商机状态" clearable size="small">
<el-select v-model="formData.statusId" placeholder="请选择商机状态" clearable>
<el-option
v-for="item in businessStatusList"
:key="item.id"
@@ -242,7 +242,8 @@ const queryParams = reactive({
mobile: null,
industryId: null,
level: null,
source: null
source: null,
pool: false
})
// 选择客户
const showCustomer = ref(false)
@@ -251,12 +252,12 @@ const openCustomerSelect = () => {
queryParams.pageNo = 1
getCustomerList()
}
/** 查询客户列表 */
const getCustomerList = async () => {
loading.value = true
try {
const data = await CustomerApi.getCustomerPage(queryParams)
console.log(JSON.stringify(data))
customerList.value = data.list
total.value = data.total
} finally {

View File

@@ -5,11 +5,32 @@
<Icon class="mr-5px" icon="ep:opportunity" />
创建商机
</el-button>
<el-button
@click="openBusinessModal"
v-hasPermi="['crm:contact:create-business']"
v-if="queryParams.contactId"
>
<Icon class="mr-5px" icon="ep:circle-plus" />关联
</el-button>
<el-button
@click="deleteContactBusinessList"
v-hasPermi="['crm:contact:delete-business']"
v-if="queryParams.contactId"
>
<Icon class="mr-5px" icon="ep:remove" />解除关联
</el-button>
</el-row>
<!-- 列表 -->
<ContentWrap class="mt-10px">
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
ref="businessRef"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
>
<el-table-column type="selection" width="55" v-if="queryParams.contactId" />
<el-table-column label="商机名称" fixed="left" align="center" prop="name">
<template #default="scope">
<el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
@@ -33,17 +54,28 @@
<!-- 表单弹窗添加 -->
<BusinessForm ref="formRef" @success="getList" />
<!-- 关联商机选择弹框 -->
<BusinessListModal
ref="businessModalRef"
:customer-id="props.customerId"
@success="createContactBusinessList"
/>
</template>
<script setup lang="ts">
import * as BusinessApi from '@/api/crm/business'
import * as ContactApi from '@/api/crm/contact'
import BusinessForm from './../BusinessForm.vue'
import { BizTypeEnum } from '@/api/crm/permission'
import { fenToYuanFormat } from '@/utils/formatter'
import BusinessListModal from './BusinessListModal.vue'
const message = useMessage() // 消息
defineOptions({ name: 'CrmBusinessList' })
const props = defineProps<{
bizType: number // 业务类型
bizId: number // 业务编号
customerId?: number // 关联联系人与商机时,需要传入 customerId 进行筛选
}>()
const loading = ref(true) // 列表的加载中
@@ -52,7 +84,8 @@ const list = ref([]) // 列表的数据
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
customerId: undefined as unknown // 允许 undefined + number
customerId: undefined as unknown, // 允许 undefined + number
contactId: undefined as unknown // 允许 undefined + number
})
/** 查询列表 */
@@ -61,6 +94,7 @@ const getList = async () => {
try {
// 置空参数
queryParams.customerId = undefined
queryParams.contactId = undefined
// 执行查询
let data = { list: [], total: 0 }
switch (props.bizType) {
@@ -68,6 +102,10 @@ const getList = async () => {
queryParams.customerId = props.bizId
data = await BusinessApi.getBusinessPageByCustomer(queryParams)
break
case BizTypeEnum.CRM_CONTACT:
queryParams.contactId = props.bizId
data = await BusinessApi.getBusinessPageByContact(queryParams)
break
default:
return
}
@@ -96,6 +134,41 @@ const openDetail = (id: number) => {
push({ name: 'CrmBusinessDetail', params: { id } })
}
/** 打开联系人与商机的关联弹窗 */
const businessModalRef = ref()
const openBusinessModal = () => {
businessModalRef.value.open()
}
const createContactBusinessList = async (businessIds: number[]) => {
const data = {
contactId: props.bizId,
businessIds: businessIds
} as ContactApi.ContactBusinessReqVO
businessRef.value.getSelectionRows().forEach((row: BusinessApi.BusinessVO) => {
data.businessIds.push(row.id)
})
await ContactApi.createContactBusinessList(data)
// 刷新列表
message.success('关联商机成功')
handleQuery()
}
/** 解除联系人与商机的关联 */
const businessRef = ref()
const deleteContactBusinessList = async () => {
const data = {
contactId: props.bizId,
businessIds: businessRef.value.getSelectionRows().map((row: BusinessApi.BusinessVO) => row.id)
} as ContactApi.ContactBusinessReqVO
if (data.businessIds.length === 0) {
return message.error('未选择商机')
}
await ContactApi.deleteContactBusinessList(data)
// 刷新列表
message.success('取关商机成功')
handleQuery()
}
/** 监听打开的 bizId + bizType从而加载最新的列表 */
watch(
() => [props.bizId, props.bizType],

View File

@@ -1,5 +1,5 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<Dialog title="关联商机" v-model="dialogVisible">
<!-- 搜索工作栏 -->
<ContentWrap>
<el-form
@@ -29,7 +29,6 @@
</ContentWrap>
<!-- 列表 -->
<!-- TODO @zyna字段按照他们对齐下 -->
<ContentWrap class="mt-10px">
<el-table
v-loading="loading"
@@ -75,16 +74,16 @@
</template>
<script setup lang="ts">
import * as BusinessApi from '@/api/crm/business'
import BusinessForm from '../../business/BusinessForm.vue'
import BusinessForm from '../BusinessForm.vue'
import { fenToYuanFormat } from '@/utils/formatter'
// TODO @zyna
import * as ContactbusinesslinkApi from '@/api/crm/contactbusinesslink'
const message = useMessage() //
defineOptions({ name: 'CrmBusinessLinkContactList' })
const message = useMessage() //
const props = defineProps<{
customerId: number
}>()
defineOptions({ name: 'BusinessListModal' })
const dialogVisible = ref(false) //
const dialogTitle = ref('') // TODO @zyna
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
@@ -93,17 +92,14 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
// TODO @zyna customerId
name: undefined
name: undefined,
customerId: props.customerId
})
const contactIdProp = ref(0) //
/** 打开弹窗 */
const open = async (contactId: number) => {
const open = async () => {
dialogVisible.value = true
contactIdProp.value = contactId
// TODO @zyna await idea
getList()
await getList()
}
defineExpose({ open }) // open
@@ -111,7 +107,7 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const getList = async () => {
loading.value = true
try {
const data = await BusinessApi.getBusinessPage(queryParams)
const data = await BusinessApi.getBusinessPageByCustomer(queryParams)
list.value = data.list
total.value = data.total
} finally {
@@ -141,25 +137,14 @@ const openForm = () => {
const emit = defineEmits(['success']) // success
const businessRef = ref()
const submitForm = async () => {
// TODO @zyna if return
if (businessRef.value.getSelectionRows().length === 0) {
message.success('未选择商机')
} else {
// TODO @zyna postData ref
const postData = ref<ContactbusinesslinkApi.ContactBusinessLinkVO[]>([])
businessRef.value.getSelectionRows().forEach((element) => {
// TODO @zyna push data
let data = {
id: undefined,
businessId: element.id,
contactId: contactIdProp.value
}
postData.value.push(data)
})
await ContactbusinesslinkApi.createContactBusinessLinkBatch(postData.value)
dialogVisible.value = false
emit('success')
const businessIds = businessRef.value
.getSelectionRows()
.map((row: BusinessApi.BusinessVO) => row.id)
if (businessIds.length === 0) {
return message.error('未选择商机')
}
dialogVisible.value = false
emit('success', businessIds)
}
/** 打开联系人详情 */

View File

@@ -49,8 +49,8 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12"
><el-form-item label="性别" prop="sex">
<el-col :span="12">
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
@@ -58,8 +58,9 @@
:label="dict.label"
:value="dict.value"
/>
</el-select> </el-form-item
></el-col>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
@@ -72,8 +73,8 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="座机" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入座机" style="width: 215px" />
<el-form-item label="电话" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入电话" style="width: 215px" />
</el-form-item>
</el-col>
</el-row>
@@ -104,10 +105,10 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下次联系时间" prop="nextTime">
<el-form-item label="下次联系时间" prop="contactNextTime">
<el-date-picker
v-model="formData.nextTime"
type="date"
v-model="formData.contactNextTime"
type="datetime"
value-format="x"
placeholder="选择下次联系时间"
/>
@@ -126,15 +127,17 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="地址" prop="address">
<el-form-item label="地址" prop="detailAddress">
<el-input
input-style="width:190px;"
v-model="formData.address"
v-model="formData.detailAddress"
placeholder="请输入地址"
/>
</el-form-item>
</el-col> </el-row
><el-row>
</el-col>
</el-row>
<!-- TODO @zyna解决下 ide 报错 -->
<el-row>
<el-col :span="12">
<el-form-item label="直属上级" prop="parentId">
<el-select v-model="formData.parentId" placeholder="请选择">
@@ -152,10 +155,11 @@
<el-form-item label="职位" prop="post">
<el-input input-style="width:190px;" v-model="formData.post" placeholder="请输入职位" />
</el-form-item>
</el-col> </el-row
><el-row>
<el-col :span="12"
><el-form-item label="是否关键决策人" prop="master" style="width: 400px">
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="关键决策人" prop="master" style="width: 400px">
<el-radio-group v-model="formData.master">
<el-radio
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
@@ -169,8 +173,8 @@
</el-col>
</el-row>
<el-row>
<el-col :span="24"
><el-form-item label="备注" prop="remark">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
@@ -192,19 +196,20 @@ import { defaultProps } from '@/utils/tree'
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 areaList = ref([]) // 地区列表
const formData = ref({
nextTime: undefined,
contactNextTime: undefined,
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
customerName: undefined,
address: undefined,
detailAddress: undefined,
remark: undefined,
ownerUserId: undefined,
lastTime: undefined,
@@ -279,13 +284,14 @@ const submitForm = async () => {
/** 重置表单 */
const resetForm = () => {
// TODO zynaide 告警,看看怎么去掉哈;
formData.value = {
nextTime: undefined,
contactNextTime: undefined,
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
address: undefined,
detailAddress: undefined,
remark: undefined,
ownerUserId: undefined,
lastTime: undefined,

View File

@@ -1,14 +1,5 @@
<!--
* @Author: zyna
* @Date: 2023-12-02 13:08:57
* @LastEditTime: 2023-12-03 13:47:16
* @FilePath: \yudao-ui-admin-vue3\src\views\crm\contact\detail\ContactDetailsHeader.vue
* @Description:
-->
<!-- TODO @zyna上面这个不加哈 -->
<template>
<!-- TODO @zynaloading 缺了 -->
<div v-loading="loading">
<div>
<div class="flex items-start justify-between">
<div>
<el-col>
@@ -48,7 +39,6 @@
import * as ContactApi from '@/api/crm/contact'
import ContactForm from '@/views/crm/contact/ContactForm.vue'
import { formatDate } from '@/utils/formatTime'
//操作修改
const formRef = ref()
const openForm = (type: string, id?: number) => {

View File

@@ -1,4 +1,5 @@
<template>
<!-- TODO @zyna少了一个外边框 -->
<el-collapse v-model="activeNames">
<el-collapse-item name="basicInfo">
<template #title>

View File

@@ -10,18 +10,22 @@
<PermissionList :biz-id="contact.id!" :biz-type="BizTypeEnum.CRM_CONTACT" />
</el-tab-pane>
<el-tab-pane label="商机" lazy>
<BusinessList :biz-id="contact.id!" :biz-type="BizTypeEnum.CRM_CONTACT" />
<BusinessList
:biz-id="contact.id!"
:biz-type="BizTypeEnum.CRM_CONTACT"
:customer-id="contact.customerId"
/>
</el-tab-pane>
</el-tabs>
</el-col>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus' // TODO @zyna使用 hook 引入 message
import { useTagsViewStore } from '@/store/modules/tagsView'
import * as ContactApi from '@/api/crm/contact'
import ContactDetailsHeader from '@/views/crm/contact/detail/ContactDetailsHeader.vue'
import ContactDetailsInfo from '@/views/crm/contact/detail/ContactDetailsInfo.vue'
import BusinessList from '@/views/crm/contactBusinessLink/components/BusinessListByContact.vue' // 商机列表
import BusinessList from '@/views/crm/business/components/BusinessList.vue' // 商机列表
import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 团队成员列表(权限)
import { BizTypeEnum } from '@/api/crm/permission'

View File

@@ -11,6 +11,7 @@
<el-form-item label="客户" prop="customerId">
<el-select
v-model="queryParams.customerId"
class="!w-240px"
placeholder="请选择客户"
value-key="id"
lable-key="name"
@@ -28,56 +29,55 @@
<el-form-item label="姓名" prop="name">
<el-input
v-model="queryParams.name"
class="!w-240px"
placeholder="请输入姓名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input
v-model="queryParams.mobile"
class="!w-240px"
placeholder="请输入手机号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="座机" prop="telephone">
<el-form-item label="电话" prop="telephone">
<el-input
v-model="queryParams.telephone"
class="!w-240px"
placeholder="请输入电话"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="QQ" prop="qq">
<el-input
v-model="queryParams.qq"
class="!w-240px"
placeholder="请输入QQ"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="微信" prop="wechat">
<el-input
v-model="queryParams.wechat"
class="!w-240px"
placeholder="请输入微信"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="电子邮箱" prop="email">
<el-input
v-model="queryParams.email"
class="!w-240px"
placeholder="请输入电子邮箱"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
@@ -102,53 +102,57 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="姓名" fixed="left" align="center" prop="name">
<el-table-column label="姓名" fixed="left" align="center" prop="name" width="140">
<template #default="scope">
<el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
</el-link>
</template>
</el-table-column>
<el-table-column label="客户" fixed="left" align="center" prop="customerName" />
<el-table-column label="客户名称" fixed="left" align="center" prop="customerName" width="120">
<template #default="scope">
<el-link
type="primary"
:underline="false"
@click="openCustomerDetail(scope.row.customerId)"
>
{{ scope.row.customerName }}
</el-link>
</template>
</el-table-column>
<el-table-column label="手机" align="center" prop="mobile" width="120" />
<el-table-column label="电话" align="center" prop="telephone" width="120" />
<el-table-column label="邮箱" align="center" prop="email" width="120" />
<el-table-column label="职位" align="center" prop="post" width="120" />
<el-table-column label="地址" align="center" prop="detailAddress" width="120" />
<el-table-column
:formatter="dateFormatter"
align="center"
label="下次联系时间"
prop="contactNextTime"
width="180px"
/>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="关键决策人" align="center" prop="master" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" />
</template>
</el-table-column>
<el-table-column label="直属上级" align="center" prop="parentName" width="140" />
<el-table-column
label="最后跟进时间"
align="center"
prop="contactLastTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="性别" align="center" prop="sex">
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
</template>
</el-table-column>
<el-table-column label="职位" align="center" prop="post" />
<el-table-column label="是否关键决策人" align="center" prop="master">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.master" />
</template>
</el-table-column>
<el-table-column label="直属上级" align="center" prop="parentName" />
<el-table-column label="手机号" align="center" prop="mobile" />
<el-table-column label="座机" align="center" prop="telephone" />
<el-table-column label="QQ" align="center" prop="qq" />
<el-table-column label="微信" align="center" prop="wechat" />
<el-table-column label="邮箱" align="center" prop="email" />
<el-table-column label="地址" align="center" prop="address" />
<el-table-column
label="下次联系时间"
align="center"
prop="nextTime"
width="180px"
:formatter="dateFormatter"
/>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column
label="最后跟进时间"
align="center"
prop="lastTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="负责人" align="center" prop="ownerUserId">
<template #default="scope">
{{ scope.row.ownerUserName }}
</template>
</el-table-column>
<!-- <el-table-column label="所属部门" align="center" prop="ownerUserId" /> -->
<el-table-column label="负责人" align="center" prop="ownerUserName" width="120" />
<el-table-column label="创建人" align="center" prop="creatorName" width="120" />
<el-table-column
label="更新时间"
align="center"
@@ -163,21 +167,10 @@
:formatter="dateFormatter"
width="180px"
/>
<!-- <el-table-column
label="创建人"
align="center"
prop="creator"
:formatter="dateFormatter"
width="180px"
>
<template #default="scope">
{{ userList.find((user) => user.id === scope.row.creator)?.nickname }}
</template>
</el-table-column> -->
<el-table-column label="操作" align="center" fixed="right" width="200">
<template #default="scope">
<el-button
plain
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['crm:contact:update']"
@@ -185,7 +178,7 @@
编辑
</el-button>
<el-button
plain
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['crm:contact:delete']"
@@ -228,23 +221,13 @@ const customerList = ref<CustomerApi.CustomerVO[]>([]) // 客户列表
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
nextTime: [],
mobile: null,
telephone: null,
email: null,
customerId: null,
address: null,
remark: null,
ownerUserId: null,
createTime: [],
lastTime: [],
parentId: null,
name: null,
post: null,
qq: null,
wechat: null,
sex: null,
policyMakers: null
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
name: undefined,
qq: undefined,
wechat: undefined
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
@@ -307,11 +290,15 @@ const handleExport = async () => {
}
}
/** 打开客户详情 */
/** 打开联系人详情 */
const { push } = useRouter()
const openDetail = (id: number) => {
push({ name: 'CrmContactDetail', params: { id } })
}
/** 打开客户详情 */
const openCustomerDetail = (id: number) => {
push({ name: 'CrmCustomerDetail', params: { id } })
}
/** 初始化 **/
onMounted(async () => {

View File

@@ -1,143 +0,0 @@
<template>
<!-- 操作栏 -->
<el-row justify="end">
<el-button @click="openForm">
<Icon class="mr-5px" icon="ep:opportunity" />
创建商机
</el-button>
<el-button @click="openBusinessLink"> 关联 </el-button>
<el-button @click="deleteBusinessLink"> 解除关联 </el-button>
</el-row>
<!-- 列表 -->
<ContentWrap class="mt-10px">
<el-table
v-loading="loading"
ref="businessRef"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
>
<el-table-column type="selection" width="55" />
<el-table-column label="商机名称" fixed="left" align="center" prop="name">
<template #default="scope">
<el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
</el-link>
</template>
</el-table-column>
<el-table-column label="商机金额" align="center" prop="price" :formatter="fenToYuanFormat" />
<el-table-column label="客户名称" align="center" prop="customerName" />
<el-table-column label="商机组" align="center" prop="statusTypeName" />
<el-table-column label="商机阶段" align="center" prop="statusName" />
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加 -->
<BusinessForm ref="formRef" @success="getList" />
<!---->
<BusinessLink ref="businessLinkRef" @success="getList" />
</template>
<script setup lang="ts">
import * as ContactBusinessLinkApi from '@/api/crm/contactbusinesslink'
import BusinessForm from '../../business/BusinessForm.vue'
import { BizTypeEnum } from '@/api/crm/permission'
import { fenToYuanFormat } from '@/utils/formatter'
import BusinessLink from './BusinessLinkContactList.vue'
const message = useMessage() // 消息弹窗
// TODO @zyna这个组件可以服用 BusinessList然后根据传入的编号类型做一些判断
defineOptions({ name: 'CrmBusinessContactList' })
const props = defineProps<{
bizType: number // 业务类型
bizId: number // 业务编号
}>()
const loading = ref(true) // 列表的加载中
const total = ref(0) // 列表的总页数
const list = ref([]) // 列表的数据
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
contactId: undefined as unknown // 允许 undefined + number
})
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
// 置空参数
queryParams.contactId = undefined
// 执行查询
let data = { list: [], total: 0 }
switch (props.bizType) {
case BizTypeEnum.CRM_CONTACT:
queryParams.contactId = props.bizId
data = await ContactBusinessLinkApi.getBusinessByContactPage(queryParams)
break
default:
return
}
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 添加操作 */
const formRef = ref()
const openForm = () => {
formRef.value.open('create')
}
/** 关联操作 */
const businessLinkRef = ref()
const openBusinessLink = () => {
businessLinkRef.value.open(props.bizId)
}
/**解除关联 */
const businessRef = ref()
const deleteBusinessLink = async () => {
if (businessRef.value.getSelectionRows().length === 0) {
message.success('未选择商机')
} else {
const postData = ref<ContactBusinessLinkApi.ContactBusinessLinkVO[]>([])
businessRef.value.getSelectionRows().forEach((element) => {
let data = {
id: undefined,
businessId: element.id,
contactId: props.bizId
}
postData.value.push(data)
})
await ContactBusinessLinkApi.deleteContactBusinessLink(postData.value)
handleQuery()
}
}
/** 打开联系人详情 */
const { push } = useRouter()
const openDetail = (id: number) => {
push({ name: 'CrmBusinessDetail', params: { id } })
}
/** 监听打开的 bizId + bizType从而加载最新的列表 */
watch(
() => [props.bizId, props.bizType],
() => {
handleQuery()
},
{ immediate: true, deep: true }
)
</script>

View File

@@ -1,11 +1,11 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<Dialog v-model="dialogVisible" :title="dialogTitle">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-row>
<el-col :span="12">
@@ -17,7 +17,7 @@
<el-form-item label="所属行业" prop="industryId">
<el-select v-model="formData.industryId" placeholder="请选择所属行业">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@@ -31,7 +31,7 @@
<el-form-item label="客户来源" prop="source">
<el-select v-model="formData.source" placeholder="请选择客户来源">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@@ -43,7 +43,7 @@
<el-form-item label="客户等级" prop="level">
<el-select v-model="formData.level" placeholder="请选择客户等级">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@@ -120,9 +120,9 @@
<el-form-item label="下次联系时间" prop="contactNextTime">
<el-date-picker
v-model="formData.contactNextTime"
type="date"
value-format="x"
placeholder="选择下次联系时间"
type="datetime"
value-format="x"
/>
</el-form-item>
</el-col>
@@ -139,13 +139,13 @@
</el-col>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as CustomerApi from '@/api/crm/customer'
import * as AreaApi from '@/api/system/area'
import { defaultProps } from '@/utils/tree'

View File

@@ -11,10 +11,19 @@
</div>
<div>
<!-- 右上按钮 -->
<el-button v-hasPermi="['crm:customer:update']" @click="openForm(customer.id)">
<el-button
type="primary"
v-hasPermi="['crm:customer:update']"
@click="openForm(customer.id)"
>
编辑
</el-button>
<!-- TODO @puhui999转移的操作接入 -->
<el-button type="primary" @click="transfer">转移</el-button>
<!-- TODO @puhui999修改成交状态的接入 -->
<el-button>更改成交状态</el-button>
<el-button v-if="customer.lockStatus" @click="handleUnlock(customer.id!)">解锁</el-button>
<el-button v-else @click="handleLock(customer.id!)">锁定</el-button>
</div>
</div>
</div>
@@ -26,26 +35,29 @@
<el-descriptions-item label="成交状态">
{{ customer.dealStatus ? '已成交' : '未成交' }}
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ customer.ownerUserName }} </el-descriptions-item>
<el-descriptions-item label="负责人">{{ customer.ownerUserName }}</el-descriptions-item>
<!-- TODO wanwan 首要联系人? -->
<el-descriptions-item label="首要联系人" />
<!-- TODO wanwan 首要联系人电话? -->
<el-descriptions-item label="首要联系人电话">{{ customer.mobile }} </el-descriptions-item>
<el-descriptions-item label="首要联系人电话">{{ customer.mobile }}</el-descriptions-item>
</el-descriptions>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<CustomerForm ref="formRef" @success="emit('refresh')" />
</template>
<script setup lang="ts">
<script lang="ts" setup>
import { DICT_TYPE } from '@/utils/dict'
import * as CustomerApi from '@/api/crm/customer'
import CustomerForm from '../CustomerForm.vue'
defineOptions({ name: 'CustomerDetailsHeader' })
const { customer, loading } = defineProps<{
customer: CustomerApi.CustomerVO // 客户信息
loading: boolean // 加载中
}>()
const message = useMessage() // 消息弹窗
/** 修改操作 */
const formRef = ref()
@@ -53,5 +65,20 @@ const openForm = (id?: number) => {
formRef.value.open('update', id)
}
/** 锁定操作 */
const handleLock = async (id: number) => {
await CustomerApi.lockCustomer(id, true)
message.success('锁定成功')
emit('refresh')
}
/** 解锁操作 */
const handleUnlock = async (id: number) => {
console.log(customer, '=======')
await CustomerApi.lockCustomer(id, false)
message.success('解锁成功')
emit('refresh')
}
const emit = defineEmits(['refresh']) // 定义 success 事件,用于操作成功后的回调
</script>

View File

@@ -1,6 +1,6 @@
<template>
<ContentWrap>
<el-collapse class="" v-model="activeNames">
<el-collapse v-model="activeNames" class="">
<el-collapse-item name="basicInfo">
<template #title>
<span class="text-base font-bold">基本信息</span>
@@ -20,11 +20,11 @@
</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="QQ">{{ customer.qq }} </el-descriptions-item>
<el-descriptions-item label="微信">{{ customer.wechat }} </el-descriptions-item>
<el-descriptions-item label="网址">{{ customer.website }} </el-descriptions-item>
<el-descriptions-item label="所在地">{{ customer.areaName }} </el-descriptions-item>
<el-descriptions-item label="邮箱">{{ customer.email }}</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="网址">{{ customer.website }}</el-descriptions-item>
<el-descriptions-item label="所在地">{{ customer.areaName }}</el-descriptions-item>
<el-descriptions-item label="详细地址"
>{{ customer.detailAddress }}
</el-descriptions-item>
@@ -38,8 +38,8 @@
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1">
<el-descriptions-item label="客户描述">{{ customer.description }} </el-descriptions-item>
<el-descriptions-item label="备注">{{ customer.remark }} </el-descriptions-item>
<el-descriptions-item label="客户描述">{{ customer.description }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ customer.remark }}</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
<el-collapse-item name="systemInfo">
@@ -47,8 +47,8 @@
<span class="text-base font-bold">系统信息</span>
</template>
<el-descriptions :column="2">
<el-descriptions-item label="负责人">{{ customer.ownerUserName }} </el-descriptions-item>
<el-descriptions-item label="创建人">{{ customer.creatorName }} </el-descriptions-item>
<el-descriptions-item label="负责人">{{ customer.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="创建人">{{ customer.creatorName }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ customer.createTime ? formatDate(customer.createTime) : '空' }}
</el-descriptions-item>
@@ -60,15 +60,16 @@
</el-collapse>
</ContentWrap>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import * as CustomerApi from '@/api/crm/customer'
import { DICT_TYPE } from '@/utils/dict'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'CustomerDetailsInfo' })
const { customer } = defineProps<{
customer: CustomerApi.CustomerVO // 客户明细
}>()
const activeNames = ref(['basicInfo', 'systemInfo']) // 展示的折叠面板
</script>
<style scoped lang="scss"></style>
<style lang="scss" scoped></style>

View File

@@ -5,7 +5,9 @@
<el-tab-pane label="详细资料">
<CustomerDetailsInfo :customer="customer" />
</el-tab-pane>
<el-tab-pane label="操作日志" lazy>TODO 待开发</el-tab-pane>
<el-tab-pane label="操作日志">
<OperateLogV2 :log-list="logList" />
</el-tab-pane>
<el-tab-pane label="联系人" lazy>
<ContactList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
</el-tab-pane>
@@ -38,24 +40,39 @@ import ReceivableList from '@/views/crm/receivable/components/ReceivableList.vue
import ReceivablePlanList from '@/views/crm/receivable/plan/components/ReceivablePlanList.vue' // 回款计划列表
import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 团队成员列表(权限)
import { BizTypeEnum } from '@/api/crm/permission'
import { OperateLogV2VO } from '@/api/system/operatelog'
defineOptions({ name: 'CrmCustomerDetail' })
const route = useRoute()
const id = Number(route.params.id) // 客户编号
const loading = ref(true) // 加载中
/** 获取详情 */
const customer = ref<CustomerApi.CustomerVO>({} as CustomerApi.CustomerVO) // 客户详情
const getCustomer = async (id: number) => {
loading.value = true
try {
customer.value = await CustomerApi.getCustomer(id)
await getOperateLog(id)
} finally {
loading.value = false
}
}
const logList = ref<OperateLogV2VO[]>([]) // 操作日志列表
/**
* 获取操作日志
*/
const getOperateLog = async (customerId: number) => {
if (!customerId) {
return
}
const data = await CustomerApi.getOperateLogPage({
pageNo: 1,
pageSize: 10,
bizId: customerId
})
logList.value = data.list
}
/** 初始化 */
const { delView } = useTagsViewStore() // 视图操作
const { currentRoute } = useRouter() // 路由

View File

@@ -101,38 +101,24 @@
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="所属行业" prop="industryId" width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
</el-table-column>
<el-table-column align="center" label="手机" prop="mobile" width="120" />
<el-table-column align="center" label="电话" prop="telephone" width="120" />
<el-table-column align="center" label="客户来源" 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="industryId" width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
</el-table-column>
<el-table-column align="center" label="客户等级" prop="level" width="120">
<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="mobile" width="120" />
<el-table-column align="center" label="详细地址" prop="detailAddress" width="200" />
<el-table-column align="center" label="负责人" prop="ownerUserName" />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" />
<el-table-column align="center" label="创建人" prop="creatorName" />
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
prop="createTime"
width="180px"
/>
<el-table-column align="center" label="成交状态" prop="dealStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template>
</el-table-column>
<el-table-column align="center" label="网址" prop="website" width="200" />
<el-table-column
:formatter="dateFormatter"
align="center"
@@ -140,6 +126,13 @@
prop="contactNextTime"
width="180px"
/>
<el-table-column align="center" label="备注" prop="remark" width="200" />
<el-table-column align="center" label="成交状态" prop="dealStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template>
</el-table-column>
<!-- TODO @puhui999距进入公海天数 -->
<el-table-column
:formatter="dateFormatter"
align="center"
@@ -147,12 +140,23 @@
prop="contactLastTime"
width="180px"
/>
<el-table-column align="center" label="锁定状态" prop="lockStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" />
</template>
</el-table-column>
<!-- TODO @wanwan 距进入公海天数 -->
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
prop="updateTime"
width="180px"
/>
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
prop="createTime"
width="180px"
/>
<el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
<el-table-column align="center" label="创建人" prop="creatorName" width="100px" />
<el-table-column align="center" fixed="right" label="操作" min-width="150">
<template #default="scope">
<el-button

View File

@@ -56,12 +56,12 @@
</Dialog>
</template>
<script setup lang="ts">
import * as CustomerLimitConfigApi from '@/api/crm/customerLimitConfig'
import * as CustomerLimitConfigApi from '@/api/crm/customer/limitConfig'
import * as DeptApi from '@/api/system/dept'
import { defaultProps, handleTree } from '@/utils/tree'
import * as UserApi from '@/api/system/user'
import { cloneDeep } from 'lodash-es'
import { LimitConfType } from '@/api/crm/customerLimitConfig'
import { LimitConfType } from '@/api/crm/customer/limitConfig'
const { t } = useI18n() //
const message = useMessage() //
@@ -72,7 +72,7 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
type: undefined,
type: LimitConfType.CUSTOMER_LOCK_LIMIT, // IDE
userIds: undefined,
deptIds: undefined,
maxCount: undefined,
@@ -88,15 +88,11 @@ const deptTree = ref() // 部门树形结构
const userTree = ref() //
/** 打开弹窗 */
const open = async (type: string, id?: number, limitConfType?: LimitConfType) => {
const open = async (type: string, limitConfType: LimitConfType, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
await getDeptTree()
//
await getUserTree()
//
if (id) {
formLoading.value = true
@@ -108,6 +104,10 @@ const open = async (type: string, id?: number, limitConfType?: LimitConfType) =>
} else {
formData.value.type = limitConfType
}
//
await getDeptTree()
//
await getUserTree()
}
defineExpose({ open }) // open
@@ -141,7 +141,7 @@ const submitForm = async () => {
const resetForm = () => {
formData.value = {
id: undefined,
type: undefined,
type: LimitConfType.CUSTOMER_LOCK_LIMIT,
userIds: undefined,
deptIds: undefined,
maxCount: undefined,

View File

@@ -1,7 +1,5 @@
<template>
<el-button type="primary" plain @click="handleQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 刷新
</el-button>
<el-button plain @click="handleQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 刷新 </el-button>
<el-button
type="primary"
plain
@@ -87,10 +85,10 @@
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import * as CustomerLimitConfigApi from '@/api/crm/customerLimitConfig'
import CustomerLimitConfigForm from '@/views/crm/config/customerLimitConfig/CustomerLimitConfigForm.vue'
import * as CustomerLimitConfigApi from '@/api/crm/customer/limitConfig'
import CustomerLimitConfigForm from './CustomerLimitConfigForm.vue'
import { DICT_TYPE } from '@/utils/dict'
import { LimitConfType } from '@/api/crm/customerLimitConfig'
import { LimitConfType } from '@/api/crm/customer/limitConfig'
defineOptions({ name: 'CustomerLimitConfigList' })
@@ -107,8 +105,6 @@ const queryParams = reactive({
pageSize: 10,
type: confType
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
@@ -125,7 +121,7 @@ const getList = async () => {
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id, confType)
formRef.value.open(type, confType, id)
}
/** 删除按钮操作 */

View File

@@ -12,8 +12,8 @@
</ContentWrap>
</template>
<script setup lang="ts">
import CustomerLimitConfigList from '@/views/crm/config/customerLimitConfig/CustomerLimitConfigList.vue'
import { LimitConfType } from '@/api/crm/customerLimitConfig'
import CustomerLimitConfigList from './CustomerLimitConfigList.vue'
import { LimitConfType } from '@/api/crm/customer/limitConfig'
defineOptions({ name: 'CrmCustomerLimitConfig' })
</script>

View File

@@ -56,7 +56,7 @@
</ContentWrap>
</template>
<script setup lang="ts">
import * as CustomerPoolConfigApi from '@/api/crm/customerPoolConfig'
import * as CustomerPoolConfigApi from '@/api/crm/customer/poolConfig'
import { CardTitle } from '@/components/Card'
defineOptions({ name: 'CrmCustomerPoolConfig' })
@@ -67,10 +67,10 @@ const { t } = useI18n() // 国际化
const formLoading = ref(false)
const formData = ref({
enabled: false,
contactExpireDays: 0,
dealExpireDays: 0,
contactExpireDays: undefined,
dealExpireDays: undefined,
notifyEnabled: false,
notifyDays: 0
notifyDays: undefined
})
const formRules = reactive({
enabled: [{ required: true, message: '是否启用客户公海不能为空', trigger: 'blur' }]
@@ -100,7 +100,7 @@ const onSubmit = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as CustomerPoolConfigApi.CustomerPoolConfigVO
const data = formData.value as CustomerPoolConfigApi.CustomerPoolConfigVO
await CustomerPoolConfigApi.saveCustomerPoolConfig(data)
message.success(t('common.updateSuccess'))
await getConfig()

View File

@@ -17,6 +17,7 @@
/>
</el-select>
</el-form-item>
<!-- TODO @puhui999编辑时level 没带过来 -->
<el-form-item label="权限级别" prop="level">
<el-radio-group v-model="formData.level">
<template

View File

@@ -24,6 +24,7 @@
:stripe="true"
@selection-change="handleSelectionChange"
>
<!-- TODO @puhui999负责人不允许选中 -->
<el-table-column type="selection" width="55" />
<el-table-column align="center" label="姓名" prop="nickname" />
<el-table-column align="center" label="部门" prop="deptName" />

View File

@@ -197,7 +197,7 @@ defineOptions({ name: 'ProductSpuBasicInfoForm' })
const ruleConfig: RuleConfig[] = [
{
name: 'stock',
rule: (arg) => arg >= 1,
rule: (arg) => arg >= 0,
message: '商品库存必须大于等于 1 '
},
{
@@ -213,7 +213,7 @@ const ruleConfig: RuleConfig[] = [
{
name: 'costPrice',
rule: (arg) => arg >= 0.01,
message: '商品成本价格必须大于等于 0.01 元!!!'
message: '商品成本价格必须大于等于 0.00 元!!!'
}
]

View File

@@ -30,6 +30,7 @@ const getPageDetail = async (id: any) => {
formLoading.value = false
}
}
// 提交表单
const submitForm = async () => {
// 校验表单

View File

@@ -27,10 +27,11 @@
</DiyEditor>
</template>
<script setup lang="ts">
// TODO @疯狂:要不要建个 decorate 目录,然后挪进去,改成 index.vue这样可以更明确看到是个独立界面哈更好找
import * as DiyTemplateApi from '@/api/mall/promotion/diy/template'
import * as DiyPageApi from '@/api/mall/promotion/diy/page'
import { useTagsViewStore } from '@/store/modules/tagsView'
import { DiyComponentLibrary, PAGE_LIBS } from '@/components/DiyEditor/util'
import { DiyComponentLibrary, PAGE_LIBS } from '@/components/DiyEditor/util' // 商城的 DIY 组件,在 DiyEditor 目录下
import { toNumber } from 'lodash-es'
/** 装修模板表单 */
@@ -51,7 +52,7 @@ const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>()
const formRef = ref() // 表单 Ref
// 当前编辑的属性
const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>()
// 商城H5预览地址
// 商城 H5 预览地址
const previewUrl = ref('')
// 获取详情

View File

@@ -205,7 +205,7 @@ const handleUse = async (row: DiyTemplateApi.DiyTemplateVO) => {
// 使用模板的二次确认
await message.confirm(`是否使用模板“${row.name}”?`)
// 发起删除
await DiyTemplateApi.useDiyTemplate(row.id)
await DiyTemplateApi.useDiyTemplate(row.id!)
message.success('使用成功')
// 刷新列表
await getList()

View File

@@ -0,0 +1,113 @@
<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="name">
<el-input v-model="formData.name" placeholder="请输入文件名称" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" placeholder="请选择状态">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="文件内容" prop="content">
<Editor v-model="formData.content" height="150px" />
</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 { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import * as UReportDataApi from '@/api/report/ureport'
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,
status: undefined,
content: undefined,
remark: undefined,
})
const formRules = reactive({
name: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'change' }],
})
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 UReportDataApi.getUReportData(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
await formRef.value.validate()
// 提交请求
formLoading.value = true
try {
const data = formData.value as unknown as UReportDataApi.UReportDataVO
if (formType.value === 'create') {
await UReportDataApi.createUReportData(data)
message.success(t('common.createSuccess'))
} else {
await UReportDataApi.updateUReportData(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
status: undefined,
content: undefined,
remark: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@@ -0,0 +1,13 @@
<template>
<ContentWrap>
<IFrame :src="src" />
</ContentWrap>
</template>
<script lang="ts" setup>
import { getAccessToken } from '@/utils/auth'
defineOptions({ name: 'UReportData' })
const BASE_URL = import.meta.env.VITE_BASE_URL
const src = ref(BASE_URL + '/ureport/designer?token=' + getAccessToken())
</script>

View File

@@ -0,0 +1,220 @@
<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="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
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"
plain
@click="openForm('create')"
v-hasPermi="['report:ureport-data:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['report:ureport-data: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="ID" align="center" prop="id" />
<el-table-column label="文件名称" align="center" prop="name" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="文件内容" align="center" prop="content" />
<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="['report:ureport-data:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['report:ureport-data: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>
<!-- 表单弹窗添加/修改 -->
<UReportDataForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as UReportDataApi from '@/api/report/ureport'
import UReportDataForm from './UReportDataForm.vue'
defineOptions({ name: 'UReportData' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
status: null,
remark: null,
createTime: [],
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await UReportDataApi.getUReportDataPage(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 UReportDataApi.deleteUReportData(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await UReportDataApi.exportUReportData(queryParams)
download.excel(data, 'Ureport2报表.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>