crm-uniapp/pages/index/index.vue
2024-11-01 15:09:56 +08:00

475 lines
10 KiB
Vue

<template>
<uv-navbar leftIcon="" :safeAreaInsetTop="true" :fixed="false" bgColor="#09b4f1">
<template v-slot:center>
<view class="slot-wrap">
<uv-search placeholder="请输入搜索客户名称" v-model="keyword" bgColor="#ffffff" :showAction="false"
:customStyle="customStyle" @focus="onSearch"></uv-search>
</view>
</template>
</uv-navbar>
<view class="container">
<view class="top" style="background-color: #09b4f1;">
<view class="statusBar" :is-back="false" style="height: 30rpx;" ></view>
</view>
<!-- 待办 -->
<view class="notice">
<uv-grid :col="4" :border="false">
<uv-grid-item v-for="(item,index) in toolIcons" :key="index" @click="gopage(item.url)">
<uv-icon :name="item.icon" :size="30"></uv-icon>
<text class="p-1 font-size-sm">{{item.name}}</text>
</uv-grid-item>
</uv-grid>
</view>
<!-- 工具项 -->
<view class="region mt-3">
<view class="title flex">
<text>常用功能</text>
</view>
<uv-grid :col="4" :border="false" @click="onGrid" >
<uv-grid-item v-for="(item, index) in toolIcons2" :key="index" :customStyle="customStyle2" @click="item.name == '客户' ? gopage2(item.url) : gopage(item.url)">
<uv-icon :name="item.icon" :size="30" ></uv-icon>
<text class="p-1 font-size-sm">{{ item.name }}</text>
</uv-grid-item>
</uv-grid>
</view>
<view class="region mt-3" style="margin-top: 20rpx;">
<view class="title flex">
<text>数据简报</text>
</view>
<uv-grid :col="3" :border="false" @click="onGrid" >
<uv-grid-item v-for="(item, index) in toolIcons3" :key="index" :customStyle="customStyle2">
<text class="p-1 font-size-sm">{{ item.name }}</text>
<text class="p-1 font-size-sm">{{ item.count }}</text>
</uv-grid-item>
</uv-grid>
</view>
<view class="region mt-3" style="margin-top: 20rpx;">
<view class="title flex">
<text>业绩目标</text>
<view class="flex align-center">
<uv-switch v-model="isContract" size="18" inactiveColor="#5ac725" @change="changeChart"></uv-switch>
<view class="ml-1">
<uv-text size="14" text="合同" color="#3c9cff" v-if="isContract"></uv-text>
<uv-text size="14" text="回款" type="success" v-else></uv-text>
</view>
</view>
</view>
<uv-row>
<uv-col span="8">
<qiun-data-charts
type="gauge"
:opts="opts"
:chartData="chartData"
/>
</uv-col>
<uv-col span="4">
<view class="mb-4">
<view class="text-color-assist font-size-medium mb-2">目标金额</view>
<view>¥{{isContract ? chartCountData.contractMoney : chartCountData.receivablesMoney}}</view>
</view>
<view>
<view class="text-color-assist font-size-medium mb-2">完成金额</view>
<view>¥{{isContract ? chartCountData.contractSuccessMoney : chartCountData.receivablesSuccessMoney}}</view>
</view>
</uv-col>
</uv-row>
</view>
</view>
</template>
<script setup>
import {ref,computed} from 'vue'
import { onLoad,onShow} from '@dcloudio/uni-app'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import {
indexCount,
indexChartCount
} from '@/api/index'
const main = useMainStore()
const statusBarHeight = ref(0)
const rightSafeArea = ref(0)
statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight
const windowInfo = uni.getWindowInfo()
const { left } = uni.getMenuButtonBoundingClientRect()
rightSafeArea.value = windowInfo.windowWidth - left + 'px'
const customStyle = computed(() =>{
return {
//width:'100%'
// paddingLeft:'20rpx',
paddingRight: rightSafeArea.value
}
})
const customStyle2 = computed(() =>{
return {
paddingBottom:'40rpx',
// paddingRight:'180rpx'
}
})
const toolIcons = ref([
{
name: '公海客户',
icon: '/static/images/index002.png',
url: '/pages/components/pages/customer/open',
},
{
name: '线索',
icon: '/static/images/index003.png',
url: '/pages/components/pages/clues/index',
},
{
name: '跟进记录',
icon: '/static/images/index004.png',
url: '/pages/components/pages/record/index',
},
{
name: '合同',
icon: '/static/images/index006.png',
url: '/pages/components/pages/contract/index',
}
])
const toolIcons2 = ref([
{
name: '客户',
icon: '/static/images/1.png',
url: '/pages/customer/index',
},
{
name: '商机',
icon: '/static/images/2.png',
url: '/pages/components/pages/business/index',
},
{
name: '线索池',
icon: '/static/images/3.png',
url: '/pages/components/pages/clues/open',
},
{
name: '联系人',
icon: '/static/images/4.png',
url: '/pages/components/pages/contacts/index',
},
{
name: '回款',
icon: '/static/images/5.png',
url: '/pages/components/pages/receivables/index',
},
{
name: '查重',
icon: '/static/images/6.png',
url: '/pages/components/pages/customer/repeat',
},
{
name: '发票',
icon: '/static/images/7.png',
url: '/pages/components/pages/invoice/index',
},
{
name: '产品',
icon: '/static/images/8.png',
url: '/pages/components/pages/product/index',
},
])
const countData = ref({})
const toolIcons3 = ref([
{
name: '新增商机',
count: 0,
},
{
name: '新增线索',
count: 0,
},
{
name: '新增客户',
count: 0,
},
{
name: '新增跟进',
count: 0,
},
{
name: '新增合同',
count: 0,
},
{
name: '合同金额',
count: 0,
},
{
name: '回款金额',
count: 0,
},
{
name: '新增联系人',
count: 0,
},
{
name: '客户成交量',
count: 0,
},
{
name: '客户未成交量',
count: 0,
},
{
name: '商机成交量',
count: 0,
},
{
name: '商机未成交量',
count: 0,
}
])
const chartData = ref(
{
categories: [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],
series: [
{
name: "完成率",
data: 0.2
}
]
}
)
const opts = ref(
{
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: undefined,
title: {
name: "完成率",
fontSize: 25,
color: "#2fc25b",
offsetY: 0
},
subtitle: {
name: "200%",
fontSize: 15,
color: "#1890ff",
offsetY: 0
},
extra: {
gauge: {
type: "progress",
width: 15,
labelColor: "#666666",
startAngle: 0.75,
endAngle: 0.25,
startNumber: 0,
endNumber: 100,
labelFormat: "",
splitLine: {
fixRadius: -10,
splitNumber: 10,
width: 15,
color: "#FFFFFF",
childNumber: 5,
childWidth: 12
},
pointer: {
width: 24,
color: "auto"
}
}
}
}
)
const isContract = ref(true)
const chartCountData = ref({})
onShow(()=>{
getData()
getChart()
})
const getChart = async() => {
let data = await indexChartCount({type:2,year:2024,month:0})
chartCountData.value = data
let resData = data.contractPer
chartData.value.series[0].data = resData > 100 ? 1 : resData/100
opts.value.subtitle.name = resData+"%"
}
const changeChart = () => {
let resData = isContract.value ? chartCountData.value.contractPer : chartCountData.value.receivablesPer
chartData.value.series[0].data = resData > 100 ? 1 : resData/100
opts.value.subtitle.name = resData+"%"
}
const getData = async() => {
let data = await indexCount()
let brieCount= data.brieCountVO
toolIcons3.value[0].count = brieCount.count01
toolIcons3.value[1].count = brieCount.count02
toolIcons3.value[2].count = brieCount.count03
toolIcons3.value[3].count = brieCount.count04
toolIcons3.value[4].count = brieCount.count05
toolIcons3.value[5].count = brieCount.count06
toolIcons3.value[6].count = brieCount.count07
toolIcons3.value[7].count = brieCount.count08
toolIcons3.value[8].count = brieCount.count09
toolIcons3.value[9].count = brieCount.count10
toolIcons3.value[10].count = brieCount.count11
toolIcons3.value[11].count = brieCount.count12
main.SET_INDEX_COUNT(data)
let count = brieCount.count13+data.contractCheckCount + data.invoiceCheckCount + data.receivablesCheckCount + data.followBusinessCount + data.followCluesCount + data.followCustomerCount
//let str = count > 0 ? count + '' : ''
if(count > 0){
uni.setTabBarBadge({
index: 2,
text: count + ''
})
}
}
const onSearch = () => {
gopage2('/pages/customer/index')
}
const gopage = (url) => {
uni.navigateTo({
url
})
}
const gopage2 = (url) =>{
uni.switchTab({
url
})
}
</script>
<style lang="scss" scoped>
.container {
background-color: #F7F7F7 !important;
padding-bottom: 50px;
min-height: 100vh;
}
.top {
height: 110rpx;
/* #ifdef H5 */
height: 360rpx;
/* #endif */
color: #fff;
}
.notice {
margin: -56px 8px 10px 8px;
left: 0;
right: 0;
background-color: #fff;
border-radius: 10px;
padding: 15px 0px;
.title {
padding: 20rpx;
font-size: 30rpx;
font-weight: 500;
justify-content: space-between;
}
}
.region {
background-color: #fff;
border-radius: 12px;
margin: 0 10px;
padding: 8px 5px;
.title {
padding: 28rpx 20rpx;
font-size: 30rpx;
font-weight: 500;
justify-content: space-between;
}
.plus {
background-color: #FFF0ED;
border-radius: 10rpx;
padding: 15rpx;
}
.nape {
width: 48%;
border-radius: 8px;
background-color: #FBFBFB;
padding: 30rpx 20rpx 30rpx 35rpx;
margin-bottom: 15rpx;
&:nth-child(2n+1){
margin-right: 4%;
}
}
}
.item-padding {
padding: 45rpx 0;
}
.gray {
color: #BFBFBF;
}
.slot-wrap {
display: flex;
align-items: center;
padding: 0 30rpx;
flex:1
}
.statusBar {
position: relative;
}
.arrow-icon {
position: absolute;
bottom: 16px;
left: 10px;
}
.charts-box{
.charts {
width: 100%;
height:300px;
}
.introduce {
justify-content: space-between;
padding: 45rpx 12px;
.text {
font-size: 30rpx;
font-weight: 500;
}
.screen {
font-size: 30rpx;
font-weight: 500;
background-color: #fff;
padding: 10rpx 32rpx;
border-radius: 60rpx;
}
}
.target {
margin-top: -60rpx;
justify-content: space-around;
.text {
background-color: #D7D7D7;
font-size: 25rpx;
padding: 10rpx 20rpx;
border-radius: 20rpx;
}
}
}
</style>