484 lines
11 KiB
Vue
484 lines
11 KiB
Vue
<template>
|
|
<uv-navbar :fixed="false" @leftClick="$onClickLeft" bgColor="#09b4f1">
|
|
<template v-slot:left>
|
|
<uv-icon name="arrow-left" size="19" color="#ffffff"></uv-icon>
|
|
</template>
|
|
<template v-slot:center>
|
|
<text style="color:#ffffff">{{title}}</text>
|
|
</template>
|
|
</uv-navbar>
|
|
<view class="container">
|
|
<view class="pb-2 flex px-5" style="background-color: #09b4f1;">
|
|
<uv-search placeholder="搜索客户名称" v-model="keyword" bgColor="#ffffff" :customStyle="customStyle"
|
|
:show-action="false" @change="onSearch"></uv-search>
|
|
<uv-icon name="http://sys.znkjfw.com/imgs/crmimages/screen.png" :size="26" @click="openSearch"></uv-icon>
|
|
</view>
|
|
<view class="bg-white">
|
|
<uv-tabs :list="list" @click="handleSelect" :scrollable="false"></uv-tabs>
|
|
</view>
|
|
<view class="wrap">
|
|
<scroll-view scroll-y class="sv" :style="{height:scrollHeight+'px'}" :scroll-top="scrollTop" lower-threshold="20"
|
|
@scroll="scroll" @scrolltolower="reachBottom">
|
|
<view class="page-box" @touchmove="handletouchstart" @touchend="handletouchend">
|
|
<block v-if="dataList.length > 0">
|
|
<view class="client" v-for="(items, index) in dataList" :key="index">
|
|
<view class="top">
|
|
<view class="left">
|
|
<view class="store uv-line-1">{{items.name}}</view>
|
|
</view>
|
|
<view class="flex" @click="onItem(items.id)">
|
|
<uv-text v-if="items.dealStatus === 1" color="#84bd00" suffixIcon="arrow-right"
|
|
iconStyle="font-size: 16px;color:#84bd00" text="成交"></uv-text>
|
|
<uv-text v-else color="#f9ae3d" suffixIcon="arrow-right" iconStyle="font-size: 16px;color:#f9ae3d"
|
|
text="未成交"></uv-text>
|
|
</view>
|
|
</view>
|
|
<!-- 标签 -->
|
|
<view class="tap" v-if="items.tags !='' ">
|
|
<uv-tag :text="item" size="min" v-for="(item,i) in items.tagsArr" :key="i" />
|
|
</view>
|
|
<view class="item">
|
|
<view class="content">
|
|
<view class="title uv-line-2">{{items.mobile ? items.mobile :items.telephone}}</view>
|
|
</view>
|
|
<view class="right">{{items.ownUserName}}</view>
|
|
</view>
|
|
<view class="bottom">
|
|
<view class="client_time" v-if="items.nextTime>0">下次跟进:{{timeFormats(items.nextTime)}}</view>
|
|
<view class="client_time" v-else>最后跟进:{{timeFormats(items.followTime)}}</view>
|
|
<view class="flex">
|
|
<view class="btn ml-1 entity" @click="follow(items.id,items.name)">跟进</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<uv-load-more :status="listStatus" />
|
|
</block>
|
|
<uv-empty text="暂无数据" v-else margin-top="100" mode="list"></uv-empty>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
<view class="floatBtn" :class="specClass" @click="onAdd">
|
|
<uv-icon class="pb-5" name="plus" size="20" color="#09b4f1"></uv-icon>添加客户
|
|
</view>
|
|
<uv-popup ref="popup" @change="change" mode="top" bgColor="" :customStyle="customStyle2" :overlay="true">
|
|
<view class="p-2">
|
|
<uv-form labelPosition="top" :model="model1" :rules="rules" ref="form" labelWidth="70">
|
|
<uv-form-item label="手机">
|
|
<uv-input v-model="mobile" placeholder="请输入手机">
|
|
</uv-input>
|
|
</uv-form-item>
|
|
<uv-form-item label="电话">
|
|
<uv-input v-model="phone" placeholder="请输入电话">
|
|
</uv-input>
|
|
</uv-form-item>
|
|
<uv-form-item label="成交状态" @click="showStatusSelect">
|
|
<uv-input v-model="dealStatusName" disabled disabledColor="#ffffff" placeholder="请选择状态">
|
|
<template v-slot:suffix>
|
|
<uv-icon name="arrow-right"></uv-icon>
|
|
</template>
|
|
</uv-input>
|
|
</uv-form-item>
|
|
<view class="flex" style="margin-top: 20rpx;">
|
|
<view class="flex-1" style="margin-right: 8rpx;">
|
|
<uv-button type="success" :plain="true" text="确定" @click="onSubmit"></uv-button>
|
|
</view>
|
|
<view class="flex-1" style="margin-left: 8rpx;">
|
|
<uv-button type="error" :plain="true" text="重置" @click="onReset"></uv-button>
|
|
</view>
|
|
</view>
|
|
</uv-form>
|
|
</view>
|
|
</uv-popup>
|
|
<uv-action-sheet ref="statusSelect" :actions="actions" title="请选择状态" @select="onStatusSelect">
|
|
</uv-action-sheet>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
ref,
|
|
computed
|
|
} from 'vue'
|
|
import {
|
|
onLoad,
|
|
onShow,
|
|
onReady
|
|
} from '@dcloudio/uni-app'
|
|
import {
|
|
getCustomerListPage
|
|
} from '@/api/customer'
|
|
import {
|
|
formatDateTime
|
|
} from '@/utils/util'
|
|
const title = ref('客户')
|
|
const keyword = ref('')
|
|
const mobile = ref('')
|
|
const phone = ref('')
|
|
const dealStatus = ref(-1)
|
|
const dealStatusName = ref('')
|
|
const scrollHeight = ref(0)
|
|
const pH = ref(0)
|
|
const scrollTop = ref(-1)
|
|
const specClass = ref('hide')
|
|
const oldScrollTop = ref(0)
|
|
const dataList = ref([])
|
|
const dx = ref(0)
|
|
const page = ref(1)
|
|
const pageSize = ref(10)
|
|
const lastPage = ref(false)
|
|
const listStatus = ref('loadmore')
|
|
const isRefresh = ref(false)
|
|
const relation = ref('my')
|
|
const list = ref(
|
|
[{
|
|
name: '我的客户',
|
|
value: 'my'
|
|
}, {
|
|
name: '下属客户',
|
|
value: 'sub'
|
|
}]
|
|
)
|
|
const actions = ref(
|
|
[{
|
|
name: '未成交',
|
|
value: 0
|
|
}, {
|
|
name: '成交',
|
|
value: 1
|
|
}]
|
|
)
|
|
|
|
defineExpose({
|
|
isRefresh
|
|
})
|
|
|
|
const customStyle = computed(() => {
|
|
return {
|
|
paddingLeft: '10rpx',
|
|
paddingRight: '120rpx'
|
|
}
|
|
})
|
|
const statusBarHeight = ref(0)
|
|
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight
|
|
const customStyle2 = computed(() => {
|
|
// return {
|
|
// marginTop: (uni.getSystemInfoSync().statusBarHeight + 40) + 'px',
|
|
// backgroundColor: '#ffffff'
|
|
// //top:'100px'
|
|
// }
|
|
return {
|
|
paddingTop: (uni.getSystemInfoSync().statusBarHeight + 40) + 'px',
|
|
paddingBottom: 15 + 'px',
|
|
backgroundColor: '#ffffff'
|
|
}
|
|
})
|
|
const popup = ref()
|
|
|
|
onReady(() => {
|
|
uni.getSystemInfo({
|
|
success(res) {
|
|
pH.value = res.windowHeight
|
|
let scrollH = uni.createSelectorQuery().select(".sv")
|
|
scrollH.boundingClientRect(data => {
|
|
let pH0 = pH.value
|
|
scrollHeight.value = pH0 - data.top - 5
|
|
}).exec()
|
|
}
|
|
})
|
|
})
|
|
|
|
onLoad((e) => {
|
|
getCustomerList();
|
|
})
|
|
|
|
onShow(() => {
|
|
if (isRefresh.value) {
|
|
isRefresh.value = false
|
|
page.value = 1
|
|
lastPage.value = false
|
|
scrollTop.value = 0
|
|
dataList.value = []
|
|
getCustomerList()
|
|
}
|
|
})
|
|
|
|
const openSearch = () => {
|
|
popup.value.open()
|
|
}
|
|
const statusSelect = ref()
|
|
const showStatusSelect = () => {
|
|
statusSelect.value.open()
|
|
}
|
|
const handleSelect = (key) => {
|
|
relation.value = key.value
|
|
getCustomerList()
|
|
}
|
|
const onStatusSelect = (val) => {
|
|
dealStatusName.value = val.name
|
|
dealStatus.value = val.value
|
|
}
|
|
|
|
const onReset = () => {
|
|
mobile.value = ''
|
|
phone.value = ''
|
|
dealStatus.value = undefined
|
|
dealStatusName.value = ''
|
|
page.value = 1
|
|
lastPage.value = false
|
|
getCustomerList()
|
|
}
|
|
const onSubmit = () => {
|
|
page.value = 1
|
|
lastPage.value = false
|
|
getCustomerList()
|
|
popup.value.close()
|
|
}
|
|
|
|
const handletouchstart = () => {
|
|
specClass.value = 'show'
|
|
}
|
|
const handletouchend = () => {
|
|
specClass.value = 'hide'
|
|
}
|
|
|
|
// 格式化时间
|
|
const timeFormats = (val) => {
|
|
if (val) {
|
|
return formatDateTime(val)
|
|
} else {
|
|
return '--'
|
|
}
|
|
}
|
|
// 页面数据
|
|
const getCustomerList = async (isNextPage, pages) => {
|
|
await getCustomerListPage({
|
|
pageNo: page.value,
|
|
pageSize: pageSize.value,
|
|
relation: relation.value,
|
|
name: keyword.value,
|
|
mobile: mobile.value,
|
|
phone: phone.value,
|
|
dealStatus: dealStatus.value >= 0 ? dealStatus.value : ''
|
|
}).then(res => {
|
|
res.list.forEach((item, index) => {
|
|
if (item.tags) {
|
|
item.tagsArr = item.tags.split(',')
|
|
}
|
|
})
|
|
if (res) {
|
|
// 不够一页
|
|
if (res.list.length < 10) {
|
|
listStatus.value = 'nomore'
|
|
}
|
|
// 最后一页
|
|
if (res.list.length == 0) {
|
|
lastPage.value = true
|
|
}
|
|
// 第二页开始
|
|
if (isNextPage) {
|
|
dataList.value = dataList.value.concat(res.list)
|
|
return
|
|
}
|
|
dataList.value = res.list
|
|
}
|
|
})
|
|
}
|
|
// scroll 滚动记录
|
|
const scroll = (e) => {
|
|
oldScrollTop.value = e.detail.scrollTop; // 必要
|
|
}
|
|
// 滚动到底部
|
|
const reachBottom = () => {
|
|
if (lastPage.value || listStatus.value == 'loading') return;
|
|
if (!lastPage.value) {
|
|
listStatus.value = 'loading';
|
|
setTimeout(() => {
|
|
listStatus.value = 'loadmore'
|
|
getCustomerList(true, ++page.value)
|
|
}, 500)
|
|
}
|
|
}
|
|
// 点击搜索
|
|
const onSearch = () => {
|
|
page.value = 1
|
|
lastPage.value = false
|
|
getCustomerList()
|
|
}
|
|
// 查看客户详情
|
|
const onItem = (id) => {
|
|
uni.navigateTo({
|
|
url: '/pages/components/pages/customer/customerDetails?id=' + id
|
|
});
|
|
}
|
|
// 跟进
|
|
const follow = (id, name) => {
|
|
uni.navigateTo({
|
|
url: '/pages/components/pages/customer/followUp?customerId=' + id + '&customerName=' + name
|
|
})
|
|
}
|
|
// 添加客户
|
|
const onAdd = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/components/pages/customer/add'
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.container {
|
|
background-color: #F7F7F7;
|
|
}
|
|
|
|
.page-box {
|
|
padding: 20rpx 20rpx 45rpx;
|
|
}
|
|
|
|
.client {
|
|
width: 710rpx;
|
|
background-color: #ffffff;
|
|
margin-bottom: 20rpx;
|
|
border-radius: 20rpx;
|
|
box-sizing: border-box;
|
|
padding: 20rpx;
|
|
font-size: 28rpx;
|
|
|
|
.top {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
|
|
.left {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.store {
|
|
max-width: 400rpx;
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
|
|
.tap {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
margin: 20rpx 0 0;
|
|
}
|
|
|
|
.item {
|
|
display: flex;
|
|
margin: 20rpx 0 0;
|
|
|
|
.content {
|
|
flex: 1;
|
|
|
|
.title {
|
|
font-size: 28rpx;
|
|
line-height: 50rpx;
|
|
}
|
|
|
|
.type {
|
|
margin: 10rpx 0;
|
|
font-size: 24rpx;
|
|
color: $uv-tips-color;
|
|
}
|
|
}
|
|
|
|
.right {
|
|
margin-left: 10rpx;
|
|
text-align: right;
|
|
|
|
.decimal {
|
|
font-size: 24rpx;
|
|
margin-top: 4rpx;
|
|
}
|
|
|
|
.number {
|
|
color: $uv-tips-color;
|
|
font-size: 24rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.bottom {
|
|
display: flex;
|
|
margin-top: 20rpx;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
.client_time {
|
|
color: #777;
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.btn {
|
|
line-height: 60rpx;
|
|
width: 160rpx;
|
|
border-radius: 5px;
|
|
font-size: 26rpx;
|
|
text-align: center;
|
|
color: $uv-primary-dark;
|
|
}
|
|
|
|
.entity {
|
|
color: #fff;
|
|
background-color: #09b4f1;
|
|
}
|
|
}
|
|
}
|
|
|
|
.wrap {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
}
|
|
|
|
.floatBtn {
|
|
font-size: 23rpx;
|
|
bottom: 100px;
|
|
right: 10px;
|
|
border-radius: 5000px;
|
|
z-index: 9;
|
|
opacity: 1;
|
|
width: 130rpx;
|
|
height: 130rpx;
|
|
position: fixed;
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
background-color: #fff;
|
|
color: #606266;
|
|
align-items: center;
|
|
transition: opacity 0.4s;
|
|
border: 1px solid #dcdfe6;
|
|
|
|
&.show {
|
|
animation: showLayer 0.2s linear both;
|
|
}
|
|
|
|
&.hide {
|
|
animation: hideLayer 0.5s linear both;
|
|
}
|
|
|
|
@keyframes showLayer {
|
|
0% {
|
|
transform: translateX(0%);
|
|
}
|
|
|
|
100% {
|
|
transform: translateX(120rpx);
|
|
}
|
|
}
|
|
|
|
@keyframes hideLayer {
|
|
0% {
|
|
transform: translateX(120rpx);
|
|
}
|
|
|
|
100% {
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
}
|
|
</style> |