提交 4fc50246 authored 作者: pengxiaohui's avatar pengxiaohui

feat: 大客户管理页面接口调试

上级 6f71692e
......@@ -27,3 +27,7 @@ export function uploadFile(data) {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
// 搜索紫荆用户
export function userSearch(params) {
return httpRequest.get('/api/customer/admin/v1/system/search-sso-users', { params })
}
......@@ -5,7 +5,7 @@
<div class="table-list-filter">
<el-form v-if="filters.length" :inline="true" :model="params" ref="filterForm">
<template v-for="item in filters">
<el-form-item :label="item.label" :prop="item.prop" :key="item.prop">
<el-form-item :label="item.label" :prop="item.prop" :key="item.prop" class="filter-form-item">
<template v-if="item.slots">
<slot :name="item.slots" v-bind="{ params }"></slot>
</template>
......@@ -31,11 +31,22 @@
</template>
</el-form-item>
</template>
<el-form-item class="filter-buttons">
<el-form-item class="filter-buttons" v-if="!searchResetSeparateLine">
<el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
<el-button icon="el-icon-refresh-left" @click="reset">重置</el-button>
</el-form-item>
</el-form>
<div class="filter-bar">
<div class="filte-bar-left-btns">
<template v-if="searchResetSeparateLine">
<el-button type="primary" icon="el-icon-search" size="small" @click="search">搜索</el-button>
<el-button icon="el-icon-refresh-left" size="small" @click="reset">重置</el-button>
</template>
</div>
<div class="filter-bar-right">
<slot name="filter-bar-right" />
</div>
</div>
</div>
<div class="table-list-hd-aside"><slot name="header-aside" /></div>
</div>
......@@ -47,7 +58,6 @@
v-loading="loading"
v-bind="$attrs"
v-on="$listeners"
style="width: 100%"
ref="table"
>
<template v-for="item in columns">
......@@ -89,6 +99,7 @@ export default {
remote: { type: Object, default: () => ({}) },
// 筛选
filters: { type: Array, default: () => [] },
searchResetSeparateLine: { type: Boolean, default: false},
// 列表项
columns: { type: Array, default: () => [] },
// 列表数据
......@@ -214,6 +225,16 @@ export default {
.table-list-filter {
flex: 1;
}
.filter-bar{
display:flex;
margin-bottom:15px;
}
.filte-bar-left-btns{
flex: 1;
}
.el-form--inline .el-form-item{
margin-right:30px;
}
.table-list-bd {
flex: 1;
}
......
<template>
<el-select v-model="userId" v-bind="options" placeholder="输入邮箱/手机号码搜索" filterable remote :remote-method="fetchUserList" :loading="searchUsersloading" @change="handleChange">
<el-option :label="user.realname || user.nickname " :value="user.id" v-for="user in userList" :key="user.id" >
<span style="float: left">
{{ user.realname || user.nickname }}
<template v-if="user.mobile">(手机号:{{user.mobile}})</template>
</span>
<span style="float: right; color: #8492a6; font-size: 13px; margin:0 20px 0 10px;" v-if="user.email">邮箱:{{ user.email }}</span>
<span style="float: right; color: #8492a6; font-size: 13px; margin:0 20px 0 10px;" v-else>ID:{{ user.id }}</span>
</el-option>
</el-select>
</template>
<script>
import { userSearch } from '@/api/base.js'
const MOBILE_REG = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{4,8}$/
const EMAIL_REG = /^[A-Za-z0-9]+([_.\\-][A-Za-z0-9]+)*@[A-Za-z0-9-.]+$/
export default {
props: {
value: {
type: [Array, String]
},
defaultList: {
type: Array,
default: () => {
return []
}
},
options: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
userId: this.value,
searchUsersloading: false,
userList: []
}
},
watch: {
value: {
handler: function (nv) {
this.userId = nv
},
immediate: true,
deep: true
},
defaultList: {
handler: function (nv) {
this.userList = nv
},
immediate: true,
deep: true
}
},
methods: {
handleChange() {
const selectedUser = this.userList.find(item => item.id === this.userId)
this.$emit('input', this.userId)
this.$emit('select', selectedUser)
},
fetchUserList(val) {
let searchType = 'username'
if (EMAIL_REG.test(val)) {
searchType = 'email'
} else if (MOBILE_REG.test(val)) {
searchType = 'mobile'
}
if (!val) return false
else {
const params = {
[searchType]: val
}
this.searchUsersloading = true
userSearch(params)
.then(res => {
this.searchUsersloading = false
if (res.data && Array.isArray(res.data.items)) {
this.userList = res.data.items
}
})
.catch(() => {})
}
}
}
}
</script>
<style scoped>
.el-select{
width:100%;
}
</style>
\ No newline at end of file
import httpRequest from '@/utils/axios'
// 获取用户信息
export function getUser() {
return httpRequest.get('/api/passport/account/get-user-info')
// 获取大客户列表
export function getCustomerList(params) {
return httpRequest.get('/api/customer/admin/v1/customers', { params })
}
// 新建客户组
export function createCustomer(data) {
return httpRequest.post('/api/customer/admin/v1/customer', data)
}
<template>
<el-dialog custom-class="create-custom-dialog" title="创建客户" :visible="value" :close-on-click-modal="false" :close-on-press-escape="false" top="50px" @close="handleClose">
<!-- <div slot="title">
</div> -->
<el-form :model="form" :rules="rules" ref="ruleForm" label-width="90px">
<el-form-item label="客户名称" prop="name">
<el-input v-model="form.name" size="small" placeholder="请输入客户名称"/>
</el-form-item>
<el-form-item label="客户简称">
<el-input v-model="form.short_name" size="small" placeholder="请输入客户简称"/>
</el-form-item>
<el-form-item label="客户来源" prop="source" class="form-item-select" style="margin-right:20px;">
<el-select v-model="form.source" placeholder="请选择客户来源" size="small" style="width:100%;">
<el-option label="公司资源" :value="1"></el-option>
<el-option label="自己开拓" :value="2"></el-option>
<el-option label="第三方介绍" :value="3"></el-option>
</el-select>
</el-form-item>
<el-form-item label="客户分类" prop="type" class="form-item-select">
<el-select v-model="form.type" placeholder="请选择客户分类" size="small" style="width:100%;">
<el-option label="普通客户" :value="1"></el-option>
<el-option label="重点客户" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="所在地区" prop="region" class="form-item-select">
<app-area v-model="form.region" />
</el-form-item>
<el-form-item label="详细地址">
<el-input v-model="form.address" size="small" placeholder="请输入详细地址"/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" size="small" rows="4" placeholder="请输入备注"/>
</el-form-item>
<el-form-item>
<el-button size="mini" @click="$emit('dialogClose')">取消</el-button>
<el-button type="primary" @click="handleSubmit" size="mini">提交</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script>
import AppArea from '@/components/base/AppArea.vue'
import { createCustomer } from '../api'
export default {
components: { AppArea },
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
type: '',
dialogVisible: true,
form: {
name: '',
short_name: '',
source: '',
type: '',
region: '',
address: '',
remark: ''
},
rules: {
name: { required: true, message: '请输入客户名称', trigger: 'blur' },
source: { required: true, message: '请选择客户来源', trigger: 'change' },
region: { required: true, message: '请选择所在地区', trigger: 'change' }
}
}
},
watch: {
value(val) {
this.dialogVisible = val
}
},
methods: {
handleClose() {
this.type = ''
this.$emit('input', false)
},
handleSubmit() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
this.fetchCreateCustomer()
}
})
},
fetchCreateCustomer() {
const params = Object.assign({}, this.form)
params.region = this.form.region.join('-')
createCustomer(params).then(res => {
if (res.code === 0 && res.data && res.data.id) {
this.$message.success('创建客户成功')
this.$emit('input', false)
this.$emit('change')
} else {
this.$message.error('创建客户失败')
}
}).catch(() => {
this.$message.error('创建客户失败')
})
}
}
}
</script>
<style scoped>
::v-deep .case-dialog{
width:95%;
max-width:1160px;
margin-bottom:20px;
}
::v-deep .el-dialog__header{
padding:12px 20px 20px;
}
::v-deep .el-dialog__headerbtn{
top:12px;
}
::v-deep .el-dialog__body{
padding:0 20px 20px;
}
::v-deep .form-item-select{
display: inline-block;
width:calc(50% - 10px);
}
::v-deep .el-cascader{
width:100%;
}
</style>
<template>
<app-card>
<app-list v-bind="tableOptions" ref="list">
<template #header-aside>
<el-button type="primary">创建客户</el-button>
<app-card class="customer">
<app-list v-bind="tableOptions" ref="list" searchResetSeparateLine>
<template #filter-bar-right>
<el-button type="primary" size="small" @click="dialogVisable = true">创建客户</el-button>
</template>
<!-- 筛选 -->
<template v-slot:filter-date="{ params }">
<el-date-picker
v-model="params.date"
v-model="params.create_date"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
start-placeholder="开始时间"
end-placeholder="结束时间"
size='small'
>
</el-date-picker>
</template>
<template v-slot:filter-region="{ params }">
<app-area v-model="params.region"></app-area>
</template>
<template v-slot:filter-userSearch="{ params }">
<app-user-search v-model="params.created_by"></app-user-search>
</template>
<template v-slot:filter-follow-date="{ params }">
<el-date-picker
v-model="params.follow_date"
type="datetimerange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
size='small'
>
</el-date-picker>
</template>
......@@ -23,36 +41,154 @@
</template>
</template>
</app-list>
<create-customer v-model="dialogVisable" @change="$refs.list.refetch()" />
</app-card>
</template>
<script>
// 组件
import AppList from '@/components/base/AppList.vue'
import AppCard from '@/components/base/AppCard.vue'
import AppUserSearch from '@/components/base/AppUserSearch.vue'
import AppArea from '@/components/base/AppArea.vue'
import CreateCustomer from '../components/CreateCustomer.vue'
// 接口
// import { getRoleList } from '../api'
import { getCustomerList } from '../api'
const sourceList = [
{ name: '公司资源', id: 1 },
{ name: '自己开拓', id: 2 },
{ name: '第三方介绍', id: 3 }
]
const typeList = [
{ name: '普通客户', id: 1 },
{ name: '重点客户', id: 2 }
]
export default {
components: { AppCard, AppList },
components: { AppUserSearch, AppArea, CreateCustomer },
data() {
return {}
return {
staffList: [
{ name: '员工1', id: '1' },
{ name: '员工2', id: '2' }
],
typeList: [
{ name: '普通客户', id: 1 },
{ name: '重点客户', id: 2 }
],
sourceList: [
{ name: '公司资源', id: 1 },
{ name: '自己开拓', id: 2 },
{ name: '第三方介绍', id: 3 }
],
projectList: [
{ name: '产业学员', id: 1 },
{ name: '1+x', id: 2 }
],
progressList: [
{ name: '待更进', id: 1 },
{ name: '更进中', id: 2 },
{ name: '待签约', id: 3 },
{ name: '已签约', id: 4 },
{ name: '已合作', id: 5 },
{ name: '已失效', id: 6 }
],
dialogVisable: false
}
},
computed: {
// 列表配置
tableOptions() {
return {
// remote: {
// httpRequest: getRoleList,
// params: { },
// },
remote: {
httpRequest: getCustomerList,
beforeRequest: this.beforeRequest,
params: {
name: '',
short_name: '',
source: '',
type: '',
region: '',
created_by: '',
project_tag: '',
project_status: '',
project_sso_id: '',
last_record_start_time: '',
last_record_end_time: '',
created_start_time: '',
created_end_time: ''
}
},
filters: [
{ prop: 'create_date', slots: 'filter-date', label: '创建时间:', class: 'filter-form-item' },
{ prop: 'follow_date', slots: 'filter-follow-date', label: '最近跟进时间:' },
{ prop: 'created_by', slots: 'filter-userSearch', label: '创建员工:' },
// {
// type: 'select',
// placeholder: '请选择创建员工',
// prop: 'creator',
// options: this.staffList,
// labelKey: 'name',
// valueKey: 'id',
// size: 'small',
// label: '创建员工:'
// },
{
type: 'input',
prop: 'name',
placeholder: '请输入活动名'
placeholder: '请输入客户名称',
options: this.staffList,
size: 'small',
label: '客户名称:'
},
{
type: 'select',
placeholder: '请选择客户分类',
prop: 'type',
options: typeList,
labelKey: 'name',
valueKey: 'id',
size: 'small',
label: '客户分类:'
},
{
type: 'select',
placeholder: '请选择客户来源',
prop: 'source',
options: sourceList,
labelKey: 'name',
valueKey: 'id',
size: 'small',
label: '客户来源:'
},
{
type: 'select',
placeholder: '请选择合作项目',
prop: 'project',
options: this.projectList,
labelKey: 'name',
valueKey: 'id',
size: 'small',
label: '合作项目:'
},
{ prop: 'date', slots: 'filter-date' }
{
type: 'select',
placeholder: '请选择项目进度',
prop: 'progress',
options: this.progressList,
labelKey: 'name',
valueKey: 'id',
size: 'small',
label: '项目进度:'
},
{
type: 'select',
placeholder: '请选择项目负责人',
prop: 'director',
options: [],
labelKey: 'name',
valueKey: 'id',
size: 'small',
label: '项目负责人:'
},
{ prop: 'region', slots: 'filter-region', label: '所在地区:' }
],
data: [
{
......@@ -70,20 +206,63 @@ export default {
columns: [
// { type: 'selection', minWidth: '40px' },
{ prop: 'name', label: '客户名称', minWidth: '120px' },
{ prop: 'source', label: '客户来源', minWidth: '80px' },
{ prop: 'category', label: '客户分类', minWidth: '150px' },
{ prop: 'address', label: '所在地区', minWidth: '150px' },
{ prop: 'time', label: '最近跟进时间', minWidth: '140px' },
{ prop: 'project', label: '合作项目', minWidth: '140px' },
{ prop: 'contacts', label: '联系人', minWidth: '140px' },
{ prop: 'creator', label: '创建员工', minWidth: '140px' },
{ prop: 'created_time', label: '创建时间', minWidth: '140px' },
{
prop: 'source',
label: '客户来源',
minWidth: '100px',
computed({ row }) {
const item = sourceList.find(it => it.id === row.source) || {}
return item.name
}
},
{
prop: 'type',
label: '客户分类',
minWidth: '120px',
computed({ row }) {
const item = typeList.find(it => it.id === row.type) || {}
return item.name
}
},
{ prop: 'region', label: '所在地区', minWidth: '150px' },
{ prop: 'last_record_time', label: '最近跟进时间', minWidth: '140px' },
{ prop: 'project_count', label: '合作项目', minWidth: '80px' },
{ prop: 'contact_count', label: '联系人', minWidth: '80px' },
{ prop: 'created_by.realname', label: '创建员工', minWidth: '140px' },
{ prop: 'created_at', label: '创建时间', minWidth: '140px' },
{ label: '操作', minWidth: '140px', slots: 'table-operate' }
]
}
}
},
methods: {
beforeRequest(params) {
const _params = Object.assign({}, params)
for (const key in _params) {
if (!_params[key] || _params.length === 0) {
delete _params[key]
}
}
if (params.create_date) {
delete _params.create_date
_params.created_start_time = params.create_date[0]
_params.created_end_time = params.create_date[1]
}
if (params.follow_date) {
delete _params.follow_date
_params.last_record_start_time = params.follow_date[0]
_params.last_record_end_time = params.follow_date[1]
}
if (params.region) {
if (params.region.length === 3) {
_params.region = _params.region.join('-')
} else {
delete _params.region
}
}
console.log(_params)
return _params
},
// 查看
handleDetails(row) {
console.log(row)
......@@ -106,4 +285,19 @@ export default {
</script>
<style lang="scss" scoped>
.customer ::v-deep .table-list-hd .el-date-editor--datetimerange.el-input__inner{
width: 280px;
padding:3px 0 3px 6px;
}
.customer ::v-deep .table-list-hd .el-input{
width: 280px;
min-width:160px;
}
.customer ::v-deep .table-list-hd .el-select{
width: 280px;
min-width:160px;
}
.customer ::v-deep .table-list-hd .el-form{
margin-right:-30px;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论