更新记录

1.0.0(2023-10-07)

可根据后端格式自定义步骤条内容,自行改插件代码来展示步骤条当前节点的颜色,目前定义的颜色有完成、审核中、未通过、通过四种状态,可以自定重新定义状态颜色


平台兼容性

Vue2 Vue3
×
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
× × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari
× × ×

步骤条流程组件

组件使用vue3开发兼容微信小程序、H5、pc端,pc端需调整样式单位

使用示例

<template>
    <div class="container_right">
        <p class="title" v-if="props.title">{{ props.title }}</p>

        <div class="timeline_box">
            <ul>

                <li class="font_h6 timeline_list_item" :class="{
                    'timeline_pass': item.workOrderBizStatus === 'INSTALLATION_TECHNOLOGY|PASS',
                    'timeline_reject': item.workOrderBizStatus === 'INSTALLATION_TECHNOLOGY|REJECT',
                    'timeline_finish': item.workOrderBizStatus === 'OPERATOR|FINISH'
                }" v-for="(item, index) in data" :key="index">
                    <!-- 若传值可使用props.data或自定义 -->
                    <div class="timeline_timeLine">
                        <div class="timeline_timeLine_point">
                            <!-- <image style="width: 20rpx; height: 20rpx;" mode="scaleToFill" :src="imgUrl"></image> -->
                            <!-- <img src={u21718Img} class=" timeline_icon" /> -->
                        </div>
                        <div class="timeline_timeLine_line"></div>
                    </div>
                    <div class="timeline_container">
                        <div class="conter_box">
                            <div class="timeline_left text_bold">{{ workOrderBizStatusMap[item.workOrderBizStatus] }}{{
                                item.actionType === 'APPOINTMENT' ? "(约车)" : '' }}
                            </div>
                            <div class="timeline_right text_bold">{{ item.startTime }}</div>
                        </div>
                        <div class="conter_box">
                            <div class="timeline_left">操作人 </div>
                            <div class="timeline_right">{{ item.handlerName || '--' }}</div>
                        </div>
                        <div class="conter_box">
                            <div class="timeline_left">备注 </div>
                            <div class="timeline_right">{{ item.remark || '--' }}</div>
                        </div>
                        <template v-if="item.actionType === 'APPOINTMENT'">
                            <div class="conter_box">
                                <div class="timeline_left">联系人 </div>
                                <div class="timeline_right">{{ item.contactName }}</div>
                            </div>

                            <div class="conter_box">
                                <div class="timeline_left">预约时间 </div>
                                <div class="timeline_right">{{ item.appointmentTime }}</div>
                            </div>

                            <div class="conter_box">
                                <div class="timeline_left">预约地址 </div>
                                <div class="timeline_right">{{ item.appointmentAddress }}</div>
                            </div>
                        </template>

                        <template v-if="item.handlerContentJson && JSON.parse(item.handlerContentJson)?.patrolModels"
                            v-for="(it, i) in JSON.parse(item.handlerContentJson)?.patrolModels">
                            <div class="conter_box">
                                <div class="timeline_left">故障问题:</div>
                                <div class="timeline_right">{{ it.faultType || '--' }}</div>
                            </div>
                            <div class="conter_box">
                                <div class="timeline_left">是否更换零件</div>
                                <div class="timeline_right">{{ it.isChangePart ? '是' : '否' || '--' }}</div>
                            </div>
                            <div class="conter_box">
                                <div class="timeline_left">更换零件名称</div>
                                <div class="timeline_right">{{ it.partName || '--' }}</div>
                            </div>
                            <div class="conter_box">
                                <div class="timeline_left">描述</div>
                                <div class="timeline_right">{{ it.description || '--' }}</div>
                            </div>
                        </template>

                        <view v-if="item.handlerContentJson" class="conter_box_image">
                            <view class="timeline_left">附件</view>
                            <view class="conter_box_image_item">
                                <view v-if="item.deliveryType === 1 || item.deliveryType === 2 || item.deliveryType === 4"
                                    class="image_item">
                                    <view style="margin-bottom: 20rpx;" @click="previewImage(it.url)"
                                        v-for="(it, index) in JSON.parse(item.handlerContentJson).allImages" :key="index">
                                        <image mode="scaleToFill" style="width: 174rpx;height: 174rpx;border-radius: 8rpx;"
                                            :src="it.url"></image>
                                        <view class="timeline_left timeline_left_name">{{ it.fieldName }}</view>
                                    </view>

                                </view>
                                <view v-if="item.deliveryType === 3" class="image_item">
                                    <view style="margin-bottom: 20rpx;" @click="previewImage(it.url)"
                                        v-for="(it, index) in JSON.parse(item.handlerContentJson).allImages" :key="index">
                                        <image mode="scaleToFill" style="width: 174rpx;height: 174rpx;border-radius: 8rpx;"
                                            :src="it.url"></image>
                                        <view class="timeline_left timeline_left_name">{{ it.fieldName }}</view>
                                    </view>
                                    <view style="margin-bottom: 20rpx;" @click="previewImage(it.url)"
                                        v-for="(it, index) in JSON.parse(item.handlerContentJson).updateImages"
                                        :key="index">
                                        <image mode="scaleToFill" style="width: 174rpx;height: 174rpx;border-radius: 8rpx;"
                                            :src="it.url"></image>
                                        <view class="timeline_left timeline_left_name">{{ it.fieldName }}</view>
                                    </view>
                                </view>
                            </view>
                        </view>

                    </div>
                </li>
            </ul>
        </div>
    </div>
</template>

<script setup lang="ts">
import { workOrderBizStatusMap } from '@/enums/index'
type Props = {
    data: any,
    title: string
}
const props = defineProps<Props>()

const data = [
    {

        finishTime: "2023-09-14 14:35:17",
        handlerContentJson: null,
        handlerId: "1698599287165333506",
        handlerName: "xxx",
        id: "1702209168411787266",
        remark: null,
        startTime: "2023-09-14 14:34:26",
        workOrderBizStatus: "OPERATOR|PROCESSING",
    }, {
        afterSaleName: "xxx",
        currentNodeOptUserRoleType: "SERVICE_PROVIDER",
        deliveryType: 1,
        finishTime: "2023-09-14 14:38:03",
        handlerContentJson: null,
        handlerId: "1698981756778655745",
        handlerName: "xxx",
        id: "1702210004378517506",
        remark: "开始接单安装单测试",
        serviceProviderName: "xxx",
        startTime: "2023-09-14 14:37:45",
        workOrderBizStatus: "INSTALLATION_TECHNOLOGY|REJECT",
    },
    {
        actionReasonType: "不喜欢",
        actionType: "REJECT",
        afterSaleName: "xxx",
        currentNodeOptUserRoleType: "SERVICE_PROVIDER",
        deliveryType: 1,
        finishTime: "2023-09-14 14:39:37",
        handlerId: "1698600798050103298",
        handlerName: "陈应林",
        id: "1702210333413277698",
        remark: null,
        serviceProviderName: "xxx",
        startTime: "2023-09-14 14:39:04",
        workOrderBizStatus: "INSTALLATION_TECHNOLOGY|PASS",
    },
    {
        afterSaleName: "xxx",
        currentNodeOptUserRoleType: "OPERATOR",
        finishTime: "2023-09-14 14:34:26",
        id: "1702209159314341890",
        remark: "新增售后工单的---描述;运维人员:xxx",
        serviceProviderName: "xxx",
        startTime: "2023-09-14 14:34:24",
        workOrderBizStatus: "OPERATOR|FINISH",
    },
]

//预览图片
const previewImage = (url: string) => {
    const urls = [];
    urls.push(url)
    uni.previewImage({
        current: urls[0],
        urls: urls,
        indicator: "number"
    })
}

</script>
<style lang="scss" scoped>
.container_right {
    padding: 20rpx;
    border-radius: 16rpx;
    background-color: #fff;
}

.title {
    margin-bottom: 30rpx;
    font-size: 34rpx;
    font-weight: 600;
}

.ac {
    border: 2rpx solid #f00;

    :focus {
        outline: #FF0000 solid 4rpx;
    }
}

.timeline_box {

    .timeline_list_item {
        list-style-type: none;
        display: flex;

        .timeline_timeLine {
            width: 32rpx;
            position: relative;
            top: 8rpx;
            display: flex;
            flex-direction: column;
            align-items: center;

            .timeline_timeLine_point {
                width: 20rpx;
                height: 20rpx;
                background: #FFFFFF;
                border: 4rpx solid #0E5DD4;
                border-radius: 50%;
                // background-color: var(--line);
                position: relative;
                z-index: 9;

                .timeline_icon {
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    font-size: 24rpx;
                    line-height: 24rpx;
                }
            }

            .timeline_timeLine_line {
                width: 6rpx;
                height: 100%;
                position: absolute;
                top: 0;
                left: 50%;
                transform: translateX(-50%);
                background: #eee;

                background-position: left;
                background-size: 4rpx 12rpx;
                background-repeat: repeat-y;
            }
        }

        .timeline_container {
            flex: 1;
            padding: 10rpx 20rpx;
            background: #f5f5f5;
            border-radius: 12rpx;
            margin: 12rpx 0px 12rpx 12rpx;

            .text_bold {
                font-weight: bold;
                font-size: 28rpx;
            }

            .conter_box {
                display: flex;
                justify-content: space-between;
                font-size: 24rpx;
                line-height: 48rpx;

                .conter_box:hover {
                    color: red;
                }

                .timeline_right {
                    font-size: 24rpx;
                    color: #333;
                    display: flex;
                    align-items: center;

                    .timeline_right_ico {
                        font-size: 24rpx;
                        margin-right: 3px;
                        color: #ea9c47;
                    }

                    .timeline_right_text {
                        font-size: 26rpx;
                        font-weight: 700;
                        color: #333;
                    }
                }
            }

            .timeline_corpName {
                color: #333;
            }

        }
    }

    .timeline_pass {
        .timeline_timeLine_point {
            width: 20rpx;
            height: 20rpx;
            background: #FFFFFF;
            border: 4rpx solid #00B042 !important;
            border-radius: 50%;
            position: relative;
            z-index: 9;

            .timeline_icon {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                font-size: 24rpx;
                line-height: 24rpx;
            }
        }
    }

    .timeline_finish {
        .timeline_timeLine_point {
            border: 4rpx solid #B3B5B9 !important;
        }
    }

    .timeline_reject {
        .timeline_timeLine_point {
            width: 20rpx;
            height: 20rpx;
            background: #FFFFFF;
            border: 4rpx solid #f00 !important;
            border-radius: 50%;
            position: relative;
            z-index: 9;

            .timeline_icon {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                font-size: 24rpx;
                line-height: 24rpx;
            }
        }
    }
}

.conter_box_image {
    .conter_box_image_item {
        .image_item {
            display: flex;
            flex-wrap: wrap;

            &>view:not(:nth-child(3n)) {
                margin-right: 30rpx;
            }
        }

    }
}

.timeline_left_name {
    width: 174rpx;
    text-align: center;
    font-size: 20rpx;
}
</style>

根据后端返回的字段类型来展示步骤原点颜色,或自定义步骤原点颜色

通过状态

'timeline_pass': item.workOrderBizStatus === 'INSTALLATION_TECHNOLOGY|PASS'

拒绝状态

'timeline_reject': item.workOrderBizStatus === 'INSTALLATION_TECHNOLOGY|REJECT'

完成状态

'timeline_finish': item.workOrderBizStatus === 'OPERATOR|FINISH'

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问