2025-09-17 10:19:20 +08:00

324 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- 遮罩层 -->
<div
v-if="visible"
class="dialog-mask"
@click="handleCancel"
></div>
<!-- 弹窗主体 -->
<div
v-if="visible"
class="dialog-container"
>
<div class="dialog-box">
<!-- 标题区域 -->
<div class="dialog-header">
<h3 class="dialog-title">{{ title }}</h3>
<button
class="dialog-close"
@click="handleCancel"
aria-label="关闭"
>
<span>×</span>
</button>
</div>
<!-- 内容区域 -->
<div class="dialog-body">
<!-- 工号输入 -->
<div class="form-item">
<label class="form-label">用户工号</label>
<input
type="text"
v-model.trim="userId"
class="form-input"
placeholder="请输入用户工号"
@keyup.enter="handleConfirm"
>
</div>
<!-- 密码输入 -->
<div class="form-item">
<label class="form-label">密码</label>
<input
type="password"
v-model="password"
class="form-input"
placeholder="请输入密码"
@keyup.enter="handleConfirm"
>
</div>
<!-- 错误提示 -->
<p v-if="errorMsg" class="error-message">{{ errorMsg }}</p>
</div>
<!-- 按钮区域 -->
<div class="dialog-footer">
<button
class="btn btn-cancel"
@click="handleCancel"
>
取消
</button>
<button
class="btn btn-confirm"
@click="handleConfirm"
:disabled="!userId || !password"
>
确认验证
</button>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits, ref, watch } from 'vue';
// 组件属性
const props = defineProps({
// 控制弹窗显示/隐藏
visible: {
type: Boolean,
default: false
},
// 弹窗标题(由外部参数控制)
title: {
type: String,
default: '用户身份验证'
},
// 验证规则(可选,由外部传入)
validationRules: {
type: Object,
default: () => ({
// 工号最小长度
userIdMinLength: 3,
// 密码最小长度
passwordMinLength: 6
})
}
});
// 组件事件
const emit = defineEmits([
'update:visible', // 控制弹窗显示状态
'onConfirm', // 验证成功回调
'onCancel' // 取消验证回调
]);
// 表单数据
const userId = ref('');
const password = ref('');
const errorMsg = ref('');
// 监听弹窗显示状态,重置表单
watch(
() => props.visible,
(newVal) => {
if (newVal) {
// 打开弹窗时重置表单
userId.value = '';
password.value = '';
errorMsg.value = '';
}
}
);
// 处理确认验证
const handleConfirm = () => {
// 基础验证
if (!userId.value) {
errorMsg.value = '请输入用户工号';
return;
}
if (!password.value) {
errorMsg.value = '请输入密码';
return;
}
// 应用外部传入的验证规则
if (userId.value.length < props.validationRules.userIdMinLength) {
errorMsg.value = `工号长度不能少于${props.validationRules.userIdMinLength}位`;
return;
}
if (password.value.length < props.validationRules.passwordMinLength) {
errorMsg.value = `密码长度不能少于${props.validationRules.passwordMinLength}位`;
return;
}
// 验证通过,返回用户工号
emit('onConfirm', {
userId: userId.value,
password: password.value
});
// 关闭弹窗
emit('update:visible', false);
};
// 处理取消
const handleCancel = () => {
emit('onCancel');
emit('update:visible', false);
};
</script>
<style scoped>
/* 遮罩层 */
.dialog-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
transition: opacity 0.3s;
}
/* 弹窗容器 */
.dialog-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
/* 弹窗主体 */
.dialog-box {
width: 100%;
max-width: 400px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
overflow: hidden;
}
/* 标题区域 */
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
background-color: #f9fafb;
}
.dialog-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.dialog-close {
padding: 0;
background: transparent;
border: none;
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.2s;
}
.dialog-close:hover {
color: #333;
}
/* 内容区域 */
.dialog-body {
padding: 24px 20px;
}
.form-item {
margin-bottom: 16px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-size: 14px;
color: #666;
}
.form-input {
width: 100%;
padding: 10px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
transition: border-color 0.2s;
}
.form-input:focus {
outline: none;
border-color: #4096ff;
box-shadow: 0 0 0 2px rgba(64, 150, 255, 0.2);
}
.error-message {
margin: 8px 0 0;
color: #f56c6c;
font-size: 12px;
line-height: 1.5;
}
/* 按钮区域 */
.dialog-footer {
display: flex;
justify-content: flex-end;
padding: 12px 20px;
border-top: 1px solid #f0f0f0;
background-color: #f9fafb;
}
.btn {
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.btn-cancel {
margin-right: 10px;
border: 1px solid #dcdfe6;
background-color: #fff;
color: #606266;
}
.btn-cancel:hover {
background-color: #f5f7fa;
border-color: #c0c4cc;
}
.btn-confirm {
border: 1px solid #4096ff;
background-color: #4096ff;
color: #fff;
}
.btn-confirm:hover {
background-color: #66b1ff;
border-color: #66b1ff;
}
.btn-confirm:disabled {
opacity: 0.6;
cursor: not-allowed;
background-color: #4096ff;
border-color: #4096ff;
}
</style>