修改用户页面 询单

This commit is contained in:
浅念
2025-08-06 18:36:42 +08:00
parent 3e24d1905f
commit 8deecc8197
8 changed files with 197 additions and 189 deletions
+17
View File
@@ -83,6 +83,15 @@ export class manageService {
// showErrorMessage: false // 不显示错误消息
})
}
//重新分配询单
static inquiryreallocation(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/inquiry/reallocation',
params
// showErrorMessage: false // 不显示错误消息
})
}
//发布询单
static inquiryrelease(params: any) {
return request.post<Api.Work.AddResponse>({
@@ -136,4 +145,12 @@ export class manageService {
params
})
}
//用户编辑
static userEdit(params: any) {
return request.get<Api.Common.AddResponse>({
url: '/admin/user/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
}
+8
View File
@@ -31,6 +31,14 @@ export class CrmService {
params
})
}
//标记无效
static customerReport(params: any) {
return request.get<any>({
url: '/crm/customer/report',
params
// showErrorMessage: false // 不显示错误消息
})
}
//切换等级crm/customer/grade
static customergrade(params: any) {
return request.post<Api.Work.AddResponse>({
+2 -123
View File
@@ -1,80 +1,5 @@
<template>
<div class="customer-page">
<!-- 顶部操作栏 -->
<div class="customer-toolbar boxshadow">
<div class="customer-search-group">
<el-select
v-model="selectValue"
style="min-width: 120px"
filterable
multiple
collapse-tags
placeholder="请选择跟单人"
>
<el-option v-for="v in userOptions" :key="v.id" :label="v.name" :value="v.id">
</el-option>
</el-select>
</div>
</div>
<!-- 筛选标签 -->
<div class="customer-tags boxshadow">
<!-- 前3组 -->
<div class="filter-row" v-for="item in visibleTagGroups" :key="item.id">
<span class="filter-label">{{ item.name }}</span>
<div class="filter-tags">
<span
:class="['tag-itemall', { 'tag-active': tagActiveMap[item.id] === '' }]"
@click="handleTagClick(item.id, '')"
>全部</span
>
<span
class="tag-items"
v-for="item1 in item.tags"
:key="item1.id"
@click="handleTagClick(item.id, item1.id)"
>
<span :class="['tag-item', { 'tag-active': tagActiveMap[item.id] === item1.id }]">
{{ item1.name }}
</span>
<el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge>
</span>
</div>
</div>
<!-- 更多 -->
<transition name="fade">
<div v-if="showMore">
<div class="filter-row" v-for="item in moreTagGroups" :key="item.id">
<span class="filter-label">{{ item.name }}</span>
<div class="filter-tags">
<span
:class="['tag-itemall', { 'tag-active': tagActiveMap[item.id] === '' }]"
@click="handleTagClick(item.id, '')"
>全部</span
>
<span
class="tag-items"
v-for="item1 in item.tags"
:key="item1.id"
@click="handleTagClick(item.id, item1.id)"
>
<span :class="['tag-item', { 'tag-active': tagActiveMap[item.id] === item1.id }]">
{{ item1.name }}
</span>
<el-badge :value="item1.count" :max="99" class="itemtag" type="primary"> </el-badge>
</span>
</div>
</div>
</div>
</transition>
<div class="filter-more-btn" v-if="moreTagGroups.length">
<el-link underline="never" @click="showMore = !showMore">
{{ showMore ? '收起' : '更多' }}
<i v-if="showMore" class="iconfont-sys"> &#xe864;</i>
<i v-else class="iconfont-sys">&#xe867;</i>
</el-link>
</div>
</div>
<div class="boxshadow">
<!-- 表格 -->
<ArtTable
@@ -105,7 +30,7 @@
</span>
</template>
</el-table-column>
<el-table-column prop="follow_next" label="下次跟进时间"></el-table-column>
<el-table-column prop="user_name" label="标记人"></el-table-column>
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column fixed="right" label="操作" width="200px" align="center">
@@ -154,13 +79,11 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { CrmService } from '@/api/crmApi'
import { ref, reactive, onMounted, watch } from 'vue'
import { useAuth } from '@/composables/useAuth'
import { manageService } from '@/api/adminApi'
const { hasAuth } = useAuth()
const selectValue = ref<string[]>([])
const showMore = ref(false)
const loading = ref(false)
const detailDialogVisible = ref(false)
const audetDialogVisible = ref(false)
@@ -181,36 +104,11 @@
userOptions.value = res || []
// return res || []
}
// 获取列表数据
const tagActiveMap = reactive<{ [groupId: string]: string }>({})
//获取标签
type TagGroup = { id: string; name: string; tags: { id: string; name: string; count: number }[] }
const tagGroups = ref<TagGroup[]>([])
const tagGrouplistfn = async () => {
const res = await CrmService.tagGrouplist({ scene: 'customers' })
tagGroups.value = res || []
tagGroups.value.forEach((group) => {
if (group.tags && Array.isArray(group.tags)) {
tagActiveMap[group.id] = ''
}
})
}
// 计算前3组和更多组
// eslint-disable-next-line vue/valid-define-props
defineProps()
const visibleTagGroups = computed(() => tagGroups.value.slice(0, 3))
const moreTagGroups = computed(() => tagGroups.value.slice(3))
// 表格数据
const tableData = ref<any[]>([])
onMounted(() => {
getuserList()
gettableList()
tagGrouplistfn()
})
// tabs 切换联动
watch([selectValue], () => {
pagination.currentPage = 1
gettableList()
})
const gettableList = async () => {
loading.value = true
@@ -221,15 +119,6 @@
size: pageSize,
scene: 'audit'
}
if (selectValue.value && selectValue.value.length) {
params.user_id = selectValue.value.join(',')
}
// 标签参数,所有选中的标签id组成数组
const selectedTagIds = Object.values(tagActiveMap).filter(Boolean)
if (selectedTagIds.length) {
params.tag_id = selectedTagIds
}
console.log(params)
const { data, current, size, total } = await manageService.getcrmCustomerList(params)
tableData.value = data.map((item: any) => ({
...item
@@ -267,16 +156,6 @@
audetDialogVisible.value = false
gettableList()
}
// 标签选中状态,key为组id,值为选中的标签id
function handleTagClick(groupId: string, tagId: string) {
// if (tagActiveMap[groupId] === tagId) {
// tagActiveMap[groupId] = '' // 取消选中
// } else {
tagActiveMap[groupId] = tagId // 选中
// }
pagination.currentPage = 1
gettableList()
}
function processImages(html: string) {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
+3 -2
View File
@@ -82,7 +82,8 @@
<el-button
type="primary"
@click="plzyDialogVisible = true"
v-if="hasAuth('customer@transfer') && selectedRows.length > 0"
v-if="hasAuth('customer@transfer')"
:disabled="selectedRows.length === 0"
>
<i class="iconfont-sys">&#xe794;</i> 批量转移
</el-button>
@@ -119,7 +120,7 @@
</el-table-column>
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
<el-table-column prop="user_name" label="跟单人"></el-table-column>
<el-table-column prop="follow_next" label="下次跟进时间"></el-table-column>
<el-table-column prop="follow_next" label="下次跟进"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column fixed="right" label="操作" width="200px" align="center">
<template #default="scope">
+54 -25
View File
@@ -60,9 +60,7 @@
}}</el-button>
</div>
<div class="form-btn-right">
<el-button class="reset-button" @click="addfn()"
><i class="iconfont-sys">&#xe602;</i> 录单</el-button
>
</div>
</div>
</el-col>
@@ -70,6 +68,7 @@
</el-form>
</section>
<div class="table">
<el-button class="reset-button" @click="addfn()" ><i class="iconfont-sys">&#xe602;</i> 录单</el-button>
<ArtTable
ref="tableRef"
row-key="id"
@@ -92,7 +91,8 @@
<span>
{{scope.row.countryInfo? scope.row.countryInfo.cn_addr : ''}}
</span>
<span class="steer" v-if="scope.row.countryInfo">{{ scope.row.countryInfo.steering }}</span>
<el-tag class="steer" type="warning" v-if="scope.row.countryInfo">{{ scope.row.countryInfo.steering }}</el-tag>
<!-- <span class="steer" v-if="scope.row.countryInfo">{{ scope.row.countryInfo.steering }}</span> -->
</template>
</el-table-column>
<el-table-column prop="phone" label="渠道">
@@ -118,8 +118,9 @@
</el-table-column>
<el-table-column prop="recipient" label="跟单人">
<template #default="scope">
<span>
<span style="color:#008477;cursor: pointer;" v-if="scope.row.recipientInfo" @click="onFenpei(scope.row,'edit')">
{{scope.row.recipientInfo? scope.row.recipientInfo.name : ''}}
<i class="iconfont-sys">&#xe626;</i>
</span>
</template>
</el-table-column>
@@ -143,11 +144,11 @@
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column fixed="right" label="操作" width="260px">
<template #default="scope">
<div class="follow-action fenpei" @click="onFenpei(scope.row)" v-if="scope.row.status!= 2">
<div class="follow-action fenpei" @click="onFenpei(scope.row,'add')" v-if="scope.row.status!= 2">
<span class="custom-clock-icon" style="margin-right: 2px; vertical-align: middle"
><i class="iconfont-sys">&#xe852;</i></span
>
分配跟单
分配
</div>
<div class="follow-action detil" @click="onDetail(scope.row)">
<span class="custom-clock-icon" style="margin-right: 2px; vertical-align: middle"
@@ -279,11 +280,24 @@
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="24">
<el-col :span="12">
<el-form-item label="WhatsApp" prop="whatsapp">
<el-input v-model="addForm.whatsapp" placeholder="请输入WhatsApp" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="跟单人" prop="country">
<el-select v-model="addForm.recipient" filterable placeholder="请选择跟单人">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="详情内容" prop="content">
<ArtWangEditor class="el-top" v-model="editorHtml" />
@@ -296,7 +310,7 @@
</el-form>
</el-dialog>
<!-- 分配 -->
<el-dialog v-model="fenpeiDialogVisible" title="分配跟单" width="360px">
<el-dialog v-model="fenpeiDialogVisible" :title="dialogTypefp === 'add' ? '分配跟单' : '重新分配跟单'" width="360px">
<el-form :model="fenpeiForm" label-width="0">
<el-form-item>
<el-select v-model="fenpeiForm.recipient" filterable placeholder="请选择" style="width: 100%">
@@ -324,6 +338,7 @@
import { manageService } from '@/api/adminApi'
const loading = ref(false)
const dialogType = ref('add')
const dialogTypefp = ref('add')
const { width } = useWindowSize()
const isMobile = computed(() => width.value < 500)
const filter = ref({
@@ -355,7 +370,8 @@
tel: '',
contacts: '',
whatsapp: '',
content: ''
content: '',
recipient: ''
})
// 响应式表单数据
const formFilters = reactive({ ...filter })
@@ -396,6 +412,13 @@
const res = await CrmService.getCountry()
countryOptions.value = res || []
}
const userOptions = ref<any>()
const getuserList = async () => {
// 这里调用获取用户列表的接口
const res = await manageService.presetusers()
userOptions.value = res || []
// return res || []
}
// 计算属性:将时间格式化为 "开始日期 - 结束日期"
const formattedTimeRange = () => {
if (!filter.value.time || filter.value.time.length !== 2) {
@@ -448,6 +471,7 @@
onMounted(() => {
getgetChannel()
gettableList()
getuserList()
timer.value = window.setInterval(() => {
refreshKey.value++
}, 1000)
@@ -507,7 +531,8 @@
tel: '',
contacts: '',
whatsapp: '',
content: ''
content: '',
recipient: ''
})
editorHtml.value = ''
}
@@ -565,7 +590,8 @@
tel: row.tel,
contacts: row.contacts,
whatsapp: row.whatsapp,
content: row.content
content: row.content,
recipient: row.recipientInfo ? row.recipientInfo.id : ''
})
editorHtml.value = row.content
// 这里可以添加编辑逻辑
@@ -614,16 +640,9 @@
id: '',
recipient: ''
})
const userOptions = ref<any>()
const getuserList = async () => {
// 这里调用获取用户列表的接口
const res = await manageService.presetusers()
userOptions.value = res || []
// return res || []
}
//分配
const onFenpei = (row: any) => {
getuserList()
const onFenpei = (row: any, edits: any) => {
dialogTypefp.value = edits
fenpeiForm.id = row.id
fenpeiDialogVisible.value = true
}
@@ -632,12 +651,21 @@
ElMessage.warning('请选择跟单人')
return
}
if (dialogTypefp.value === 'add') {
const res = await manageService.inquiryallocation({
id: fenpeiForm.id,
recipient: fenpeiForm.recipient,
status: 2
})
ElMessage.success(res?.message || '分配成功!')
} else {
const res = await manageService.inquiryreallocation({
id: fenpeiForm.id,
recipient: fenpeiForm.recipient,
status: 2
})
ElMessage.success(res?.message || '分配成功!')
}
fenpeiDialogVisible.value = false
gettableList()
}
@@ -711,6 +739,7 @@
}
.table {
margin-top: 10px;
:deep(.el-table__empty-block) {
height: 300px !important;
}
@@ -816,10 +845,10 @@
}
.steer {
margin-left: 5px;
display: inline-block;
border: 1px solid #00a43f;
padding: 0px 4px;
color: #00a43f;
// display: inline-block;
// border: 1px solid #00a43f;
// padding: 0px 4px;
// color: #00a43f;
}
.dtitle {
line-height: 40px;
+82 -28
View File
@@ -3,6 +3,7 @@
<!-- 顶部操作栏 -->
<div class="customer-toolbar boxshadow">
<div class="customer-search-group">
<el-input v-model="keyword" placeholder="请输入关键字" />
<el-select
v-model="selectValue"
style="min-width: 120px"
@@ -30,13 +31,13 @@
>
<template #default>
<el-table-column prop="id" label="用户ID" align="center" />
<el-table-column prop="sn" label="SN" align="center" />
<el-table-column prop="follow" label="头像" align="center">
<template #default="scope">
<img :src="scope.row.avatar" alt="头像" class="avatar" />
</template>
</el-table-column>
<el-table-column prop="name" label="用户名称" align="center" />
<el-table-column prop="customer_count" label="客户数量" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="follow" label="状态" align="center">
@@ -46,6 +47,7 @@
</span>
</template>
</el-table-column>
<el-table-column prop="customer_count" label="客户数量" align="center" />
<el-table-column fixed="right" label="操作" width="200px" align="center">
<template #default="scope">
<el-link
@@ -57,6 +59,15 @@
>
<i class="iconfont-sys"> &#xe794;</i>客户转移
</el-link>
<el-link
type="success"
underline="never"
style="margin-right: 8px"
@click="onEdit(scope.row)"
v-if="hasAuth('user@customer_transfer')"
>
<i class="iconfont-sys"> &#xe6bf;</i>编辑
</el-link>
</template>
</el-table-column>
</template>
@@ -128,6 +139,45 @@
</div>
</el-form>
</el-dialog>
<el-dialog
title="编辑用户"
v-model="AddDialogVisible"
width="800px"
:close-on-click-modal="false"
>
<el-form :model="addForm" ref="addFormRef" label-width="80px" class="add-form">
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="用户名" prop="country">
<el-input v-model="addForm.name" placeholder="请输入用户名" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="Email" prop="email">
<el-input v-model="addForm.email" placeholder="请输入Email" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="电话" prop="tel">
<el-input v-model="addForm.phone" placeholder="请输入电话" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="状态" prop="status">
<el-select v-model="addForm.status">
<el-option label="正常" :value="1" />
<el-option label="离职" :value="2" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<div class="form-submit-row">
<el-button type="primary" size="large" style="width: 50%" @click="handleAddSubmit"
>提交</el-button
>
</div>
</el-form>
</el-dialog>
</template>
<script setup lang="ts">
@@ -136,10 +186,12 @@
import { useAuth } from '@/composables/useAuth'
const { hasAuth } = useAuth()
const selectValue = ref<string[]>([])
const keyword = ref<string>('')
const loading = ref(false)
const loadingkh = ref(false)
const detailDialogVisible = ref(false)
const plzyDialogVisible = ref(false)
const AddDialogVisible = ref(false)
const pagination = reactive({
currentPage: 1,
pageSize: 10,
@@ -157,6 +209,13 @@
const zyForm = reactive({
customer_id: ''
})
const addForm = reactive({
id: '',
name: '',
email: '',
phone: '',
status: ''
})
const userOptions = ref<any>()
const getuserList = async () => {
// 这里调用获取用户列表的接口
@@ -172,7 +231,7 @@
gettableList()
})
// tabs 切换联动
watch([selectValue], () => {
watch([selectValue, keyword], () => {
pagination.currentPage = 1
gettableList()
})
@@ -185,7 +244,10 @@
size: pageSize
}
if (selectValue.value) {
params.keyword = selectValue.value
params.id = selectValue.value
}
if (keyword.value) {
params.keyword = keyword.value
}
const { records, current, size, total } = await manageService.getUserList(params)
tableData.value = records.map((item: any) => ({
@@ -275,6 +337,21 @@
detailDialogVisible.value = false
gettableList()
}
// 编辑用户
const onEdit = (row: any) => {
AddDialogVisible.value = true
addForm.id = row.id
addForm.name = row.name
addForm.email = row.email
addForm.phone = row.phone
addForm.status = row.status
}
const handleAddSubmit = async () => {
const res = await manageService.userEdit(addForm)
ElMessage.success(res?.message || '编辑成功!')
AddDialogVisible.value = false
gettableList()
}
</script>
<style scoped lang="scss">
@@ -410,30 +487,7 @@
.fade-leave-to {
opacity: 0;
}
.tag-items {
cursor: pointer;
border-radius: 4px;
padding: 5px 10px;
transition: background 0.2s;
min-width: 100px;
display: inline-block;
margin-right: 30px;
}
.tag-item {
border-radius: 4px;
padding: 5px 10px;
}
.tag-itemall {
border-radius: 4px;
padding: 5px 10px;
margin-right: 20px;
}
.tag-active {
background: #3471ff;
color: #fff;
}
.tag-active :deep(.el-badge__content) {
color: #3471ff !important; /* 文字颜色 */
background-color: #fff !important; /* 背景色 */
.form-submit-row {
text-align: center;
}
</style>
+2 -2
View File
@@ -36,11 +36,11 @@
<div class="form">
<!-- 登录方式切换 tab -->
<div class="login-type-tabs">
<span
<!-- <span
:class="{ active: activeLoginType === 'password' }"
@click="activeLoginType = 'password'"
>账号密码登录</span
>
> -->
<span
:class="{ active: activeLoginType === 'qrcode' }"
@click="activeLoginType = 'qrcode'"
+23 -3
View File
@@ -101,16 +101,17 @@
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="WhatsApp" label="WhatsApp" align="center" />
<!-- <el-table-column prop="WhatsApp" label="WhatsApp" align="center" /> -->
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="grade_txt" label="等级" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<el-table-column prop="describe" label="备注" align="center" />
<!-- <el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
<span :class="statusClass(scope.row.follow)">
{{ scope.row.follow_txt }}
</span>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column prop="follow_next" label="下次跟进时间"></el-table-column>
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
@@ -143,6 +144,9 @@
>
<i class="iconfont-sys">&#xe6bf;</i> 跟进
</el-link>
<el-link type="danger" underline="never" @click="reportfn(scope.row)">
<i class="iconfont-sys">&#xe701;</i> 标记无效
</el-link>
<el-link
type="danger"
underline="never"
@@ -302,6 +306,22 @@
// 用户点击了取消
})
}
// 标记无效
const reportfn = (row: any) => {
ElMessageBox.confirm('确定要标记无效吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
const res = await CrmService.customerReport({ id: row.id })
ElMessage.success(res?.message || '提交成功!')
gettableList()
})
.catch(() => {
// 用户点击了取消
})
}
function processImages(html: string) {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')