Vue 管理系统——数据可视化大屏之活动看板

时间:2025-02-28 07:55:38

目录

        1.需求背景及重点需求和解决方式

         2.效果实现

         3.遇到的问题以及解决思路


需求背景:      

        需求的最终目的是为了让门店更了解参加活动的实时数据,通过可视化大屏的形式进行展现。此需求在两个项目上开发,唯一的区别就是门店端只会显示当前门店的数据信息,这篇博客我们主要介绍门店端的开发历程。

重点需求:

        1.为了高效还原ui图,手写倒计时正计时组件,Switch组件;

        2.订单金额没隔3位数加,号(可以参考我之前的博客);

        3.二次封装组件,与后端建立长链接保持数据的实时通讯(大屏金额发生变化时数字跳         动效果&&实时弹幕);

        4.使用rem布局适配大屏;

        5.使用原生js实现屏幕百分百显示效果;

        6.使用js完成一些特效;

 

效果实现:

1.手写组件

倒计时正计时组件:

            <div class="active_nam">距离活动结束还剩</div>
            <div class="countdown">
                <div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">天</div>
                <div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">时</div>
                <div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">分</div>
                <div class="div-con">{{().padStart(2,0)}}</div><div class="div-dw">秒</div>
            </div>
            <div class="diachronic">
                活动历时 : {{().padStart(2,0)}}:{{().padStart(2,0)}}:{{().padStart(2,0)}}:{{().padStart(2,0)}}
            </div>

js:

            calculateTheTime(row) {
                // 此处获取时间信息完成倒计时单位转换
                let start = new Date() ? dayjs(new Date()).format("YYYY/MM/DD HH:mm:ss") :""; // 当前最新的时间
				let begin =  ? dayjs().format("YYYY/MM/DD HH:mm:ss") : "" // 开始时间
				let end =  ? dayjs().format("YYYY/MM/DD HH:mm:ss") : "" // 结束时间
				let start_num = new Date((/-/g, "/"))
				let end_num = new Date((/-/g, "/"))
				let begin_num = new Date((/-/g, "/"))
                if(end_num.getTime() > start_num.getTime()){
                     = parseInt(end_num.getTime() - start_num.getTime())
                    ()
                     = parseInt(start_num.getTime() - begin_num.getTime())
                    const Duration = parseInt(end_num.getTime() - begin_num.getTime())
                    (,Duration)
                }else{
                     = parseInt(end_num.getTime() - begin_num.getTime())
                    const Duration = parseInt(end_num.getTime() - begin_num.getTime())
                    (,Duration)
                }
            },
            formatDuring(millisecond) { // 手写倒计时 倒计时时间为0000的时候清除计时器
                 = parseInt(millisecond / (1000 * 60 * 60 * 24));
                 = parseInt((millisecond % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
                 = parseInt((millisecond % (1000 * 60 * 60)) / (1000 * 60));
                 = ((millisecond % (1000 * 60)) / 1000);
                 = setInterval(()=>{
                    if(>0){
                         --
                    }else if(>0){
                         = 59
                         --
                    }
                    else if(>0){
                         = 59
                         --
                    }
                    else if(>0){
                         = 23
                         --
                    } 
                    else if(==0){
                        clearInterval()
                    }
				},1000)
            },

css:

        .active_nam{
            margin-top: 0.625rem;
            font-size: 1.3125rem;
            color: #FFF;
        }
        .countdown{
            display: flex;
            margin-top: 1.875rem;
            .div-con{
                font-size: 1.25rem;
                font-weight: 600;
                width: 2.8125rem;
                height: 2.8125rem;
                color: #20209D;
                background-color: #FFF;
                border-radius: 0.3125rem;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .div-dw{
                font-size: 1.3125rem;
                color: #FFF;
                width: 2.8125rem;
                height: 2.8125rem;
                border-radius: 0.3125rem;
                display: flex;
                justify-content: center;
                align-items: center; 
            }
        }
        .diachronic{
            margin-top: 1.25rem;
            font-size: 1.3125rem;
            color: #FFF;
        }

Switch组件(主要借助伪元素实现效果):

                    <div class="switch-con" @click="barrageIsShow = !barrageIsShow">
                        <div class="outer">
                            <input type="checkbox" :checked="barrageIsShow">
                            <div class="slider"></div>
                        </div>
                    </div>

css:

              .switch-con{
                    margin-top: 1rem;
                    width: 3.8rem;
                    height: 2rem;
                    border-radius: 1.5625rem;
                    padding: 0.187rem 0 0 0.125rem;
                    border: 0.0125rem solid transparent;
                    background-clip: padding-box, border-box;
                    background-origin: padding-box, border-box;
                    background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(33, 31, 48, 0.58))), -webkit-gradient(linear, left top, right top, from(rgba(193, 99, 152, 0.44)), to(rgba(176, 175, 242, 0.58)));
                    .outer{
                        width:3.375rem;
                        height:1.5rem;
                        position: relative;
                        .slider{
                            position: absolute;
                            left:0;
                            top:0;
                            right:0;
                            bottom:0;
                            background:rgba(33, 31, 48, 0.58);
                            border-radius: 1.125rem;
                            transition:  0.4s;
                            cursor: default;
                            line-height: 1.625rem;
                            &::before{
                                content: '';
                                position: absolute;
                                width:1.62rem;
                                height:1.62rem;
                                left:0;
                                top:-0.09rem;
                                border-radius: 50%;
                                transition:  0.4s;
                                box-sizing: border-box;
                                border: 0.0625rem solid transparent;
                                background-clip: padding-box, border-box;
                                background-origin: padding-box, border-box;
                                background-image: -webkit-gradient(linear, left top, left bottom, from(#CF48A9)), -webkit-gradient(linear, left top, right top, from(rgba(116, 30, 79, 1)), to(rgba(255, 255, 255, 0.44)));
                            }
                        }
                        input{
                            display: none;
                            &:checked + .slider{
                                color: #fff;
                                box-sizing: border-box;
                                border: 0.0625rem solid transparent;
                                background-clip: padding-box, border-box;
                                background-origin: padding-box, border-box;
                                background-image: -webkit-gradient(linear, left top, left bottom, from(#F487CD)), -webkit-gradient(linear, left top, right top, from(rgba(61, 12, 31, 0.85)), to(rgba(255, 255, 255, 0.24)));
                            }
                            &:checked + .slider::before{
                                left: 1.75rem;
                            }
                        }
                    }
                }

2.借助 countTo 和 vueBaberrage 组件实施数字跳动以及弹幕效果

        关于这两个组件的使用就不过多介绍大家自行去搜索也很简单

        重点在于建立长链接生成一个唯一key后在把key储存给后端完成链接后通过vux加上侦听器实时监听数据变化并完成css效果,一下是部分代码:

长链接的js文件中:

import client from "./client"
const push = client();
// 这里的client 需要借助 @stomp/stompjs
export function initKey(shopcode) {
    let str = shopcode + "-" + ();
    ("pushkey", str);
    ("wss:///ws" , shopcode + "|" + str , async function (frame) {
        let {webdata,memberBuyInfo} = (frame);
        if(webdata)
        ("update/setTimely",webdata);
        if(memberBuyInfo)
        ("update/setBuyInfo",memberBuyInfo);
    }, function (frame) {
        ('disconnect', frame);
    });
}

在要是用的组件中侦听: 

            "$": function () { // 获取vuex中数据并操作
                // (this.$,'setTimely徐飞');
                ()
                 = this.$
                 =  // 保证第二次变化的初始值
                 = ?:0
            },
            "$": function () { // 获取vuex中数据并操作
                // (this.$,'memberBuyInfo徐飞');
                let memberBuyInfo = this.$
                (memberBuyInfo)
            }

弹幕样式更改:

 /*弹幕区域高度*/
    /deep/ .baberrage-stage {
        padding: 12.5rem 2rem;
        width: 87.5rem;
        height: 62.5rem;
    }

    /*弹幕消息框*/
    /deep/ .baberrage-item .normal {
        padding: 0 1.25rem;
        background: none;
    }

    // /*头像*/
    /deep/ .baberrage-item .normal .baberrage-avatar {
        width: 2.875rem;
        height: 2.875rem;
        border-radius: 50%;
        border: 0.0625rem solid transparent;
        background-clip: padding-box, border-box;
        background-origin: padding-box, border-box;
        background-image: linear-gradient(rgba(193, 99, 152, 0.44)), linear-gradient(to right, rgba(193, 99, 152, 0.44), rgba(176, 175, 242, 0.58));
        img{
            width: 2.875rem;
            height: 2.875rem;
            border-radius: 50%;
        }
    }

    // /*文字*/
    /deep/ .baberrage-item .normal .baberrage-msg {
        height: 2rem;
        margin-top: 0.4375rem;
        margin-left: -0.5rem;
        font-size: 1.125rem;
        line-height: 2rem;
        background: rgba(0,0,0,0.2)!important;
        border-radius:0 1.5625rem 1.5625rem 0;
        border: 0.0563rem solid rgba(193, 99, 152, 0.44);
        border-left: none;
        padding: 0 1.25rem;
    }

3.原生js实现大屏效果(并改变fontsize大小完成rem自适应):

            handleFullScreen (params) {
                // 实现全屏的方法
                function requestFullScreen(element) {
                    var requestMethod =  || //W3C
                         || //Chrome
                         || //FireFox
                        ; //IE11
                    if (requestMethod) {
                        (element);
                    } else if (typeof  !== "undefined") { //for Internet Explorer
                        var wscript = new ActiveXObject("");
                        if (wscript !== null) {
                        ("{F11}");
                        }
                    }
                }
                requestFullScreen();
                let doc = ('Content')[0]
                let bgimg = ('bg-img')[0]
                 = 'fixed'
                 = 0
                 = 0
                 = '100vw'
                 = '100vh'
                 = function () {
                    let doc = ('Content')[0]
                    if (!doc) { return }
                    if () {
                    ('进入全屏')
                    if( > 1430) // 徐飞对单页面进行rem适配
                    =/105+"px"
                    // (,'')  // 太强了
                    } else {
                    // 退出全屏的时候恢复原来的样式
                    ('退出全屏')
                     = 'relative'
                     = 'inherit'
                     = 'inherit'
                     = 'inherit'
                     = 'inherit'
                     = 'inherit'
                    }
                };
            },
            exitFull() { //退出全屏 esc键和F11可以直接退出,
                // 判断各种浏览器,找到正确的方法
                var exitMethod =  || //W3C
                     || //FireFox
                     || //Chrome等
                    ; //IE11
                if (exitMethod) {
                    (document);
                } else if (typeof  !== "undefined") { //for Internet Explorer
                    var wscript = new ActiveXObject("");
                    if (wscript !== null) {
                        ("{F11}");
                    }
                }
            },

遇到的问题:

1.子组件使用v-show后里面调用弹幕组件会失效

解决办法:使用路由加载数据实时大屏。顺便解决了大屏之前f11后丑陋的问题

其他还好都解决了。