Przeglądaj źródła

人员产品目标

xiaohaizhao 3 miesięcy temu
rodzic
commit
7bca3b65dc
37 zmienionych plików z 1083 dodań i 20 usunięć
  1. 3 1
      app.json
  2. 2 2
      components/filtrate/filtrate.wxml
  3. 1 1
      portrayal/modules/filtrate.wxml
  4. 9 2
      project.private.config.json
  5. 28 0
      salesPanel/agencyTarget/index.js
  6. 6 0
      salesPanel/agencyTarget/index.json
  7. 0 0
      salesPanel/agencyTarget/index.scss
  8. 3 0
      salesPanel/agencyTarget/index.wxml
  9. 1 1
      salesPanel/agencyTarget/productType/index.js
  10. 0 0
      salesPanel/agencyTarget/productType/index.json
  11. 0 0
      salesPanel/agencyTarget/productType/index.scss
  12. 0 0
      salesPanel/agencyTarget/productType/index.wxml
  13. 1 1
      salesPanel/customerBlance/index.wxml
  14. 2 2
      salesPanel/dataOverview/Client/dataOverview.wxml
  15. 2 2
      salesPanel/dataOverview/Clue/dataOverview.wxml
  16. 2 2
      salesPanel/dataOverview/Costs/dataOverview.wxml
  17. 2 2
      salesPanel/dataOverview/Project/dataOverview.wxml
  18. 27 0
      salesPanel/headOptionBox/index.js
  19. 5 0
      salesPanel/headOptionBox/index.json
  20. 126 0
      salesPanel/headOptionBox/index.scss
  21. 14 0
      salesPanel/headOptionBox/index.wxml
  22. 28 0
      salesPanel/hospitalTarget/index.js
  23. 6 0
      salesPanel/hospitalTarget/index.json
  24. 0 0
      salesPanel/hospitalTarget/index.scss
  25. 3 0
      salesPanel/hospitalTarget/index.wxml
  26. 175 0
      salesPanel/hospitalTarget/productType/index.js
  27. 6 0
      salesPanel/hospitalTarget/productType/index.json
  28. 126 0
      salesPanel/hospitalTarget/productType/index.scss
  29. 71 0
      salesPanel/hospitalTarget/productType/index.wxml
  30. 1 1
      salesPanel/personTarget/index.js
  31. 2 2
      salesPanel/personTarget/index.json
  32. 1 1
      salesPanel/personTarget/index.wxml
  33. 210 0
      salesPanel/personTarget/productType/index.js
  34. 6 0
      salesPanel/personTarget/productType/index.json
  35. 126 0
      salesPanel/personTarget/productType/index.scss
  36. 80 0
      salesPanel/personTarget/productType/index.wxml
  37. 8 0
      utils/work/apps.js

+ 3 - 1
app.json

@@ -112,7 +112,9 @@
                 "dataOverview/OverviewAndDetails/Costs",
                 "dataOverview/Costs/SPMEDetail",
                 "dataOverview/Project/projectList",
-                "personTarget/index"
+                "personTarget/index",
+                "hospitalTarget/index",
+                "agencyTarget/index"
             ]
         }
     ],

+ 2 - 2
components/filtrate/filtrate.wxml

@@ -6,9 +6,9 @@
         <view style='color:#3874F6;'>{{showText}}</view>
         <block wx:if='{{isEmpty}}'>
             <view wx:if="{{showText != '全部'}}" class="iconfont icon-quxiao" catchtap="clearResults" />
-            <view wx:else class="iconfont icon-xiangxiazhankai" />
+            <view wx:else class="iconfont icon-webxialaxuanxiangjiantou" />
         </block>
-        <view wx:else class="iconfont icon-xiangxiazhankai" />
+        <view wx:else class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <van-action-sheet show="{{  actionShow }}" actions="{{ actions }}" bind:select='onSelect' bind:cancel='onCancel'

+ 1 - 1
portrayal/modules/filtrate.wxml

@@ -4,7 +4,7 @@
     </view>
     <view class="right">
         <view style='color:#3874F6;'>{{language[showText]||showText}}</view>
-        <view class="iconfont icon-xiangxiazhankai" />
+        <view class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <van-action-sheet show="{{  actionShow }}" actions="{{ actions }}" bind:select='onSelect' bind:cancel='onCancel' bind:click-overlay='onCancel' cancel-text="{{language['取消']||'取消'}}" />

+ 9 - 2
project.private.config.json

@@ -11,12 +11,19 @@
         "miniprogram": {
             "list": [
                 {
-                    "name": "人员目标",
-                    "pathName": "salesPanel/personTarget/index",
+                    "name": "医院目标",
+                    "pathName": "salesPanel/hospitalTarget/index",
                     "query": "",
                     "scene": null,
                     "launchMode": "default"
                 },
+                {
+                    "name": "人员目标",
+                    "pathName": "salesPanel/personTarget/index",
+                    "query": "",
+                    "launchMode": "default",
+                    "scene": null
+                },
                 {
                     "name": "/prsx/target/index",
                     "pathName": "/prsx/target/index",

+ 28 - 0
salesPanel/agencyTarget/index.js

@@ -0,0 +1,28 @@
+Page({
+    data: {
+        tabsList: [{
+            label: "产品类别",
+            model: "#productType"
+        }],
+        tabsActive: 0,
+    },
+    onLoad(options) {
+        this.partialRenewal();
+    },
+    tabsChange({
+        detail
+    }) {
+        this.setData({
+            tabsActive: detail
+        });
+        this.partialRenewal();
+    },
+    //局部数据更新 tabs
+    partialRenewal() {
+        const model = this.data.tabsList[this.data.tabsActive].model;
+        if (model) {
+            const Component = this.selectComponent(model);
+            Component.getList(true);
+        }
+    },
+})

+ 6 - 0
salesPanel/agencyTarget/index.json

@@ -0,0 +1,6 @@
+{
+    "usingComponents": {
+        "productType":"./productType/index"
+    },
+    "navigationBarTitleText": "医院目标"
+}

+ 0 - 0
salesPanel/agencyTarget/index.scss


+ 3 - 0
salesPanel/agencyTarget/index.wxml

@@ -0,0 +1,3 @@
+<Yl_FunTabs id='Yl_FunTabs' safety='{{false}}' list='{{tabsList}}' mode='buts' active='{{tabsActive}}' bind:onChenge="tabsChange">
+    <productType slot='产品类别' id='productType' />
+</Yl_FunTabs>

+ 1 - 1
salesPanel/personTarget/target/index.js → salesPanel/agencyTarget/productType/index.js

@@ -22,7 +22,7 @@ Component({
         content: {
             year: new Date().getFullYear(),
             sa_saleareaid: 0,
-            "type": 1, //1:人员,2:医院,3:经销商
+            "type": 2, //1:人员,2:医院,3:经销商
             "month_start": 1,
             "month_end": 12,
             "userid": wx.getStorageSync('userMsg').userid,

+ 0 - 0
salesPanel/personTarget/target/index.json → salesPanel/agencyTarget/productType/index.json


+ 0 - 0
salesPanel/personTarget/target/index.scss → salesPanel/agencyTarget/productType/index.scss


+ 0 - 0
salesPanel/personTarget/target/index.wxml → salesPanel/agencyTarget/productType/index.wxml


+ 1 - 1
salesPanel/customerBlance/index.wxml

@@ -14,7 +14,7 @@
 	<view class="detail">
 		<view class="but" hover-class="navigator-hover" bind:tap="toDetail">
 			{{language['账户余额明细']||'账户余额明细'}}
-			<view class="iconfont icon-xiangxiazhankai" />
+			<view class="iconfont icon-webxialaxuanxiangjiantou" />
 		</view>
 	</view>
 	<view class="chart"></view>

+ 2 - 2
salesPanel/dataOverview/Client/dataOverview.wxml

@@ -2,14 +2,14 @@
     <view class="left">{{language[content.username]||content.username}}_{{language['数据概况']||'数据概况'}}</view>
     <view class="right" bind:tap="openDateType">
         {{language[content.dateType]||content.dateType}}
-        <text class="iconfont icon-xiangxiazhankai" />
+        <text class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <view class="global-card list">
     <view class="item" hover-class="{{item.link?'navigator-hover':''}}" wx:for="{{list}}" wx:key="title" bind:tap="toDetail" data-item="{{item}}">
         <view class="value">{{item.value}}</view>
         <view class="title">{{language[item.title]||item.title}} <text catch:tap="showTips" wx:if="{{item.tips}}" data-tips="{{item.tips}}" class="iconfont icon-wenhao" /></view>
-        <view wx:if="{{item.link}}" class="iconfont icon-xiangxiazhankai detail" />
+        <view wx:if="{{item.link}}" class="iconfont icon-webxialaxuanxiangjiantou detail" />
     </view>
 </view>
 <My_empty wx:if="{{list.length==0}}" />

+ 2 - 2
salesPanel/dataOverview/Clue/dataOverview.wxml

@@ -2,14 +2,14 @@
     <view class="left">{{language[content.username]||content.username}}_{{language['数据概况']||'数据概况'}}</view>
     <view class="right" bind:tap="openDateType">
         {{language[content.dateType]||content.dateType}}
-        <text class="iconfont icon-xiangxiazhankai" />
+        <text class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <view class="global-card list">
     <view class="item" hover-class="{{item.link?'navigator-hover':''}}" wx:for="{{list}}" wx:key="title" bind:tap="toDetail" data-item="{{item}}">
         <view class="value">{{item.value}}</view>
         <view class="title">{{language[item.title]||item.title}} <text catch:tap="showTips" wx:if="{{item.tips}}" data-tips="{{item.tips}}" class="iconfont icon-wenhao" /></view>
-        <view wx:if="{{item.link}}" class="iconfont icon-xiangxiazhankai detail" />
+        <view wx:if="{{item.link}}" class="iconfont icon-webxialaxuanxiangjiantou detail" />
     </view>
 </view>
 <My_empty wx:if="{{list.length==0}}" />

+ 2 - 2
salesPanel/dataOverview/Costs/dataOverview.wxml

@@ -2,14 +2,14 @@
     <view class="left">{{language[content.username]||content.username}}_{{language['数据概况']||'数据概况'}}</view>
     <view class="right" bind:tap="openDateType">
         {{language[content.dateType]||content.dateType}}
-        <text class="iconfont icon-xiangxiazhankai" />
+        <text class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <view class="global-card list">
     <view class="item" hover-class="{{item.link?'navigator-hover':''}}" wx:for="{{list}}" wx:key="title" bind:tap="toDetail" data-item="{{item}}">
         <view class="value">{{item.value}}</view>
         <view class="title">{{language[item.title]||item.title}} <text catch:tap="showTips" wx:if="{{item.tips}}" data-tips="{{item.tips}}" class="iconfont icon-wenhao" /></view>
-        <view wx:if="{{item.link}}" class="iconfont icon-xiangxiazhankai detail" />
+        <view wx:if="{{item.link}}" class="iconfont icon-webxialaxuanxiangjiantou detail" />
     </view>
 </view>
 <My_empty wx:if="{{list.length==0}}" />

+ 2 - 2
salesPanel/dataOverview/Project/dataOverview.wxml

@@ -2,14 +2,14 @@
     <view class="left">{{language[content.username]||content.username}}_{{language['数据概况']||'数据概况'}}</view>
     <view class="right" bind:tap="openDateType">
         {{language[content.dateType]||content.dateType}}
-        <text class="iconfont icon-xiangxiazhankai" />
+        <text class="iconfont icon-webxialaxuanxiangjiantou" />
     </view>
 </view>
 <view class="global-card list">
     <view class="item" hover-class="{{item.link?'navigator-hover':''}}" wx:for="{{list}}" wx:key="title" bind:tap="toDetail" data-item="{{item}}">
         <view class="value">{{item.value}}</view>
         <view class="title">{{language[item.title]||item.title}} <text catch:tap="showTips" wx:if="{{item.tips}}" data-tips="{{item.tips}}" class="iconfont icon-wenhao" /></view>
-        <view wx:if="{{item.link}}" class="iconfont icon-xiangxiazhankai detail" />
+        <view wx:if="{{item.link}}" class="iconfont icon-webxialaxuanxiangjiantou detail" />
     </view>
 </view>
 <My_empty wx:if="{{list.length==0}}" />

+ 27 - 0
salesPanel/headOptionBox/index.js

@@ -0,0 +1,27 @@
+Component({
+    options: {
+        addGlobalClass: true
+    },
+    properties: {
+        iconName: {
+            type: String,
+            value: "icon-feiyongleixing"
+        },
+        title: {
+            type: String,
+        },
+        showText: {
+            type: String,
+        },
+        isEmpty: {
+            type: Boolean,
+            value: false
+        },
+        placeholder: {
+            type: String,
+            value: "请选择"
+        }
+    },
+    data: {},
+    methods: {}
+})

+ 5 - 0
salesPanel/headOptionBox/index.json

@@ -0,0 +1,5 @@
+{
+    "component": true,
+    "usingComponents": {
+    }
+}

+ 126 - 0
salesPanel/headOptionBox/index.scss

@@ -0,0 +1,126 @@
+.detePickerHeader {
+	position: relative;
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	width: 750rpx;
+	height: 100rpx;
+	padding: 0 30rpx;
+	box-sizing: border-box;
+
+	text {
+		font-size: 28rpx;
+		font-family: PingFang SC-Regular, PingFang SC;
+		color: var(--assist);
+	}
+
+	.type {
+		display: flex;
+		width: 384rpx;
+		height: 80rpx;
+		border: 1rpx solid var(--assist);
+		box-sizing: border-box;
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		border-radius: 4rpx;
+		overflow: hidden;
+
+		.option {
+			height: 100%;
+			width: 50%;
+			padding: 10rpx 0 0 20rpx;
+			box-sizing: border-box;
+			font-size: 20rpx;
+			font-family: PingFang SC-Regular, PingFang SC;
+			color: var(--assist);
+
+			.time {
+				margin-top: 4rpx;
+			}
+		}
+
+		.active-op {
+			background-color: var(--assist);
+			color: #fff;
+		}
+	}
+}
+
+.time-range {
+	display: flex;
+
+	.default {
+		font-family: PingFang SC, PingFang SC;
+		font-size: 24rpx;
+		color: #999999;
+	}
+
+	.left {
+		display: flex;
+		align-items: center;
+		flex-shrink: 0;
+
+		.iconfont {
+			font-family: PingFang SC, PingFang SC;
+			font-size: 24rpx;
+			color: #333333;
+		}
+
+
+		.iconfont::before {
+			font-size: 28rpx;
+			margin-right: 20rpx;
+		}
+
+		.dateType {
+			min-width: 128rpx;
+			font-family: PingFang SC, PingFang SC;
+			font-size: 24rpx;
+			color: #999999;
+			text-align: center;
+		}
+
+		.blue {
+			color: #3874F6;
+		}
+	}
+
+	.right {
+		display: flex;
+		flex: 1;
+		width: 0;
+		flex-shrink: 0;
+		justify-content: space-between;
+
+		.iconfont {
+			transform: rotate(-90deg);
+			color: #999999;
+		}
+
+		.range {
+			display: flex;
+			align-items: center;
+			font-family: PingFang SC, PingFang SC;
+			font-size: 24rpx;
+			color: #3874F6;
+
+			.middle {
+				color: #999999;
+				padding: 0 15rpx;
+			}
+		}
+	}
+
+}
+
+.right {
+	margin-left: 20rpx;
+	padding-left: 20rpx;
+
+	font-family: PingFang SC, PingFang SC;
+	font-size: 24rpx;
+	color: #999999;
+	text-align: center;
+}

+ 14 - 0
salesPanel/headOptionBox/index.wxml

@@ -0,0 +1,14 @@
+<view class="global-card time-range" style='margin-bottom:0;' bindtap="openActionSheet">
+    <view class='left'>
+        <view class="iconfont {{iconName}}">{{title}}</view>
+    </view>
+    <view class="right">
+        <view wx:if="{{showText}}" style='color:#3874F6;'>{{showText}}</view>
+        <view wx:else>{{placeholder}}</view>
+        <block wx:if='{{isEmpty}}'>
+            <view wx:if="{{showText != '全部'}}" class="iconfont icon-quxiao" catchtap="clearResults" />
+            <view wx:else class="iconfont icon-webxialaxuanxiangjiantou" />
+        </block>
+        <view wx:else class="iconfont icon-webxialaxuanxiangjiantou" />
+    </view>
+</view>

+ 28 - 0
salesPanel/hospitalTarget/index.js

@@ -0,0 +1,28 @@
+Page({
+    data: {
+        tabsList: [{
+            label: "产品类别",
+            model: "#productType"
+        }],
+        tabsActive: 0,
+    },
+    onLoad(options) {
+        this.partialRenewal();
+    },
+    tabsChange({
+        detail
+    }) {
+        this.setData({
+            tabsActive: detail
+        });
+        this.partialRenewal();
+    },
+    //局部数据更新 tabs
+    partialRenewal() {
+        const model = this.data.tabsList[this.data.tabsActive].model;
+        if (model) {
+            const Component = this.selectComponent(model);
+            Component.getList(true);
+        }
+    },
+})

+ 6 - 0
salesPanel/hospitalTarget/index.json

@@ -0,0 +1,6 @@
+{
+    "usingComponents": {
+        "productType":"./productType/index"
+    },
+    "navigationBarTitleText": "医院目标"
+}

+ 0 - 0
salesPanel/hospitalTarget/index.scss


+ 3 - 0
salesPanel/hospitalTarget/index.wxml

@@ -0,0 +1,3 @@
+<Yl_FunTabs id='Yl_FunTabs' safety='{{false}}' list='{{tabsList}}' mode='buts' active='{{tabsActive}}' bind:onChenge="tabsChange">
+    <productType slot='产品类别' id='productType' />
+</Yl_FunTabs>

+ 175 - 0
salesPanel/hospitalTarget/productType/index.js

@@ -0,0 +1,175 @@
+const _Http = getApp().globalData.http,
+    currency = require("../../../utils/currency"),
+    CNY = (value, symbol = "¥", precision = 2) => currency(value, {
+        symbol,
+        precision
+    }).format();
+
+Component({
+    properties: {
+
+    },
+    options: {
+        addGlobalClass: true
+    },
+    lifetimes: {
+        attached: function () {}
+    },
+    data: {
+        tabs: [],
+        salesShow: false,
+        showType: 0,
+        content: {
+            year: new Date().getFullYear(),
+            sa_saleareaid: 0,
+            "type": 2, //1:人员,2:医院,3:经销商
+            "month_start": 1,
+            "month_end": 12,
+            "userid": wx.getStorageSync('userMsg').userid,
+            "sa_customersid": 0,
+            "sa_agentsid": 0,
+            where: {}
+        },
+        areaList: [],
+        active: "",
+        details: {}
+    },
+    methods: {
+        async getList(init = false) {
+            if (init) this.getData()
+        },
+        //查询当前账号的营销区域
+        getArea() {
+            return new Promise((resolve, reject) => {
+                _Http.basic({
+                    "content": {},
+                    "id": 2026010513574702
+                }).then(res => {
+                    console.log("营销区域", res)
+                    const areaList = res.code != 1 ? [] : res.data.map(v => {
+                        v.value = v.areaname
+                        return v
+                    });
+                    resolve(areaList);
+                    this.setData({
+                        areaList,
+                        active: areaList[0].areaname
+                    })
+                })
+            })
+        },
+        changeArea({
+            detail
+        }) {
+            this.setData({
+                active: detail,
+                "content.sa_saleareaid": this.data.areaList.find(v => v.areaname == 'detail').sa_saleareaid
+            });
+            this.getData();
+        },
+        async getData() {
+            let content = this.data.content
+            if (content.sa_saleareaid == 0) await this.getArea().then(res => {
+                if (res.length > 0) {
+                    content.sa_saleareaid = res[0].sa_saleareaid
+                }
+            })
+            _Http.basic({
+                "id": 2026010714131502,
+                content
+            }).then(res => {
+                console.log("产品目标", res)
+                if (res.code != 1) return wx.showToast({
+                    title: res.msg,
+                    icon: "none"
+                });
+                let tabs = [],
+                    details = {};
+
+                res.data.forEach((item, index) => {
+                    tabs.push({
+                        name: item.itemclassname,
+                        index: index,
+                        key: 'm_'
+                    })
+                    item.m_balanceamount = CNY(item.m_balanceamount)
+                    item.m_saleamount = CNY(item.m_saleamount)
+                    item.m_targetamount = CNY(item.m_targetamount)
+                    details[item.itemclassname] = item;
+                })
+
+
+                this.setData({
+                    tabs,
+                    details
+                })
+            })
+        },
+        changeDate({
+            detail
+        }) {
+            this.setData({
+                "content.year": detail.year,
+                "content.month_start": detail.startMonth,
+                "content.month_end": detail.endMonth,
+            })
+            this.getData()
+        },
+        changeType(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            this.setData({
+                showType: item.index
+            })
+        },
+        // 获取营销类别
+        getSales() {
+            _Http.basic({
+                "content": {},
+                "id": 2025123014533002
+            }).then(res => {
+                console.log("营销类别", res)
+                const tabs = res.code != 1 ? [] : res.data.map((v, i) => {
+                    return {
+                        name: v,
+                        index: i,
+                        key: 'm_'
+                    }
+                });
+                this.setData({
+                    tabs
+                })
+                this.closeSelect()
+            })
+        },
+        selectSale() {
+            this.setData({
+                salesShow: true
+            })
+        },
+        onSelect(e) {
+            this.setData({
+                showType: e.detail.index
+            })
+            this.closeSelect();
+        },
+        swiperChange(e) {
+            this.setData({
+                showType: e.detail.current
+            })
+            this.closeSelect()
+        },
+        closeSelect() {
+            this.setData({
+                salesShow: false
+            });
+            this.setData({
+                tabs: this.data.tabs.map(v => {
+                    v.color = v.index == this.data.showType ? '#3874F6' : ''
+                    return v
+                })
+            })
+        },
+    }
+})

+ 6 - 0
salesPanel/hospitalTarget/productType/index.json

@@ -0,0 +1,6 @@
+{
+    "component": true,
+    "usingComponents": {
+        "headOptionBox": "../../headOptionBox/index"
+    }
+}

+ 126 - 0
salesPanel/hospitalTarget/productType/index.scss

@@ -0,0 +1,126 @@
+page {
+    width: 100vw;
+    overflow: hidden;
+}
+
+.head {
+    display: flex;
+    margin-bottom: 30rpx;
+
+    .item {
+        font-weight: bold;
+    }
+}
+
+.chart {
+    margin: 0 auto;
+    width: 280rpx;
+    flex-shrink: 0;
+    margin-bottom: 20rpx;
+
+    .circle {
+        width: 280rpx;
+        height: 280rpx;
+        position: relative;
+        border-radius: 50%;
+        box-shadow: inset 0 0 0 20rpx var(--assist);
+
+        .ab {
+            position: absolute;
+            left: 0;
+            right: 0;
+            top: 0;
+            bottom: 0;
+            margin: auto;
+        }
+
+        &_left {
+            border: 20rpx solid #EBEEF5;
+            border-radius: 50%;
+            clip: rect(0, 140rpx, 280rpx, 0);
+        }
+
+        &_right {
+            border: 20rpx solid #EBEEF5;
+            border-radius: 50%;
+            clip: rect(0, 280rpx, 280rpx, 140rpx);
+        }
+
+        &_text {
+            height: 100%;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            font-size: 32rpx;
+
+            .value {
+                font-family: Microsoft YaHei, Microsoft YaHei;
+                font-weight: bold;
+                font-size: 32rpx;
+                color: #333333;
+                margin-top: 12rpx;
+            }
+
+            .name {
+                font-family: Microsoft YaHei, Microsoft YaHei;
+                color: #999999;
+                margin-top: 16rpx;
+            }
+        }
+    }
+}
+
+.card {
+    width: 100%;
+    border-radius: 20rpx;
+    border: 1rpx solid #E0E0E0;
+    padding: 20rpx 40rpx;
+    margin-top: 20rpx;
+
+    .title {
+        line-height: 32rpx;
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #999999;
+    }
+
+    .price {
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #3685FC;
+        margin-top: 10rpx;
+
+        text {
+            font-size: 40rpx;
+            margin-right: 6rpx;
+        }
+    }
+
+    .row {
+        line-height: 32rpx;
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #999999;
+        margin-top: 6rpx;
+
+        .increase,
+        .decrease {
+            display: inline-block;
+            width: 0;
+            height: 0;
+            border-left: 8rpx solid transparent;
+            border-right: 8rpx solid transparent;
+            margin-left: 10rpx;
+        }
+
+        .increase {
+            border-bottom: 14rpx solid #009966;
+        }
+
+        .decrease {
+            border-top: 14rpx solid #EF0606;
+        }
+    }
+
+}

+ 71 - 0
salesPanel/hospitalTarget/productType/index.wxml

@@ -0,0 +1,71 @@
+<view style="height: 10rpx;"></view>
+<headOptionBox iconName='icon-bumen' title='营销区域' />
+<viewDate iconName='icon-shijian1' type='sameYear' fields='year' value='{{content.year}}' startMonth="{{content.month_start}}" endMonth="{{content.month_end}}" title='时间范围' bind:onChange='changeDate' />
+<view style="height: 20rpx;"></view>
+<view class="global-card" style="overflow: hidden;">
+
+	<view class="head">
+		<view class="item" catch:tap="selectSale">{{tabs[showType].name}}<text class="iconfont icon-webxialaxuanxiangjiantou"></text></view>
+	</view>
+	<van-action-sheet show="{{  salesShow }}" actions="{{ tabs }}" bind:select='onSelect' bind:cancel='closeSelect' bind:click-overlay='closeSelect' cancel-text="取消" />
+
+	<swiper current="{{showType}}" circular style="height: 760rpx;" bindchange='swiperChange'>
+		<swiper-item wx:for="{{tabs}}" wx:key="name">
+			<view class="chart">
+				<view class="circle">
+					<view class="circle_left ab" style="{{render.leftRate(details[tabs[showType].name][item.key +'rate_achieve'])}}" />
+					<view class="circle_right ab" style="{{render.rightRate(details[tabs[showType].name][item.key +'rate_achieve'])}}" />
+					<view class="circle_text">
+						<text class="name">目标达成率</text>
+						<text class="value">{{details[tabs[showType].name][item.key + 'rate_achieve' ]}}%</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="card">
+				<view class="title">销售额</view>
+				<view class="price">
+					<text>{{details[tabs[showType].name][item.key + 'saleamount' ]}}</text>
+				</view>
+				<view class="row">
+					同比:{{details[tabs[showType].name][item.key + 'rate_yoy' ]}}%
+					<view wx:if="{{details[tabs[showType].name][item.key  + 'rate_yoy'] != 0}}" class="{{details[tabs[showType].name][item.key + 'rate_yoy']>=0?'increase':'decrease'}}" />
+				</view>
+				<view class="row">
+					环比:{{details[tabs[showType].name][item.key + 'rate_mom' ]}}%
+					<view wx:if="{{details[tabs[showType].name][item.key + 'rate_mom'] != 0}}" class="{{details[tabs[showType].name][item.key + 'rate_mom']>=0?'increase':'decrease'}}" />
+				</view>
+			</view>
+
+			<view class="card">
+				<view class="title">任务量</view>
+				<view class="price">
+					<text>{{details[tabs[showType].name][item.key + 'targetamount' ]}}</text>
+				</view>
+				<view class="row">
+					目标达成率:{{details[tabs[showType].name][item.key + 'rate_achieve' ]}}%
+				</view>
+				<view class="row">
+					销售额与任务量差额:{{details[tabs[showType].name][item.key + 'balanceamount' ]}}
+				</view>
+			</view>
+		</swiper-item>
+	</swiper>
+</view>
+
+<wxs module="render">
+	module.exports = {
+		rightRate: function (rate) {
+			if (rate - 0 < 50) {
+				return 'transform: rotate(' + 3.6 * (rate - 0) + 'deg);';
+			} else {
+				return 'transform: rotate(0);border-color: var(--assist);';
+			}
+		},
+		leftRate: function (rate) {
+			if (rate - 0 >= 50) {
+				return 'transform: rotate(' + 3.6 * (rate - 50) + 'deg);';
+			}
+		}
+	}
+</wxs>

+ 1 - 1
salesPanel/personTarget/index.js

@@ -5,7 +5,7 @@ Page({
             model: "#GK"
         }, {
             label: "产品类别",
-            model: "#target"
+            model: "#productType"
         }],
         tabsActive: 1,
     },

+ 2 - 2
salesPanel/personTarget/index.json

@@ -1,7 +1,7 @@
 {
     "usingComponents": {
         "GK": "./GK/index",
-        "target":"./target/index"
+        "productType":"./productType/index"
     },
-    "navigationBarTitleText": "销售数据"
+    "navigationBarTitleText": "人员目标"
 }

+ 1 - 1
salesPanel/personTarget/index.wxml

@@ -1,4 +1,4 @@
 <Yl_FunTabs id='Yl_FunTabs' safety='{{false}}' list='{{tabsList}}' mode='buts' active='{{tabsActive}}' bind:onChenge="tabsChange">
     <GK slot='概况' id='GK' />
-    <target slot='产品类别' id='target' />
+    <productType slot='产品类别' id='productType' />
 </Yl_FunTabs>

+ 210 - 0
salesPanel/personTarget/productType/index.js

@@ -0,0 +1,210 @@
+const _Http = getApp().globalData.http,
+    currency = require("../../../utils/currency"),
+    CNY = (value, symbol = "¥", precision = 2) => currency(value, {
+        symbol,
+        precision
+    }).format();
+
+Component({
+    properties: {
+
+    },
+    options: {
+        addGlobalClass: true
+    },
+    lifetimes: {
+        attached: function () {}
+    },
+    data: {
+        tabs: [],
+        salesShow: false,
+        showType: 0,
+        content: {
+            year: new Date().getFullYear(),
+            sa_saleareaid: 0,
+            "type": 1, //1:人员,2:医院,3:经销商
+            "month_start": 1,
+            "month_end": 12,
+            "userid": 0,
+            "sa_customersid": 0,
+            "sa_agentsid": 0,
+            where: {}
+        },
+        areaList: [],
+        active: "",
+        details: {},
+        showFiltrate: false,
+        areaname: "",
+        userName: ""
+    },
+    methods: {
+        async getList(init = false) {
+            if (init) this.getData()
+        },
+        changeArea({
+            detail
+        }) {
+            this.setData({
+                active: detail,
+                "content.sa_saleareaid": this.data.areaList.find(v => v.areaname == 'detail').sa_saleareaid
+            });
+            this.getData();
+        },
+        async getData() {
+            let content = this.data.content;
+            if (content.sa_saleareaid == 0) {
+                let organization = this.selectComponent("#organization");
+                await organization.initDepAndUser().then(res => {
+                    if (res.sa_saleareaid) {
+                        this.data.content.sa_saleareaid = res.sa_saleareaid
+                        this.setData({
+                            areaname: res.areaname
+                        })
+                    }
+                })
+            }
+            _Http.basic({
+                "id": 2026010714131502,
+                content
+            }).then(res => {
+                console.log("产品目标", res)
+                if (res.code != 1) return wx.showToast({
+                    title: res.msg,
+                    icon: "none"
+                });
+                let tabs = [],
+                    details = {};
+
+                res.data.forEach((item, index) => {
+                    tabs.push({
+                        name: item.itemclassname,
+                        index: index,
+                        key: 'm_'
+                    })
+                    item.m_balanceamount = CNY(item.m_balanceamount)
+                    item.m_saleamount = CNY(item.m_saleamount)
+                    item.m_targetamount = CNY(item.m_targetamount)
+                    details[item.itemclassname] = item;
+                })
+
+                this.setData({
+                    tabs,
+                    details
+                })
+            })
+        },
+        changeDate({
+            detail
+        }) {
+            this.setData({
+                "content.year": detail.year,
+                "content.month_start": detail.startMonth,
+                "content.month_end": detail.endMonth,
+            })
+            this.getData()
+        },
+        changeType(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            this.setData({
+                showType: item.index
+            })
+        },
+        // 获取营销类别
+        getSales() {
+            _Http.basic({
+                "content": {},
+                "id": 2025123014533002
+            }).then(res => {
+                console.log("营销类别", res)
+                const tabs = res.code != 1 ? [] : res.data.map((v, i) => {
+                    return {
+                        name: v,
+                        index: i,
+                        key: 'm_'
+                    }
+                });
+                this.setData({
+                    tabs
+                })
+                this.closeSelect()
+            })
+        },
+        selectSale() {
+            this.setData({
+                salesShow: true
+            })
+        },
+        onSelect(e) {
+            this.setData({
+                showType: e.detail.index
+            })
+            this.closeSelect();
+        },
+        swiperChange(e) {
+            this.setData({
+                showType: e.detail.current
+            })
+            this.closeSelect()
+        },
+        closeSelect() {
+            this.setData({
+                salesShow: false
+            });
+            this.setData({
+                tabs: this.data.tabs.map(v => {
+                    v.color = v.index == this.data.showType ? '#3874F6' : ''
+                    return v
+                })
+            })
+        },
+        openFiltrate() {
+            this.setData({
+                showFiltrate: true
+            })
+        },
+        async handleFilter({
+            detail
+        }) {
+            let organization = this.selectComponent("#organization");
+
+            if (detail.name == "close") return;
+            if (detail.name == 'reset') {
+                organization.setData({
+                    isleave: "0"
+                })
+                await organization.initDepAndUser().then(res => {
+                    if (res.sa_saleareaid) {
+                        this.data.content.sa_saleareaid = res.sa_saleareaid
+                        this.data.content.userid = ''
+                        this.setData({
+                            areaname: res.areaname,
+                            userName: ""
+                        })
+                        this.getData()
+                    }
+                })
+            } else {
+                let res = organization.data.result;
+                if (res.userid) {
+                    let dep = organization.data.selectDepObj;
+                    this.data.content.sa_saleareaid = dep.sa_saleareaid;
+                    this.data.content.userid = res.userid;
+                    this.setData({
+                        areaname: dep.areaname,
+                        userName: res.name
+                    })
+                } else {
+                    this.data.content.sa_saleareaid = res.sa_saleareaid
+                    this.data.content.userid = 0
+                    this.setData({
+                        areaname: res.areaname,
+                        userName: ''
+                    })
+                }
+                this.getData()
+            }
+        },
+    }
+})

+ 6 - 0
salesPanel/personTarget/productType/index.json

@@ -0,0 +1,6 @@
+{
+    "component": true,
+    "usingComponents": {
+        "headOptionBox": "../../headOptionBox/index"
+    }
+}

+ 126 - 0
salesPanel/personTarget/productType/index.scss

@@ -0,0 +1,126 @@
+page {
+    width: 100vw;
+    overflow: hidden;
+}
+
+.head {
+    display: flex;
+    margin-bottom: 30rpx;
+
+    .item {
+        font-weight: bold;
+    }
+}
+
+.chart {
+    margin: 0 auto;
+    width: 280rpx;
+    flex-shrink: 0;
+    margin-bottom: 20rpx;
+
+    .circle {
+        width: 280rpx;
+        height: 280rpx;
+        position: relative;
+        border-radius: 50%;
+        box-shadow: inset 0 0 0 20rpx var(--assist);
+
+        .ab {
+            position: absolute;
+            left: 0;
+            right: 0;
+            top: 0;
+            bottom: 0;
+            margin: auto;
+        }
+
+        &_left {
+            border: 20rpx solid #EBEEF5;
+            border-radius: 50%;
+            clip: rect(0, 140rpx, 280rpx, 0);
+        }
+
+        &_right {
+            border: 20rpx solid #EBEEF5;
+            border-radius: 50%;
+            clip: rect(0, 280rpx, 280rpx, 140rpx);
+        }
+
+        &_text {
+            height: 100%;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            font-size: 32rpx;
+
+            .value {
+                font-family: Microsoft YaHei, Microsoft YaHei;
+                font-weight: bold;
+                font-size: 32rpx;
+                color: #333333;
+                margin-top: 12rpx;
+            }
+
+            .name {
+                font-family: Microsoft YaHei, Microsoft YaHei;
+                color: #999999;
+                margin-top: 16rpx;
+            }
+        }
+    }
+}
+
+.card {
+    width: 100%;
+    border-radius: 20rpx;
+    border: 1rpx solid #E0E0E0;
+    padding: 20rpx 40rpx;
+    margin-top: 20rpx;
+
+    .title {
+        line-height: 32rpx;
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #999999;
+    }
+
+    .price {
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #3685FC;
+        margin-top: 10rpx;
+
+        text {
+            font-size: 40rpx;
+            margin-right: 6rpx;
+        }
+    }
+
+    .row {
+        line-height: 32rpx;
+        font-family: Microsoft YaHei, Microsoft YaHei;
+        font-size: 24rpx;
+        color: #999999;
+        margin-top: 6rpx;
+
+        .increase,
+        .decrease {
+            display: inline-block;
+            width: 0;
+            height: 0;
+            border-left: 8rpx solid transparent;
+            border-right: 8rpx solid transparent;
+            margin-left: 10rpx;
+        }
+
+        .increase {
+            border-bottom: 14rpx solid #009966;
+        }
+
+        .decrease {
+            border-top: 14rpx solid #EF0606;
+        }
+    }
+
+}

+ 80 - 0
salesPanel/personTarget/productType/index.wxml

@@ -0,0 +1,80 @@
+<view style="height: 10rpx;"></view>
+<view bind:tap="openFiltrate">
+	<headOptionBox iconName='icon-bumen' title='营销区域' showText="{{areaname}}" placeholder='请选择营销区域' />
+	<headOptionBox iconName='icon-a-biaoqianlanwode' showText="{{userName}}" title='业务员' placeholder='请选择业务员' />
+</view>
+<filtrate id='Filtrate' iconName='icon-bumen' wx:if='{{areaList.length}}' list='{{areaList}}' type="{{active}}" title='营销区域' bind:onChange='changeArea' />
+<viewDate iconName='icon-shijian1' type='sameYear' fields='year' value='{{content.year}}' startMonth="{{content.month_start}}" endMonth="{{content.month_end}}" title='时间范围' bind:onChange='changeDate' />
+<view style="height: 20rpx;"></view>
+
+<Yl_Filtrate1 id="Yl_Filtrate1" show='{{showFiltrate}}' list="{{[]}}" bindhandle="handleFilter">
+	<organization slot='head' defaultIsleave='0' dimissionF id='organization' />
+</Yl_Filtrate1>
+
+<view class="global-card" style="overflow: hidden;">
+
+	<view class="head">
+		<view class="item" catch:tap="selectSale">{{tabs[showType].name}}<text class="iconfont icon-webxialaxuanxiangjiantou"></text></view>
+	</view>
+	<van-action-sheet show="{{  salesShow }}" actions="{{ tabs }}" bind:select='onSelect' bind:cancel='closeSelect' bind:click-overlay='closeSelect' cancel-text="取消" />
+
+	<swiper current="{{showType}}" circular style="height: 760rpx;" bindchange='swiperChange'>
+		<swiper-item wx:for="{{tabs}}" wx:key="name">
+			<view class="chart">
+				<view class="circle">
+					<view class="circle_left ab" style="{{render.leftRate(details[tabs[showType].name][item.key +'rate_achieve'])}}" />
+					<view class="circle_right ab" style="{{render.rightRate(details[tabs[showType].name][item.key +'rate_achieve'])}}" />
+					<view class="circle_text">
+						<text class="name">目标达成率</text>
+						<text class="value">{{details[tabs[showType].name][item.key + 'rate_achieve' ]}}%</text>
+					</view>
+				</view>
+			</view>
+
+			<view class="card">
+				<view class="title">销售额</view>
+				<view class="price">
+					<text>{{details[tabs[showType].name][item.key + 'saleamount' ]}}</text>
+				</view>
+				<view class="row">
+					同比:{{details[tabs[showType].name][item.key + 'rate_yoy' ]}}%
+					<view wx:if="{{details[tabs[showType].name][item.key  + 'rate_yoy'] != 0}}" class="{{details[tabs[showType].name][item.key + 'rate_yoy']>=0?'increase':'decrease'}}" />
+				</view>
+				<view class="row">
+					环比:{{details[tabs[showType].name][item.key + 'rate_mom' ]}}%
+					<view wx:if="{{details[tabs[showType].name][item.key + 'rate_mom'] != 0}}" class="{{details[tabs[showType].name][item.key + 'rate_mom']>=0?'increase':'decrease'}}" />
+				</view>
+			</view>
+
+			<view class="card">
+				<view class="title">任务量</view>
+				<view class="price">
+					<text>{{details[tabs[showType].name][item.key + 'targetamount' ]}}</text>
+				</view>
+				<view class="row">
+					目标达成率:{{details[tabs[showType].name][item.key + 'rate_achieve' ]}}%
+				</view>
+				<view class="row">
+					销售额与任务量差额:{{details[tabs[showType].name][item.key + 'balanceamount' ]}}
+				</view>
+			</view>
+		</swiper-item>
+	</swiper>
+</view>
+
+<wxs module="render">
+	module.exports = {
+		rightRate: function (rate) {
+			if (rate - 0 < 50) {
+				return 'transform: rotate(' + 3.6 * (rate - 0) + 'deg);';
+			} else {
+				return 'transform: rotate(0);border-color: var(--assist);';
+			}
+		},
+		leftRate: function (rate) {
+			if (rate - 0 >= 50) {
+				return 'transform: rotate(' + 3.6 * (rate - 50) + 'deg);';
+			}
+		}
+	}
+</wxs>

+ 8 - 0
utils/work/apps.js

@@ -104,6 +104,14 @@ function getcrm() {
     name: "人员目标",
     path: "/salesPanel/personTarget/index",
     icon: "work-dingdan"
+  }, {
+    name: "医院目标",
+    path: "/salesPanel/hospitalTarget/index",
+    icon: "work-dingdan"
+  }, {
+    name: "经销商目标",
+    path: "/salesPanel/agencyTarget/index",
+    icon: "work-dingdan"
   }];
   let crm = getApp().globalData.queryPer.query(wx.getStorageSync('userauth'), ['CRM'], ['业务管理', '销售管理']),
     list = [];