Przeglądaj źródła

Merge branch '黄色' into 测试

xiaohaizhao 11 miesięcy temu
rodzic
commit
b9b00173dc

+ 4 - 0
components/Yl_Filtrate1/index.js

@@ -11,6 +11,10 @@ Component({
         multipleSlots: true
     },
     properties: {
+        rule: {
+            type: Boolean,
+            value: true
+        },
         list: {
             type: {
                 type: Array

+ 29 - 3
components/Yl_Filtrate1/index.scss

@@ -1,4 +1,32 @@
 @import "./groud.scss";
+
+.content1 {
+    display: flex;
+    flex-wrap: wrap;
+    width: 100%;
+
+    .but {
+        min-width: 188rpx;
+        height: 72rpx;
+        background: #F5F5F5;
+        border-radius: 8rpx;
+        font-size: 28rpx;
+        font-family: PingFang SC-Regular, PingFang SC;
+        color: #333333;
+        box-sizing: border-box;
+        margin-right: 20rpx;
+        margin-top: 20rpx;
+        padding: 0 10rpx;
+    }
+
+    .active {
+        border: 1px solid #3874F6;
+        color: #3874F6;
+        font-weight: bold;
+        background-color: #F5F5F5;
+    }
+}
+
 .footer {
     display: flex;
     justify-content: space-around;
@@ -26,6 +54,4 @@
         font-weight: bold;
         color: #FFFFFF;
     }
-}
-
-
+}

+ 2 - 2
components/Yl_Filtrate1/index.wxml

@@ -8,10 +8,10 @@
                 <view class="label">
                     {{language[item.label]||item.label}}
                 </view>
-                <view class="content" wx:if="{{item.type!='checkbox'}}">
+                <view class="{{rule?'content':'content1'}}" wx:if="{{item.type!='checkbox'}}">
                     <van-button custom-class='but {{item.index==i?"active":""}}' wx:for="{{item.list}}" wx:for-item="data" wx:for-index="i" wx:key="i" data-item="{{data}}" data-index="{{index}}" data-i="{{i}}" bindtap="onSelect">{{language[data[item.showName]]||data[item.showName]}}</van-button>
                 </view>
-                <view wx:else class="content">
+                <view wx:else class="{{rule?'content':'content1'}}">
                     <van-button custom-class='but {{per.query(item.index,i)?"active":""}}' wx:for="{{item.list}}" wx:for-item="data" wx:for-index="i" wx:key="i" data-item="{{data}}" data-index="{{index}}" data-i="{{i}}" bindtap="onSelectCheckbox">{{language[data[item.showName]]||data[item.showName]}}</van-button>
                 </view>
             </view>

+ 298 - 0
salesPanel/dataOverview/Costs/SituationStatistics.js

@@ -0,0 +1,298 @@
+const _Http = getApp().globalData.http,
+    currency = require("../../../utils/currency"),
+    CNY = (value, symbol = "¥", precision = 2) => currency(value, {
+        symbol,
+        precision
+    }).format(),
+    dividend = wx.getStorageSync('languagecode') == 'ZH' ? 10000 : 1000;
+
+
+import * as echarts from '../../ec-canvas/echarts';
+Component({
+    properties: {
+        idname: {
+            type: [String || Number]
+        }
+    },
+    options: {
+        addGlobalClass: true
+    },
+    lifetimes: {
+        attached: function () {
+            getApp().globalData.Language.getLanguagePackage(this)
+        }
+    },
+    data: {
+        dateTypes: ["全部", "本年"],
+        "content": {
+            pageNumber: 1,
+            pageTotal: 1,
+            dataid: wx.getStorageSync('userMsg').userid,
+            username: wx.getStorageSync('userMsg').name,
+            dateType: "本年",
+            type: 0,
+            where: {
+                begdate: "",
+                enddate: "",
+                isleave: "1",
+                feestype: "",
+                type: ""
+            }
+        },
+        filterShow: false,
+        list: []
+    },
+    methods: {
+        async getList(init = false) {
+            if (!this.data.list.length) _Http.basic({
+                "classname": "sysmanage.develop.optiontype.optiontype",
+                "method": "optiontypeselect",
+                "content": {
+                    "pageNumber": 1,
+                    "pageSize": 1000,
+                    "typename": "feestype",
+                    "parameter": {}
+                }
+            }).then(res => {
+                console.log("费用类型", res)
+                if (res.code == 1) {
+                    this.setData({
+                        filtratelist: [{
+                            label: "费用类型",
+                            index: null,
+                            showName: "name", //显示字段
+                            valueKey: "feestype", //返回Key
+                            selectKey: "value", //传参 代表选着字段 不传参返回整个选择对象
+                            value: "", //选中值
+                            list: res.data.map(v => {
+                                return {
+                                    name: v.value + '-' + getApp().globalData.Language.getMapText(v.remarks),
+                                    value: v.value + '-' + v.remarks
+                                }
+                            })
+                        }]
+                    })
+                }
+            })
+            if (init.detail != undefined) init = init.detail;
+            let content = this.data.content
+            const {
+                dataid,
+                type,
+                username,
+                isleave
+            } = getCurrentPages()[getCurrentPages().length - 1].data;
+            if (content.dataid != dataid || content.type != type || isleave != isleave) init = true
+            content.dataid = dataid;
+            content.type = type;
+            content.username = username;
+            content.where.isleave = isleave;
+            if (init) {
+                content.pageNumber = 1;
+                content.pageTotal = 1;
+            }
+            if (content.pageNumber > content.pageTotal) return;
+
+            _Http.basic({
+                id: this.data.idname,
+                content
+            }).then(res => {
+                console.log("费用分析", res)
+                this.selectComponent('#ListBox').RefreshToComplete();
+                if (res.code != '1') return wx.showToast({
+                    title: res.data,
+                    icon: "none"
+                })
+                res.data = res.data.map(v => {
+                    v.amount = CNY(v.amount)
+                    return v
+                })
+                this.setData({
+                    list: res.pageNumber == 1 ? res.data : this.data.list.concat(res.data),
+                    "content.pageNumber": res.pageNumber + 1,
+                    "content.pageSize": res.pageSize,
+                })
+                this.selectComponent("#TimeRange").onCancel()
+                try {
+                    res.data[0].ratio = res.data[0].ratio.filter(v => v.ratio)
+                } catch (error) {
+
+                }
+
+                if (init) this.initChart(res.data[0].ratio, CNY(res.data[0].ratio[0].total / dividend));
+            })
+        },
+        initChart(data, total) {
+            const getMapText = getApp().globalData.Language.getMapText;
+            let countDown = null,
+                that = this;
+
+            function changeUnwriteoffamounttype(params) {
+                if (countDown) return;
+                countDown = setTimeout(() => {
+                    let data = that.data.list[0].ratio.find(v => getApp().globalData.Language.getMapText(v[nameKey]) == params.name)
+                    clearTimeout(countDown)
+                    countDown = null;
+                    switch (that.data.idname) {
+                        case "2024062614062202":
+                            if (data.text != that.data.content.where.feestype) {
+                                that.setData({
+                                    "content.where.feestype": data.text || "",
+                                    "content.pageNumber": 1,
+                                });
+                                let showText = getApp().globalData.Language.getMapText(data.text)
+                                let Filtrate = that.selectComponent('#Filtrate');
+                                Filtrate.setData({
+                                    showText
+                                })
+                            }
+                            break;
+                        default:
+                            if (data.type != that.data.content.where.type) {
+                                that.setData({
+                                    "content.where.type": data.type || "",
+                                    "content.pageNumber": 1,
+                                });
+                            }
+                            break;
+                    }
+                    that.getList()
+                }, 200)
+            };
+
+            let nameKey = {
+                2024062614062202: "text",
+                2024062915153702: "type",
+                2024062615133802: "type",
+                2024062915152702: "type",
+            } [this.data.idname]
+
+            let option = {
+                tooltip: {
+                    trigger: 'item',
+                    confine: true, // Ensure tooltip stays within chart boundaries
+                    formatter: function (params) {
+                        changeUnwriteoffamounttype(params)
+                        return `${getMapText(params.name)}: ${params.value} (${params.percent}%)`;
+                    },
+                },
+                legend: {
+                    type: 'scroll', // Enable scrollable legend
+                    bottom: '5%', // Moved legend to the bottom
+                    left: 'center',
+                    pageIconColor: '#333', // Customize page icon color
+                    pageTextStyle: {
+                        color: '#333' // Customize page text style
+                    }
+                },
+                series: [{
+                    type: 'pie',
+                    radius: ['40%', '70%'],
+                    center: ['50%', '42%'], // Adjusted to align with the new legend position
+                    endAngle: 360,
+                    data: data.map(v => {
+                        return {
+                            name: getMapText(v[nameKey]),
+                            value: (v.ratio * 100).toFixed(2),
+                        }
+                    }),
+                    label: {
+                        normal: {
+                            show: true,
+                            position: 'outside',
+                            formatter: '{b}: {c} ({d}%)',
+                            textStyle: {
+                                fontSize: 12,
+                                color: '#333'
+                            }
+                        },
+                        emphasis: {
+                            show: true,
+                            textStyle: {
+                                fontSize: 14,
+                                fontWeight: 'bold'
+                            }
+                        },
+                        rich: {
+                            total: {
+                                fontSize: 20,
+                                fontWeight: 'bold',
+                                color: '#333'
+                            },
+                            desc: {
+                                fontSize: 12,
+                                color: '#999'
+                            }
+                        }
+                    },
+                    labelLine: {
+                        normal: {
+                            show: true,
+                            length: 10,
+                            length2: 10
+                        }
+                    }
+                }]
+            };
+            option.graphic = {
+                type: 'text',
+                left: 'center',
+                top: '35%', // Adjusted to align with the new series position
+                style: {
+                    text: `${getMapText('总计')}\n\n${total}`,
+                    textAlign: 'center',
+                    fill: '#333',
+                    fontSize: 16,
+                    fontWeight: 'bold'
+                }
+            };
+            this.chartComponent = this.selectComponent('#mychart');
+            this.chartComponent.init((canvas, width, height, dpr) => {
+                const chart = echarts.init(canvas, null, {
+                    width,
+                    height,
+                    devicePixelRatio: dpr
+                });
+                chart.setOption(option);
+                return chart;
+            });
+        },
+        changeDate({
+            detail
+        }) {
+            this.setData({
+                "content.dateType": detail.dateType,
+                "content.where.begdate": detail.begdate || "",
+                "content.where.enddate": detail.enddate || ""
+            })
+            this.getList(true)
+        },
+        clickOpen() {
+            this.setData({
+                filterShow: true
+            })
+        },
+        /* 处理筛选 */
+        handleFilter({
+            detail
+        }) {
+            if (detail.name == "confirm") {
+                this.setData({
+                    "content.where.feestype": detail.feestype
+                })
+                this.selectComponent('#Filtrate').setData({
+                    showText: getApp().globalData.Language.getMapText(detail.feestype)
+                })
+                this.getList(true)
+            } else if (detail.name == 'reset') {
+                this.setData({
+                    "content.where.feestype": ""
+                })
+                this.selectComponent('#Filtrate').setData({
+                    showText: getApp().globalData.Language.getMapText("全部")
+                })
+                this.getList(true)
+            }
+        },
+    }
+})

+ 6 - 0
salesPanel/dataOverview/Costs/SituationStatistics.json

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

+ 3 - 0
salesPanel/dataOverview/Costs/SituationStatistics.scss

@@ -0,0 +1,3 @@
+@import "../../analysisOfOrderTypeDistribution/index.scss";
+// @import "../OverviewAndDetails/Client.scss";
+@import "./SPMEDetail.scss";

+ 35 - 0
salesPanel/dataOverview/Costs/SituationStatistics.wxml

@@ -0,0 +1,35 @@
+<timeRange id='TimeRange' dateTypes='{{dateTypes}}' dateType='{{content.dateType}}' bind:onChange='changeDate' />
+
+<filtrate id='Filtrate' iconName='icon-xiangmuzhuangtai' list='{{[]}}' title='项目状态' bind:clickOpen='clickOpen' />
+
+<Yl_ListBox id='ListBox' bind:getlist='getList'>
+	<view class="global-card" wx:if='{{list[0].ratio.length}}'>
+		<view class="chart">
+			<ec-canvas id="mychart" canvas-id="chart" ec="{{ ec }}"></ec-canvas>
+		</view>
+	</view>
+	<My_empty wx:if='{{list[0].isEmpty}}' />
+	<block wx:else>
+		<view class="global-card item" wx:for="{{list}}" wx:key="sa_salesfeesid">
+			<view class="title">
+				<text class="line-1">{{item.billno || " --"}}</text>
+			</view>
+			<view class="systemapp">{{language[item.systemapp]||item.systemapp}}</view>
+			<view class="row">
+				<view class="col">{{language['负责人']||'负责人'}}:{{language[item.salesname]||item.salesname ||' --'}}</view>
+				<view class="col">{{language['部门']||'部门'}}:{{language[item.depname]||item.depname ||' --'}}</view>
+			</view>
+			<view class="row">{{language['客户名称']||'客户名称'}}:{{item.enterprisename ||' --'}}</view>
+			<view class="row">{{language['项目名称']||'项目名称'}}:{{item.projectname ||' --'}}</view>
+			<view class="row">{{language['联系人']||'联系人'}}:{{item.names ||' --'}}</view>
+			<view class="row">{{language['费用类型']||'费用类型'}}:<text class="amount">{{item.amount}}</text></view>
+			<view class="row">{{language['营销费用(元)']||'营销费用(元)'}}:{{language[item.feestypefullname]||item.feestypefullname ||' --'}}</view>
+			<view class="row">{{language['跟进类型']||'跟进类型'}}:{{language[item.type]||item.type ||' --'}}</view>
+			<view class="row">{{language['跟进内容']||'跟进内容'}}:{{item.content ||' --'}}</view>
+			<view class="row">{{language['跟进时间']||'跟进时间'}}:{{item.createdate ||' --'}}</view>
+		</view>
+		<My_empty wx:if="{{list.length==0}}" />
+	</block>
+</Yl_ListBox>
+
+<Yl_Filtrate1 show='{{filterShow}}' rule="{{false}}" list="{{filtratelist}}" bindhandle="handleFilter" />

+ 12 - 0
salesPanel/dataOverview/list/costs.js

@@ -22,6 +22,18 @@ Component({
         }, {
             label: "业务员营销费用TOP10",
             model: "#SPmarketingExpenses"
+        }, {
+            label: "营销费用类型情况统计",
+            model: "#TypeOfCost"
+        }, {
+            label: "营销费用来源情况统计",
+            model: "#SourceOfExpenses"
+        }, {
+            label: "客户类型营销费用情况统计",
+            model: "#CustomerTypeFee"
+        }, {
+            label: "项目类型营销费用情况统计",
+            model: "#ProjectTypeFee"
         }],
         init: false
     },

+ 1 - 0
salesPanel/dataOverview/list/costs.json

@@ -2,6 +2,7 @@
     "component": true,
     "usingComponents": {
         "DataOverview": "../Costs/dataOverview",
+        "SituationStatistics": "../Costs/SituationStatistics",
         "SPmarketingExpenses": "../Costs/SPmarketingExpenses"
     }
 }

+ 4 - 0
salesPanel/dataOverview/list/costs.wxml

@@ -1,4 +1,8 @@
 <Yl_FunTabs id='Yl_FunTabs' safety='{{false}}' list='{{tabsList}}' mode='buts' active='{{tabsActive}}' bind:onChenge="tabsChange">
     <DataOverview slot='数据概况' id='DataOverview' />
     <SPmarketingExpenses slot='业务员营销费用TOP10' id='SPmarketingExpenses' />
+    <SituationStatistics slot='营销费用类型情况统计' idname='2024062614062202' id='TypeOfCost' />
+    <SituationStatistics slot='营销费用来源情况统计' idname='2024062915153702' id='SourceOfExpenses' />
+    <SituationStatistics slot='客户类型营销费用情况统计' idname='2024062615133802' id='CustomerTypeFee' />
+    <SituationStatistics slot='项目类型营销费用情况统计' idname='2024062915152702' id='ProjectTypeFee' />
 </Yl_FunTabs>