2 07.封装通用弹框表单组件

  • 封装组件

src/components/FormDrawer.vue

<template>
    <el-drawer 
        v-model="showDrawer" 
        :title=title 
        :size=size
        :close-on-click-modal="true"
        :destroy-on-close="destroyOnClose"
        >

        <div class="formDrawer">
            <div class="body">
                <slot></slot>
            </div>
            <div class="actions">
                <el-button type="primary" @click="submit" :loading="loading">{{ confirmText }}</el-button>
                <el-button type="default" @click="close">取消</el-button>
            </div>
        </div>

    </el-drawer>
</template>


<script setup>
    import { ref } from 'vue'
    const showDrawer = ref(false)

    // 打开
    const open = ()=> showDrawer.value = true

    // 关闭
    const close = ()=> showDrawer.value = false

    // 提交加载
    const loading = ref(false)
    const showLoading = ()=>loading.value = true
    const hideLoading = ()=>loading.value = false

    // 向父组件暴露方法
    defineExpose({
        open,
        close,
        showLoading,
        hideLoading
    })

    // 传参
    const props = defineProps({
        title: String,
        size:{
            type:String,
            default: '45%'
        },
        destroyOnClose: {
            type:Boolean,
            default: false
        },
        confirmText: {
            type:String,
            default: '提交'
        }
    })


    // 提交
    const emit = defineEmits(['submit'])
    const submit = ()=> emit("submit")

    
</script>



<style>
    .formDrawer{
        width: 100%;
        height: 100%;
        position: relative;
        @apply flex flex-col;
    }

    .formDrawer .body{
        flex: 1;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 50px;
        overflow-y: auto;
    }

    .formDrawer .actions{
        height: 50px;
        @apply mt-auto flex items-center;
    }
</style>
  • 头部组件

  • src/layouts/components/FHeader.vue

<template>
    <div class="f-header">
        <span class="logo">
            <el-icon class="mr-1"><eleme-filled></eleme-filled></el-icon>
            Vue+Vite编程
        </span>
        <el-icon class="icon-btn"><fold /></el-icon>
        <el-tooltip effect="dark" content="刷新" placement="bottom">
            <el-icon class="icon-btn" @click="handleRefresh"><refresh /></el-icon>
        </el-tooltip>
        


        <div class="ml-auto flex items-center">
            <el-tooltip effect="dark" content="全屏" placement="bottom">
                <el-icon  class="icon-btn" @click="toggle">
                    <full-screen v-if="!isFullscreen"/>
                    <aim v-else/>
                </el-icon>
            </el-tooltip>
            <el-dropdown class="dropdown" @command="handleCommand">
                <span class="flex items-center text-light-50">
                    <el-avatar class="mr-2" :size="25" :src="$store.state.user.avatar"></el-avatar>
                    {{ $store.state.user.username }}
                    <el-icon class="el-icon--right"> <arrow-down /></el-icon>
                </span>
                <template #dropdown>
                    <el-dropdown-menu>
                        <el-dropdown-item command="rePassword">修改密码</el-dropdown-item>
                        <el-dropdown-item command="logout">退出登录</el-dropdown-item>
                    </el-dropdown-menu>
                </template>
        </el-dropdown>
        </div>
    </div>


<!-- 修改密码 Start -->

    <form-drawer ref="formDrawerRef" title="修改密码" destroyOnClose @submit="onSubmit">

        <el-form  ref="formRef" :rules="rules" :model="form" label-width="80px" size="small">
            <el-form-item prop="oldpassword" label="旧密码">
                <el-input v-model="form.oldpassword" placeholder="请输入旧密码">
                    <template #prefix>
                        <el-icon><User /></el-icon>
                    </template>
                </el-input>
            </el-form-item>
            <el-form-item prop="password" label="新密码">
                <el-input type="password" v-model="form.password" placeholder="请输入新密码" show-password>
                    <template #prefix>
                        <el-icon><Lock /></el-icon>
                    </template>
                </el-input>
            </el-form-item>
            <el-form-item prop="repassword" label="确认密码">
                <el-input type="password" v-model="form.repassword" placeholder="请输入确认密码" show-password>
                    <template #prefix>
                        <el-icon><Lock /></el-icon>
                    </template>
                </el-input>
            </el-form-item>
        </el-form>

    </form-drawer>
    
<!-- 修改密码 End -->
</template>


<script setup>
import { ref,reactive } from 'vue'
import FormDrawer from '~/components/FormDrawer.vue'
import { logout,updatepassword } from "~/api/manager"
import { showModal,toast } from "~/composables/util"
import { useRouter } from "vue-router"
import { useStore } from "vuex"
import { useFullscreen } from '@vueuse/core'
const { 
    // 是否全屏状态
    isFullscreen, 
    toggle 
} = useFullscreen()



const store = useStore()
const router = useRouter()

// do not use same name with ref
const form = reactive({
  oldpassword: '',
  password: '',
  repassword: '',
  
})

// 定义验证规则
const rules = {
    oldpassword: [
        {
            required: true,
            message: '旧密码不能为空',
            trigger: 'blur',
        },
    ],
    password: [
        {
            required: true,
            message: '新密码不能为空',
            trigger: 'blur',
        },
    ],
    repassword: [
        {
            required: true,
            message: '确认密码不能为空',
            trigger: 'blur',
        },
    ]
}

// 点击登录验证
const formDrawerRef = ref(null)
const formRef = ref(null)


const onSubmit = () => {
    formRef.value.validate((valid) => {
        if (!valid) {
            console.log('error')
        }

        // 加载动画
        formDrawerRef.value.showLoading()

        updatepassword(form).then(res=>{
            toast('修改密码成功,请重新登录')
            store.dispatch('logout')
            router.push('/login')
        }).finally(()=>{
            formDrawerRef.value.hideLoading()
        })
        
    })
}



// 修改密码

const handleCommand = (c) =>{
    switch (c) {
        case "logout":
            handleLogout()
            break;

        case "rePassword":
            // showDrawer.value = true
            formDrawerRef.value.open()
            break;
    }
}


// 刷新
const handleRefresh = () => location.reload()


function handleLogout(){
    showModal("是否要退出登录?").then(res=>{
        logout()
        .finally(()=>{
            // 退出
            store.dispatch('logout')
            // 跳转回登录页
            router.push('/login')
            // 提示退出登录成功
            toast('退出登录成功')
        })
    })
}

</script>

<style>
.f-header{
    @apply flex items-center bg-indigo-500 text-light-50 fixed top-0 left-0 right-0;
    height: 64px;
}

.logo{
    width: 250px;
    @apply flex justify-center items-center text-xl font-thin;
}

.icon-btn{
    @apply flex justify-center items-center;
    width: 42px;
    height: 64px;
    cursor: pointer;
}

.icon-btn:hover{
    @apply bg-indigo-600;
}

.f-header .dropdown{
    height: 64x;
    cursor: pointer;
    @apply flex justify-center items-center mx-5;
}
</style>

Last updated