|
@@ -123,12 +123,19 @@
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 全局消息提示组件 -->
|
|
|
+ <div v-if="showGlobalMessage" class="global-message">
|
|
|
+ <div class="message-content" :class="messageType">
|
|
|
+ {{ globalMessage }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import { reactive, ref, computed, watch, onMounted } from "vue";
|
|
|
-import { ElForm, ElMessage } from "element-plus";
|
|
|
+import { ElForm } from "element-plus";
|
|
|
import type { FormRules } from "element-plus";
|
|
|
import { login, register } from "@/API/users";
|
|
|
import { useTokenStore } from "@/stores/mytoken";
|
|
@@ -136,6 +143,11 @@ import { useI18n } from "vue-i18n";
|
|
|
import { User } from "@element-plus/icons-vue";
|
|
|
import { useRouter } from "vue-router";
|
|
|
|
|
|
+// ============ 新增状态 ============
|
|
|
+const showGlobalMessage = ref(false);
|
|
|
+const globalMessage = ref("");
|
|
|
+const messageType = ref("success"); // 消息类型: success/error
|
|
|
+
|
|
|
// ============ 类型定义 ============
|
|
|
interface LoginForm {
|
|
|
name: string;
|
|
@@ -187,6 +199,18 @@ const currentUserTypeName = computed(() =>
|
|
|
userType.value === "user" ? t("login.switchToAdmin") : t("login.switchToUser")
|
|
|
);
|
|
|
|
|
|
+// ============ 显示全局消息 ============
|
|
|
+const showMessage = (message: string, type: "success" | "error" = "success") => {
|
|
|
+ globalMessage.value = message;
|
|
|
+ messageType.value = type;
|
|
|
+ showGlobalMessage.value = true;
|
|
|
+
|
|
|
+ // 3秒后自动隐藏消息
|
|
|
+ setTimeout(() => {
|
|
|
+ showGlobalMessage.value = false;
|
|
|
+ }, 3000);
|
|
|
+};
|
|
|
+
|
|
|
// ============ 登录逻辑 ============
|
|
|
const onSubmit = async () => {
|
|
|
if (!formRef.value) return;
|
|
@@ -194,39 +218,36 @@ const onSubmit = async () => {
|
|
|
await formRef.value.validate();
|
|
|
loading.value = true;
|
|
|
|
|
|
- // 1) 这里把 username 改为 name,跟后端一致
|
|
|
const res = await login({
|
|
|
name: form.name,
|
|
|
password: form.password,
|
|
|
usertype: userType.value,
|
|
|
});
|
|
|
|
|
|
- // 2) 按你的后端返回结构取值
|
|
|
const ok = res?.data?.success === true;
|
|
|
if (!ok) {
|
|
|
- ElMessage.error(res?.data?.message || t("login.loginFailed"));
|
|
|
+ showMessage(res?.data?.message || t("login.loginFailed"), "error");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const userId = res.data.userId;
|
|
|
const name = res.data.name;
|
|
|
|
|
|
- // 3) 保存“已登录”状态(按你的 store 需要来)
|
|
|
- // 如果你的全局守卫检查 token,这里塞一个标记防止被拦截
|
|
|
store.saveToken({
|
|
|
userId,
|
|
|
name,
|
|
|
- loginType: userType.value, // 后端没返回 userType,就以当前选择为准
|
|
|
+ loginType: userType.value,
|
|
|
});
|
|
|
|
|
|
- ElMessage.success(res.data?.message || t("login.loginSuccess"));
|
|
|
+ // 使用全局消息提示
|
|
|
+ showMessage(res.data?.message || t("login.loginSuccess"));
|
|
|
|
|
|
- // 4) 跳转(建议 await,能捕获潜在错误)
|
|
|
- await router.push({ name: "selectCityAndCounty" });
|
|
|
+ // 跳转
|
|
|
+ await router.push({ name: "samplingMethodDevice1"});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
console.error("登录异常:", error);
|
|
|
- ElMessage.error(error?.response?.data?.detail || t("login.loginFailed"));
|
|
|
+ showMessage(error?.response?.data?.detail || t("login.loginFailed"), "error");
|
|
|
} finally {
|
|
|
loading.value = false;
|
|
|
}
|
|
@@ -246,15 +267,17 @@ const onRegister = async () => {
|
|
|
});
|
|
|
|
|
|
if (res.data?.message) {
|
|
|
- ElMessage.success(res.data.message);
|
|
|
+ // 使用全局消息提示
|
|
|
+ showMessage(res.data.message);
|
|
|
toggleForm();
|
|
|
} else {
|
|
|
- ElMessage.error(res.data?.message || t("register.registerFailed"));
|
|
|
+ showMessage(res.data?.message || t("register.registerFailed"), "error");
|
|
|
}
|
|
|
} catch (error: any) {
|
|
|
console.error("注册异常:", error);
|
|
|
- ElMessage.error(
|
|
|
- error?.response?.data?.detail || t("register.registerFailed")
|
|
|
+ showMessage(
|
|
|
+ error?.response?.data?.detail || t("register.registerFailed"),
|
|
|
+ "error"
|
|
|
);
|
|
|
} finally {
|
|
|
loading.value = false;
|
|
@@ -336,6 +359,7 @@ onMounted(() => {
|
|
|
display: flex;
|
|
|
height: 100vh;
|
|
|
background-color: #f6f6f6;
|
|
|
+ position: relative; /* 为全局消息组件提供定位上下文 */
|
|
|
}
|
|
|
.auth-left {
|
|
|
width: 35%;
|
|
@@ -449,4 +473,55 @@ onMounted(() => {
|
|
|
padding: 15px 10px;
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
-</style>
|
|
|
+
|
|
|
+/* 全局消息提示样式 */
|
|
|
+.global-message {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ z-index: 9999;
|
|
|
+ pointer-events: none; /* 允许点击穿透 */
|
|
|
+}
|
|
|
+
|
|
|
+.message-content {
|
|
|
+ padding: 30px 60px;
|
|
|
+ border-radius: 12px;
|
|
|
+ font-size: 48px;
|
|
|
+ font-weight: bold;
|
|
|
+ text-align: center;
|
|
|
+ animation: messageAnimation 0.5s ease-out forwards;
|
|
|
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
|
+ max-width: 80%;
|
|
|
+ word-break: break-word;
|
|
|
+}
|
|
|
+
|
|
|
+.message-content.success {
|
|
|
+ background-color: rgba(103, 194, 58, 0.9); /* 成功消息绿色背景 */
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.message-content.error {
|
|
|
+ background-color: rgba(245, 108, 108, 0.9); /* 错误消息红色背景 */
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes messageAnimation {
|
|
|
+ 0% {
|
|
|
+ transform: scale(0.5);
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+ 70% {
|
|
|
+ transform: scale(1.1);
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: scale(1);
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|