uniapp自定义数量兑换积分流程

<template>

    <view>

        <view class="noActivityBox" v-if="showNoActivity">

            <image src="/static/images/ve-match/noActivity.png" mode="" class="noActivityImg"></image>

            <view class="activityText" v-if="showEndText">

                <view>活动已结束</view>

                <view style="margin-top: 20rpx;">感谢您的关注</view>

            </view>

            <view class="activityText" v-if="showStartText">{{activityText}}</view>

        </view>

        <view class="c-header" v-if="!showNoActivity">

            <view style="width: 750rpx;height: 344rpx;"></view>

            <view class="h-grid">

                <view class="g-num">

                    <view class="n-item">

                        <view class="l-text1" v-if="Number(amount) > 0" style="color: #f65252;">

                            <text v-if="Number(amount) > 999999.99" style="font-size: 40rpx;">+100<text style="font-size: 26rpx;">W+</text></text>

                            <text v-else>{{'+'+amount}}</text>

                        </view>

                        <view class="l-text1" v-else-if="Number(amount) < 0" style="color: #68ee49;">

                            <text v-if="Math.abs(Number(amount)) > 999999.99" style="font-size: 40rpx;">-100<text style="font-size: 26rpx;">W+</text></text>

                            <text v-else>{{amount}}</text>

                        </view>

                        <view class="l-text1" v-else>{{amount}}</view>

                        <view class="l-text2">盈亏资产</view>

                    </view>

                    <view class="n-line"></view>

                    <view class="n-item">

                        <view class="l-text1" v-if="Number(yibeiNum) > 9999.99">1<text style="font-size: 26rpx;">W+</text></view>

                        <view class="l-text1" v-else>{{yibeiNum}}</view>

                        <view class="l-text2">可兑换积分</view>

                    </view>

                </view>

                <view class="g-check">

                    <view class="c-left">兑换数量</view>

                    <view class="c-center">

                        <view class="c-box">

                            <view class="b-circle" @click="btnClick(1)">-</view>

                            <input type="number" v-model="num" @blur="inputBlur" @focus="inputFocus" @input="changePayNum" class="b-text" ref="ipt">

                            <view class="b-circle" @click="btnClick(2)">+</view>

                        </view>

                    </view>

                    <view class="c-right">积分</view>

                </view>

            </view>

            <image src="../../static/images/ve-match/m-bg9.png" mode="" class="h-btn" @click="confirm" v-if="showExchangeImg"></image>

            <image src="../../static/images/ve-match/m-bg10.png" mode="" class="h-btn" v-else></image>

        </view>

        <view class="c-content" v-if="!showNoActivity">

            <view class="c-rule">

                <view class="r-title">

                    <view class="t-thread"></view>

                    <view class="t-name">兑换规则</view>

                </view>

                <view class="r-conten">

                    {{exchangeRules}}

                </view>

            </view>

            <view class="c-exchange">

                <view class="e-title">

                    <view class="t-left">

                        <view class="t-thread"></view>

                        <view class="t-name">兑换明细</view>

                    </view>

                    <view class="t-right" v-if="Number(exchangedAmount) > 9999.99">

                        已兑换积分共计:1<text style="font-size: 24rpx;">W+</text>

                    </view>

                    <view class="t-right" v-else>

                        已兑换积分共计:{{ exchangedAmount === null || exchangedAmount === '' ? '0.00' : exchangedAmount }}

                    </view>

                </view>

                <view class="e-list">

                    <block v-if="exchangeList.length > 0">

                        <view class="e-item" v-for="(item,index) in exchangeList" :key="index">

                            <view class="i-left">

                                <view class="l-name">兑换积分</view>

                                <view class="l-time">{{item.createTime}}</view>

                            </view>

                            <view class="i-right">-{{item.exchangeAmountTitle}}</view>

                        </view>

                        <!-- uView LoadMore 加载更多组件 -->

                        <u-loadmore :status="loadStatus" style="padding-bottom: 20rpx;"></u-loadmore>

                    </block>

                   

                    <view class="e-empty" v-else>

                        <image src="/static/images/empty.png" mode=""></image>

                        <text>暂无兑换记录哦~</text>

                    </view>

                </view>

            </view>

        </view>

        <!-- 回到列表顶部按钮 -->

        <b-fab :defaultPost="'right'" :defaultY="100">

            <view class="fab" :xGap="40" :bottomGap="40" @tap="scrollTopData">

                <image src="/static/images/genius/go-back.png" class="scroll-top"

                    :class="{'show-img':scrollTopPage<200}"></image>

            </view>

        </b-fab>

    </view>

</template>

<script>

    import { getSession } from "@/util/storage";

    import { hex_md5 } from "@/util/md5";

    import { getVirtualCoinNumber, queryActivitySettings, queryConvertTime, queryExchangeRules, exchangeVirtualCoin, queryExchangeCoin} from "@/api/exchange.js"; // 后端接口

    import { dateFormat } from "@/common/dateFormat.js";

    export default {

        data() {

            return {

                competitionId:'', // 活动id

                page: 1,

                limit: 5,

                amount:0,//盈亏资产金额

                exchangeAsset:0,//可兑换资产额度

                exchangedAmount:0,//已兑换额度

                exchangeList:[],//兑换列表

                yibeiNum: '0' ,//可兑换积分数量

                num: '0',

                loadStatus: 'more',

                activityText: '', // 当前时间小于活动开始时间展示文本

                showStartText: false, // 是否显示当前时间小于活动开始时间展示文本

                activityStartTime: '', // 兑换活动开始时间

                activityEndTime: '', // 兑换活动结束时间

                showNoActivity: false, // 是否显示活动结束页面

                showEndText: false, // 是否显示活动结束文本

                exchangeRules: '', // 活动兑换规则文本

                isBottom: !1, //定义变量为false

                scrollTopPage: 0, // 距离顶部距离

                showExchangeImg: false, // 是否显示兑换图片

            };

        },

        watch:{

            num(val) {

                if (Number(val) > Number(this.yibeiNum)) {

                    this.$nextTick(() => {

                        this.num = this.yibeiNum

                        this.showExchangeImg = true

                    })

                } else if (Number(val) < 0 || Number(val) == 0.01) {

                    this.$nextTick(() => {

                        this.num = 0.01

                        this.showExchangeImg = true

                    })

                } else if (Number(val) > 0.01 && Number(val) < Number(this.yibeiNum)) {

                    this.showExchangeImg = true

                } else if (val == '' || Number(val) == 0) {

                    this.showExchangeImg = false

                }

            }

        },

        onLoad(options){

            window.yibeiPayCallback = (data) => {

              let t = (new Date()).getTime();

              let s = hex_md5(data + getSession("token") + this.num + this.competitionId + t);

              // 调兑换的接口

              this.updataYibei(t, s)

            }

            this.competitionId = options.id

            this.getVirtualCoinNumber()

            this.getActivitySettings()

            this.getConvertTime()

            this.getExchangeRules()

        },

        // 实时获取滚动条的位置

        onPageScroll(res) {

            this.scrollTopPage = res.scrollTop

        },

        methods:{

            // 失去焦点时输入框积分赋值

            inputBlur() {

                if (Number(this.num) == 0) {

                    this.num = '0.01'

                } else if (Number(this.num) >= Number(this.yibeiNum)) {

                    this.num = Number(this.yibeiNum)

                } else {

                    let inputNum = Number(this.num.toString().match(/^\d+(?:\.\d{0,2})?/)[0]).toString().replace(/^0+\./g,'0.') // 只能输入数字

                    if (Number(inputNum) == 0) {

                        this.num = '0.01'

                    } else {

                        this.num = Number(inputNum).toFixed(2)

                    }

                }

                this.showExchangeImg = true

            },

            // 聚焦时输入框积分赋值

            inputFocus() {

                this.num = Number(this.num)

            },

            // 积分加减

            btnClick(type) {

                if(type == 1) { //减

                    if (Number(this.num) > 0.01) {

                        this.getExchangeCoin(type)

                    }

                } else { //加

                    if(Number(this.num) < Number(this.yibeiNum)) {

                        this.getExchangeCoin(type)

                    }

                }

            },

            //回到列表顶部

            scrollTopData() {

                uni.pageScrollTo({

                    selector: ".c-header",

                    scrollTop: 0

                })

            },

            // 改变积分兑换数量

            changePayNum(e) {

                this.num = e.detail.value

            },

            // 可兑换积分计算

            getExchangeCoin(type) {

                let params = {

                    value: Number(this.num), // 原始值

                    isAdd: type == 1 ? false : true, // 是否相加,true为相加

                    changeNumber: 1, // 要加减的目标值

                    point: 2 // 限定的小数位

                }

                queryExchangeCoin(params).then(res => {

                    this.num = res.resultData

                })

            },

            // 获取积分兑换活动开始和结束时间

            getActivitySettings() {

                queryActivitySettings().then(res => {

                    this.activityStartTime = res.data.startTime

                    this.activityEndTime =  res.data.endTime

                    let nowTime = dateFormat(Date.now(), "yyyy-MM-dd hh:mm:ss")

                    let oDate1 = new Date(nowTime)

                    let oDate2 = new Date(this.activityStartTime)

                    let oDate3 = new Date(this.activityEndTime)

                    if(oDate1.getTime() < oDate2.getTime()){

                        this.showNoActivity = true

                        this.showEndText = false

                        this.showStartText = true

                    }

                    if(oDate1.getTime() > oDate3.getTime()){

                        this.showNoActivity = true

                        this.showEndText = true

                        this.showStartText = false

                    }

                })

            },

            // 获取积分兑换时间

            getConvertTime() {

                queryConvertTime().then(res => {

                    this.convertTime = res.data.exchangeTime // 积分兑换时间

                    let nowTime1 = dateFormat(Date.now(), "yyyy-MM-dd hh:mm:ss")

                    let oDate1 = new Date(nowTime1)

                    let oDate2 = new Date(this.activityStartTime)

                    let oDate3 = new Date(this.activityEndTime)

                    if(oDate1.getTime() > oDate2.getTime() && oDate1.getTime() < oDate3.getTime()){

                        this.showNoActivity = false

                    }

                })

            },

            // 获取积分兑换规则

            getExchangeRules() {

                let params = {

                    activeId: this.competitionId

                }

                queryExchangeRules(params).then(res => {

                    this.activityText = res.data.defaultPrompt

                    this.exchangeRules = res.data.rules

                })

            },

            // 获取页面盈亏资产等数据

            async getVirtualCoinNumber() {

                let res = await getVirtualCoinNumber({

                    competitionId:this.competitionId,

                    pageIndex:this.page,

                    pageSize:this.limit,

                    token: getSession("token")

                })

                this.amount = res.resultData.amountTitle

                this.exchangeAsset = res.resultData.exchangeAsset

                this.exchangedAmount = res.resultData.totalExchangedBalance

                this.yibeiNum = Number(res.resultData.accountBalanceTitle) < 0 ? '0.00' : res.resultData.accountBalanceTitle

                this.num = this.yibeiNum

                if (Number(this.yibeiNum) > 0) {

                    this.showExchangeImg = true

                } else {

                    this.showExchangeImg = false

                }

                let tempList = []

                tempList = res.resultData.data //定义第1页赋值

                if (!tempList || tempList.length == 0) { // 无数据时

                    this.exchangeList = []

                } else { //有数据时

                    this.isBottom = !1 //定义变量为false

                    this.exchangeList = this.exchangeList.concat(...tempList)

                }

                // 数据全部加载完成(停止下拉加载)

                if (this.exchangeList.length >= res.total) {

                    this.loadStatus = 'noMore'

                } else {

                    this.loadStatus = 'loading'

                }

            },

            // 点击确定兑换

            confirm() {

                // 调取原生的积分支付界面

                let isIOS = getSession("isIOS");

                let isAndroid = getSession("isAndroid");

                let obj = {

                  name: "积分兑换",

                  yibei: this.num

                };

                if (isAndroid) {

                  window.ytyJsApi.onYibeiPay(JSON.stringify(obj));

                }

                if (isIOS) {

                  window.webkit.messageHandlers.onYibeiPay.postMessage(

                    JSON.stringify(obj)

                  );

                }

            },

            // 兑换回调

            async updataYibei(t,s) {

                let res = await exchangeVirtualCoin({

                    competitionId: this.competitionId,

                    changeMoney: this.num,

                    t:t,

                    s:s,

                    matchName: '积分兑换',

                    pageSize: 10,

                    token: getSession("token")

                })

                if(res.status == 1) {

                    uni.showToast({

                        title:'兑换成功',

                        icon:'none'

                    })

                    this.exchangeList = []

                    this.isBottom = !1

                    this.page = 1

                    this.getVirtualCoinNumber()

                }else {

                    uni.showToast({

                        title: res.msg,

                        icon: 'none'

                    })

                }

               

            }

        },

        onReachBottom() {

            // 判断数据是否全部加载完

            if (!this.isBottom && this.loadStatus === 'loading') {

                this.isBottom = !0 //定义变量为true

                this.page += 1

                this.getVirtualCoinNumber()

            } else {

                this.loadStatus = 'noMore'

            }

        }

    }

</script>

<style lang="less" scoped>

.scroll-top {

    position: relative;

    width: 82rpx;

    height: 82rpx;

    border-radius: 50%;

    opacity: 1;

    transition: opacity .5s;

    -webkit-transition: opacity .5s;

    bottom: 60rpx;

}

.show-img {

    opacity: 0;

}

.noActivityBox {

    width: 100%;

    height: calc(100vh - 88rpx);

    display: flex;

    flex-direction: column;

    justify-content: center;

    align-items: center;

    .noActivityImg {

        width: 360rpx;

        height: 274rpx;

        display: block;

        background-size: 100% 100%;

    }

    .activityText {

        font-size: 26rpx;

        font-family: PingFang SC;

        font-weight: 500;

        color: #999999;

        line-height: 40rpx;

        margin-top: 32rpx;

        white-space: pre-wrap;

        text-align: center;

    }

}

view {

    line-height: 1;

}

.e-empty {

    display: flex;

    align-items: center;

    justify-content: center;

    flex-direction: column;

    height:  750rpx;

    image {

        width: 320rpx;

        height: 268rpx;

    }

    text {

        font-size: 24rpx;

        font-family: PingFang SC;

        font-weight: 500;

        color: #999999;

        margin-top: 22rpx;

    }

}

.c-content {

    width: 750rpx;

    background: #EEF3FD;

    border-radius: 20rpx 20rpx 0px 0px;

    padding: 28rpx 20rpx;

    margin-top: -26rpx;

    .c-rule{

        width: 710rpx;

        box-sizing: border-box;

        padding: 32rpx;

        margin-bottom: 20rpx;

        background-color:#fff;

        border-radius: 10rpx;

        .r-title{

            margin-bottom: 20rpx;

            display: flex;

            align-items: center;

            .t-thread{

                width: 4rpx;

                height: 22rpx;

                background: #6C8FF8;

            }

            .t-name{

                margin-left: 15rpx;

                font-size: 30rpx;

                font-weight: bold;

                color: #333333;

            }

        }

        .r-conten{

            font-size: 28rpx;

            line-height: 48rpx;

            font-weight: 500;

            color: #666666;

            white-space: pre-wrap;

        }

    }

    .c-exchange{

        box-sizing: border-box;

        padding: 0 32rpx;

        background-color:#fff;

        border-radius: 10rpx;

        .e-title{

            padding: 32rpx 0;

            display: flex;

            justify-content: space-between;

            align-items: center;

            border-bottom: 1rpx solid #EAEBEE;

            .t-left{

                display: flex;

                align-items: center;

                .t-thread{

                    width: 4rpx;

                    height: 22rpx;

                    background: #6C8FF8;

                }

                .t-name{

                    margin-left: 15rpx;

                    font-size: 30rpx;

                    font-weight: bold;

                    color: #333333;

                }

            }

            .t-right{

                font-size: 24rpx;

                color: #6C8FF8;

            }

           

        }

        .e-list {

            width: 100%;

            min-height:  750rpx;

        }

        .e-item{

            display: flex;

            align-items: center;

            justify-content: space-between;

            height: 140rpx;

            border-bottom: 1rpx solid #EAEBEE;

            .i-left{

                display: flex;

                flex-direction: column;

                .l-name{

                    font-size: 28rpx;

                    color: #333333;

                }

                .l-time{

                    font-size: 24rpx;

                    color: #999999;

                    margin-top: 16rpx;

                }

            }

            .i-right{

                font-size: 28rpx;

                font-weight: bold;

                color: #EA3F49;

            }

        }

    }

}

.c-header {

    background: url("/static/images/ve-match/m-bg6.png") no-repeat;

    background-size: 100% 100%;

    width: 750rpx;

    height: 974rpx;

    .h-grid {

        background: url("/static/images/ve-match/m-bg8.png") no-repeat;

        background-size: 100% 100%;

        width: 700rpx;

        height: 444rpx;

        margin: 0 auto;

        overflow: hidden;

        .g-tip {

            display: flex;

            align-items: center;

            justify-content: center;

            width: 370rpx;

            height: 50rpx;

            background: #3325E4;

            border-radius: 25rpx;

            font-size: 26rpx;

            font-family: PingFang SC;

            font-weight: 500;

            color: #C5C0FF;

            margin: 38rpx auto 0;

        }

        .g-check {

            display: flex;

            align-items: center;

            margin-top: 76rpx;

            height: 70rpx;

            .c-left {

                font-size: 26rpx;

                font-family: PingFang SC;

                font-weight: 500;

                color: #FFFFFF;

                margin-left: 56rpx;

            }

            .c-center {

                display: flex;

                align-items: center;

                margin-left: 18rpx;

                font-size: 26rpx;

                font-weight: 500;

                color: #FFFFFF;

               

                .c-box {

                    display: flex;

                    align-items: center;

                    justify-content: space-between;

                    width: 400rpx;

                    height: 70rpx;

                    background: #291ECC;

                    border-radius: 35rpx;

                    padding: 0 4rpx;

                   

                    font-size: 40rpx;

                    font-family: PingFang SC;

                    font-weight: 500;

                    color: #FFFFFF;

                    .b-circle {

                        display: flex;

                        // align-items: center;

                        justify-content: center;

                        width: 60rpx;

                        height: 60rpx;

                        background: #4738EE;

                        border-radius: 50%;

                        font-size: 50rpx;

                    }

                    .b-text {

                        flex: 1;

                        text-align: center;

                    }

                }

            }

            .c-right {

                font-size: 26rpx;

                font-family: PingFang SC;

                font-weight: 500;

                color: #FFFFFF;

                margin-left: 19rpx;

            }

        }

        .g-num {

            display: flex;

            width: 586rpx;

            height: 174rpx;

            margin: 60rpx auto 0;

            .n-item {

                flex:1;

                display: flex;

                align-items: center;

                justify-content: center;

                flex-direction: column;

                .l-text1 {

                    font-size: 40rpx;

                    font-family: PingFang SC;

                    font-weight: bold;

                    color: #FFFFFF;

                }

                .l-text2 {

                    font-size: 26rpx;

                    font-family: PingFang SC;

                    font-weight: 500;

                    color: #FFFFFF;

                    margin-top: 18rpx;

                }

            }

        }

    }

    .h-btn {

        width: 698rpx;

        height: 148rpx;

        margin: -36rpx auto 0;

        display: block;

    }

}

</style>

置顶组件:

<template>

    <view class="mo-fab"

    :class="isShow ? '' : 'hideView'"

    :animation="animationData"

    @touchstart="drag_start"

    @touchmove.stop.prevent="drag_move"

    @touchend.stop="drag_end"

    @touchcancel.stop="drag_end"

    >

        <view>

            <slot

            <!-- #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO || MP-BAIDU  -->

            v-if="zScopedSlots.default||zSlots.default"

            <!-- #endif -->

            <!-- #ifndef MP-WEIXIN || MP-QQ || MP-TOUTIAO || MP-BAIDU -->

            v-if="$scopedSlots.default||$slots.default"

            <!-- #endif -->

            ></slot>

            <template v-else>

                <view class="mo-fab--wrap">

                    <slot

                    <!-- #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO || MP-BAIDU  -->

                    v-if="zScopedSlots.content||zSlots.content"

                    <!-- #endif -->

                    <!-- #ifndef MP-WEIXIN || MP-QQ || MP-TOUTIAO || MP-BAIDU -->

                    v-if="$scopedSlots.content||$slots.content"

                    <!-- #endif -->

                    name="content"

                    ></slot>

                    <text v-else>示例</text>

                </view>

            </template>

        </view>

    </view>

</template>

<script>

/**

 * 一个悬浮拖拽框

 使用示例1:<moFab />

 使用示例2:<moFab>内容</moFab>

 使用示例3:<moFab><template #content>示例3</template></moFab>

 *

 */

    export default {

        name: 'moFab',

        props: {

            type: { // 悬停类型 left-right || left || right || none

                type: String,

                default: 'left-right'

            },

            defaultPost: {  // 初始化位置 left || right

                type: String,

                default: 'left'

            },

            defaultY: {  // 初始化位置距离底部的距离

                type: Number,

                default: 200

            },

            xGap: {  // 距离左右两边最小间距

                type: Number,

                default: 35

            },

            topGap: { // 距离顶部最小间距

                type: Number,

                default: 200

            },

            bottomGap: { // 距离底部最小间距

                type: Number,

                default: 80

            },

            defer: { // 是否开启惯性位移

                type: Boolean,

                default: true

            },

            deferVal: { // 惯性位移量

                type: Number,

                default: 150

            },

        },

        data() {

            return {

                fabWidth: 50,

                fabHeight: 50,

                start: [0,0],

                move: [0,0],

                pages: [0,0],

                animationData: {},

                times: [0,0],

                isShow: false,

            }

        },

        computed:{

            zScopedSlots() {

                return this.$scopedSlots;

            },

            zSlots() {

                return this.$slots;

            }

        },

        mounted() {

            this.initmove()

        },

        methods: {

            getPageHeight(){

                // px转换到rpx的比例

                const { windowWidth, windowHeight } = uni.getSystemInfoSync();

                const pxToRpxScale = 750 / windowWidth;

                this.pages = [windowWidth, windowHeight]

                return { pxToRpxScale }

            },

            initmove(){

                const { pxToRpxScale } = this.getPageHeight()

                const defaultY = this.defaultY / pxToRpxScale

                const bottomGap = this.bottomGap / pxToRpxScale

                const query = uni.createSelectorQuery().in(this);

                query.select('.mo-fab').boundingClientRect(res=>{

                    if(!res) return

                    this.fabWidth = res.width

                    this.fabHeight = res.height

                    let moveX = this.pages[0] - this.fabWidth - this.xGap / pxToRpxScale

                    let moveY = this.pages[1] - this.fabHeight - (bottomGap > defaultY ? bottomGap : defaultY )

                    if(this.defaultPost == 'left'){

                        moveX = this.xGap / pxToRpxScale

                    }

                    const dir = moveX > (this.pages[0] - this.fabWidth) / 2 ? -1 : 1

                    this.move = [moveX,moveY]

                    this.setmove({

                        duration: 0,

                        timingFunction: 'linear',

                        x: this.move[0],

                        y: this.move[1]

                    })

                    setTimeout(() => {

                        this.isShow = true;

                    }, 500)

                    this.$emit('dragInit',{dir, grid: this.move})

                }).exec();

            },

            setmove(ops){

                const { duration, timingFunction, x, y } = Object.assign({

                    duration: 0,

                    timingFunction: 'linear',

                    x: 0,

                    y: 0

                }, ops)

                let animation = uni.createAnimation({

                    duration,

                    timingFunction,

                    delay: 0,

                })

                animation.translate(x,y).step()

                this.animation = animation

                this.animationData = this.animation.export()

            },

            drag_start(event){

                const touches = event.touches[0] || event.changedTouches[0]

                this.start = [touches.clientX, touches.clientY ]

                this.times[0] = event.timeStamp

                this.$emit('dragstart',event)

            },

            drag_move(event){

                const touches = event.touches[0] || event.changedTouches[0];

                const moveX = this.move[0] - this.start[0] + touches.clientX

                const moveY = this.move[1] - this.start[1] + touches.clientY

                const dir =moveX > (this.pages[0] - this.fabWidth) / 2 ? -1 : 1

                this.setmove({

                    duration: 0,

                    timingFunction: 'linear',

                    x: moveX,

                    y: moveY

                })

                this.$emit('dragmove',{...event, dir, grid: this.move})

            },

            drag_end(event){

                const touches = event.touches[0] || event.changedTouches[0];

                this.times[1] = event.timeStamp

                const timeDiff = this.times.reduce((a,b)=>b-a, 0)

               

                const { pxToRpxScale } = this.getPageHeight()

                const xGap = this.xGap / pxToRpxScale

                const topGap = this.topGap / pxToRpxScale

                const bottomGap = this.bottomGap / pxToRpxScale

                const endX = this.pages[0] - this.fabWidth - xGap

                const endY = this.pages[1] - this.fabHeight - bottomGap

               

                const offx = touches.clientX - this.start[0]

                const offy = touches.clientY - this.start[1]

                let moveX = this.move[0] + offx

                let moveY = this.move[1] + offy

               

                if(this.defer){

                    moveX = moveX + this.getEndPost(offx,timeDiff)

                    moveY = moveY + this.getEndPost(offy,timeDiff)

                }

               

                moveY = moveY < topGap ? topGap : (moveY > endY ? endY : moveY)

               

                if(this.type == 'left'){

                    moveX = xGap

                }

                if(this.type == 'right'){

                    moveX = endX

                }

                if(this.type == 'left-right'){

                    moveX = moveX > (this.pages[0] - this.fabWidth) / 2 ? endX : xGap

                }

                if(this.type == 'none'){

                    moveX = moveX < xGap ? xGap : (moveX > endX ? endX : moveX)

                }

                const dir = moveX > (this.pages[0] - this.fabWidth) / 2 ? -1 : 1

                this.move = [moveX, moveY]

                this.setmove({

                    duration: 250,

                    timingFunction: 'ease-out',

                    x: this.move[0],

                    y: this.move[1]

                })

                this.$emit('dragend',{...event, dir, grid: this.move})

            },

            getEndPost(offset, timeDiff){

                let g = 2 * offset / Math.pow(timeDiff, 2)

                const abs = Math.abs(+ (g * 10).toFixed(4))

                g = abs < 0.01 ? 0 : g

                return g * Math.pow(this.deferVal, 2) / 2

            }

        }

    }

</script>

<style lang="scss" scoped>

    .mo-fab {

        display: block;

        position: fixed;

        top: 0;

        left: 0;

        color: #000;

        z-index: 998;

        user-select: none;

        &.hideView {

            opacity: 0;

        }

        &--wrap{

            display: flex;

            justify-content: center;

            align-items: center;

            border-radius: 50%;

            height: 100rpx;

            width: 100rpx;

            color: #fff;

            box-shadow: 0px 7rpx 18rpx 0px rgba(107, 14, 195, 0.38);

            border: 4rpx solid rgba(250, 121, 255, 0.8);

            background: linear-gradient(90deg, #CD56FF, #833AD6);

        }

    }

</style>

dateFormat.js文件方法:

/**

 * [dateFormat 时间格式化]

 * @param  {[Number,String]} [timestamp=Date.now()] [需转化的时间戳或一个能格式化的时间字符串]

 * @param  {[String]} [format='yyyy-M-d'] [需转化的时间格式]

 * yyyy年,月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q),两个字符表示按2位字符输入

 * 举例:

 * dateFormat(Date.now(), "yyyy-MM-dd hh:mm:ss") ==> 2017-04-25 16:06:06

 * dateFormat(Date.now(), "yyyy-M-d h:m:s q")    ==> 2017-4-25 16:6:6 2

 * @return {[String]}                       [格式化时间字符串]

 */

export function dateFormat(timestamp = Date.now(), format = 'yyyy-M-d') {

  return getFormatDate(getJsonDate(timestamp), format)

}

// 生成时间对象

export function getJsonDate(timestamp) {

  let time = new Date(getCorrectTime(timestamp))

  let jsonDate = {

    y: time.getFullYear(), //年

    M: time.getMonth() + 1, //月

    d: time.getDate(), //日

    h: time.getHours(), //时

    m: time.getMinutes(), //分

    s: time.getSeconds(), //秒

    q: Math.floor((time.getMonth() + 3) / 3) //季度

  }

  return jsonDate

}

// 生成格式化时间字符串

export function getFormatDate(jsonDate, format) {

  let dateStr = format.replace(/yyyy/g, jsonDate.y)

  Object.keys(jsonDate).forEach(e => {

    // 时间格式化操作

    let double = e.repeat(2)

    let num = jsonDate[e]

    if (format.includes(double)) {

      // 如果需要两位的格式化数据,则转换为两位数

      dateStr = dateStr.replace(double, getTwoDigit(num))

    } else {

      dateStr = dateStr.replace(e, num)

    }

  })

  return dateStr

}

// 数字如果为一位数,前面加0

function getTwoDigit(num) {

  return Number(num) < 10

    ? `0${num}`

    : num

}

// 对于传入时间数据的转换

function getCorrectTime(timestamp) {

  if (isNaN(timestamp)) {

    // ios日期格式兼容处理

    timestamp = timestamp.toString().includes('-')

      ? (timestamp.replace(/-/g, '/')).slice(0,19)

      : timestamp

  } else {

    timestamp = Number(timestamp)

  }

  return timestamp

}

storage.js文件getSession方法:

// add by jq

const process = {

    env:{

        PROJECT_DIR_NAME: 'product/VTS',

       

        // 如果自动获取本地ip不正确,则设置为false

        isAutoGetIp: true,

       

        // 是否随机配置本地端口号

        isRandPort: true,

       

        // 是否启用mock模拟数据

        isUseMock: false

    }

}

// projectConfig中的当前项目路径(如activities/CreditMonthExam)

const PROJECT_DIR_NAME = process.env.PROJECT_DIR_NAME.replace('/', '_')

// sessionStorage获取

export function getSession(key) {

    if(key == "searchArr"){

        let arr = getObjectValue(sessionStorage.getItem(getMixKey(key)))

        if(arr && arr.length > 0){

            return arr;

        } else {

            //ios15 searchArr数组可能太大,存储失败

            let codeList = getObjectValue(localStorage.getItem(getMixKey("searchStr")))

            if(codeList && codeList.length>0){

                let arr01 = [],

                    arr02 = [],

                    arr03 = [];

                arr01 = codeList.split(';');

                arr01.forEach(item => {

                    let obj = {};

                    arr02 = item.split(',');

                    obj.a = arr02[0];

                    obj.b = arr02[1];

                    obj.c = arr02[2];

                    obj.d = arr02[3];

                    obj.e = arr02[4];

                    obj.f = arr02[5];

                    obj.g = arr02[6];

                    obj.h = arr02[7];

                    obj.i = arr02[8];

                    arr03.push(obj);

                });

                return arr03;

            } else {

                return [];

            }

        }

    }

  return getObjectValue(sessionStorage.getItem(getMixKey(key)))

}

// 获取混合后key名

export function getMixKey(key) {

  return `${PROJECT_DIR_NAME}__${key}`

}

// 返回正确格式数据(若存储的时候为json,则直接返回json对象,否则为字符串)

// valueType 0字符类型,1json类型

export function getObjectValue(value) {

  // 防止value为null的出错情况

  let {valueType, realValue} = JSON.parse(value) || {}

  return realValue

}

md5.js文件方法:

/*

 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message

 * Digest Algorithm, as defined in RFC 1321.

 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009

 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet

 * Distributed under the BSD License

 * See http://pajhome.org.uk/crypt/md5 for more info.

 */

/*

 * Configurable variables. You may need to tweak these to be compatible with

 * the server-side, but the defaults work in most cases.

 */

var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase        */

var b64pad  = "";  /* base-64 pad character. "=" for strict RFC compliance   */

/*

 * These are the export functions you'll usually want to call

 * They take string arguments and return either hex or base-64 encoded strings

 */

export function hex_md5(s)    { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }

export function b64_md5(s)    { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }

export function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }

export function hex_hmac_md5(k, d)

  { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }

export function b64_hmac_md5(k, d)

  { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }

export function any_hmac_md5(k, d, e)

  { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*

 * Perform a simple self-test to see if the VM is working

 */

export function md5_vm_test()

{

  return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";

}

/*

 * Calculate the MD5 of a raw string

 */

export function rstr_md5(s)

{

  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));

}

/*

 * Calculate the HMAC-MD5, of a key and some data (raw strings)

 */

export function rstr_hmac_md5(key, data)

{

  var bkey = rstr2binl(key);

  if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);

  for(var i = 0; i < 16; i++)

  {

    ipad[i] = bkey[i] ^ 0x36363636;

    opad[i] = bkey[i] ^ 0x5C5C5C5C;

  }

  var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);

  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));

}

/*

 * Convert a raw string to a hex string

 */

export function rstr2hex(input)

{

  try { hexcase } catch(e) { hexcase=0; }

  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";

  var output = "";

  var x;

  for(var i = 0; i < input.length; i++)

  {

    x = input.charCodeAt(i);

    output += hex_tab.charAt((x >>> 4) & 0x0F)

           +  hex_tab.charAt( x        & 0x0F);

  }

  return output;

}

/*

 * Convert a raw string to a base-64 string

 */

export function rstr2b64(input)

{

  try { b64pad } catch(e) { b64pad=''; }

  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

  var output = "";

  var len = input.length;

  for(var i = 0; i < len; i += 3)

  {

    var triplet = (input.charCodeAt(i) << 16)

                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)

                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);

    for(var j = 0; j < 4; j++)

    {

      if(i * 8 + j * 6 > input.length * 8) output += b64pad;

      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);

    }

  }

  return output;

}

/*

 * Convert a raw string to an arbitrary string encoding

 */

export function rstr2any(input, encoding)

{

  var divisor = encoding.length;

  var i, j, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */

  var dividend = Array(Math.ceil(input.length / 2));

  for(i = 0; i < dividend.length; i++)

  {

    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);

  }

  /*

   * Repeatedly perform a long division. The binary array forms the dividend,

   * the length of the encoding is the divisor. Once computed, the quotient

   * forms the dividend for the next step. All remainders are stored for later

   * use.

   */

  var full_length = Math.ceil(input.length * 8 /

                                    (Math.log(encoding.length) / Math.log(2)));

  var remainders = Array(full_length);

  for(j = 0; j < full_length; j++)

  {

    quotient = Array();

    x = 0;

    for(i = 0; i < dividend.length; i++)

    {

      x = (x << 16) + dividend[i];

      q = Math.floor(x / divisor);

      x -= q * divisor;

      if(quotient.length > 0 || q > 0)

        quotient[quotient.length] = q;

    }

    remainders[j] = x;

    dividend = quotient;

  }

  /* Convert the remainders to the output string */

  var output = "";

  for(i = remainders.length - 1; i >= 0; i--)

    output += encoding.charAt(remainders[i]);

  return output;

}

/*

 * Encode a string as utf-8.

 * For efficiency, this assumes the input is valid utf-16.

 */

export function str2rstr_utf8(input)

{

  var output = "";

  var i = -1;

  var x, y;

  while(++i < input.length)

  {

    /* Decode utf-16 surrogate pairs */

    x = input.charCodeAt(i);

    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;

    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)

    {

      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);

      i++;

    }

    /* Encode output as utf-8 */

    if(x <= 0x7F)

      output += String.fromCharCode(x);

    else if(x <= 0x7FF)

      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),

                                    0x80 | ( x         & 0x3F));

    else if(x <= 0xFFFF)

      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),

                                    0x80 | ((x >>> 6 ) & 0x3F),

                                    0x80 | ( x         & 0x3F));

    else if(x <= 0x1FFFFF)

      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),

                                    0x80 | ((x >>> 12) & 0x3F),

                                    0x80 | ((x >>> 6 ) & 0x3F),

                                    0x80 | ( x         & 0x3F));

  }

  return output;

}

/*

 * Encode a string as utf-16

 */

export function str2rstr_utf16le(input)

{

  var output = "";

  for(var i = 0; i < input.length; i++)

    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,

                                  (input.charCodeAt(i) >>> 8) & 0xFF);

  return output;

}

export function str2rstr_utf16be(input)

{

  var output = "";

  for(var i = 0; i < input.length; i++)

    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,

                                   input.charCodeAt(i)        & 0xFF);

  return output;

}

/*

 * Convert a raw string to an array of little-endian words

 * Characters >255 have their high-byte silently ignored.

 */

export function rstr2binl(input)

{

  var output = Array(input.length >> 2);

  for(var i = 0; i < output.length; i++)

    output[i] = 0;

  for(var i = 0; i < input.length * 8; i += 8)

    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);

  return output;

}

/*

 * Convert an array of little-endian words to a string

 */

export function binl2rstr(input)

{

  var output = "";

  for(var i = 0; i < input.length * 32; i += 8)

    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);

  return output;

}

/*

 * Calculate the MD5 of an array of little-endian words, and a bit length.

 */

export function binl_md5(x, len)

{

  /* append padding */

  x[len >> 5] |= 0x80 << ((len) % 32);

  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;

  var b = -271733879;

  var c = -1732584194;

  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)

  {

    var olda = a;

    var oldb = b;

    var oldc = c;

    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);

    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);

    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);

    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);

    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);

    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);

    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);

    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);

    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);

    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);

    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);

    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);

    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);

    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);

    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);

    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);

    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);

    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);

    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);

    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);

    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);

    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);

    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);

    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);

    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);

    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);

    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);

    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);

    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);

    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);

    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);

    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);

    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);

    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);

    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);

    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);

    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);

    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);

    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);

    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);

    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);

    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);

    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);

    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);

    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);

    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);

    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);

    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);

    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);

    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);

    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);

    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);

    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);

    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);

    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);

    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);

    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);

    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);

    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);

    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);

    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);

    b = safe_add(b, oldb);

    c = safe_add(c, oldc);

    d = safe_add(d, oldd);

  }

  return Array(a, b, c, d);

}

/*

 * These export functions implement the four basic operations the algorithm uses.

 */

export function md5_cmn(q, a, b, x, s, t)

{

  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);

}

export function md5_ff(a, b, c, d, x, s, t)

{

  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);

}

export function md5_gg(a, b, c, d, x, s, t)

{

  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);

}

export function md5_hh(a, b, c, d, x, s, t)

{

  return md5_cmn(b ^ c ^ d, a, b, x, s, t);

}

export function md5_ii(a, b, c, d, x, s, t)

{

  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);

}

/*

 * Add integers, wrapping at 2^32. This uses 16-bit operations internally

 * to work around bugs in some JS interpreters.

 */

export function safe_add(x, y)

{

  var lsw = (x & 0xFFFF) + (y & 0xFFFF);

  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);

  return (msw << 16) | (lsw & 0xFFFF);

}

/*

 * Bitwise rotate a 32-bit number to the left.

 */

export function bit_rol(num, cnt)

{

  return (num << cnt) | (num >>> (32 - cnt));

}

样式仅供参考,所用到的部分图片:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值