ERPTurbo_Client/packages/app-client/src/pages/public/login/index.tsx
shenyifei ea3cfca7d6 style(components): 统一弹窗样式并添加图标优化
- 为多个 Popup 组件添加统一的动画持续时间和最小高度样式
- 在多个表单标题和标签前添加相应功能图标提升可读性
- 引入 Icon 组件并在合适位置应用
- 调整部分组件导入顺序以符合规范
- 优化表格列渲染逻辑以支持图标显示
- 修复部分 JSX 结构以改善布局展示效果
2025-11-19 22:23:46 +08:00

212 lines
6.8 KiB
TypeScript
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.

import { Button, Input, Popup, SafeArea, Toast } from "@nutui/nutui-react-taro";
import { useEffect, useState } from "react";
import auth from "@/services/auth";
import { userStore } from "@/store/user-store";
import Taro from "@tarojs/taro";
import { aesEncrypt } from "@/utils/aes";
import Captcha from "@/components/captcha";
import { Image, Text, View } from "@tarojs/components";
import base from "@/hocs/base";
import { Icon } from "@/components";
import dayjs from "dayjs";
import { APP_VERSION } from "@/constant";
export default base(function Page() {
const setUser = userStore((state) => state.setUser);
const [showBasic, setShowBasic] = useState<boolean>(false);
const [username, setUsername] = useState<string>();
const [password, setPassword] = useState<string>();
const [channel, setChannel] = useState<BusinessAPI.ChannelVO>();
const initChannel = async () => {
const { data } = await auth.channel.selectChannelByDomain({
domain: "operation.erp.qilincloud168.com",
});
setChannel(data.data);
};
useEffect(() => {
initChannel().then();
}, []);
return (
<View
style={{
//@ts-ignore
"--nutui-input-padding": 0,
}}
>
<Popup
duration={150}
style={{
minHeight: "auto",
}}
visible={showBasic}
onClose={() => {
setShowBasic(false);
}}
>
<Captcha
handleClick={async (token: string) => {
const formData = {
token: token,
username: username!,
password: aesEncrypt(password!),
};
const { data } = await auth.userAuth.passwordLogin(formData);
if (data.success) {
await setUser();
setShowBasic(false);
Taro.reLaunch({
url: `/pages/main/index/index`,
});
}
}}
/>
</Popup>
<View className="flex flex-1 flex-col items-center justify-center px-4 pb-20">
<View className="mt-16 mb-8 w-full max-w-md text-center">
{/* Logo展示区域 */}
<View className="mb-4 flex justify-center">
{channel?.logo && (
<Image src={channel.logo} className="h-16 w-16" />
)}
</View>
<View className="mb-4 text-xl font-bold text-gray-900">
{channel?.title}
</View>
<View className="mx-auto h-px w-24 bg-gray-200"></View>
</View>
<View className="flex w-full max-w-md flex-col gap-4">
<View>
<View className="mb-2 block text-sm font-bold text-gray-900">
</View>
<View className="border-primary-200 flex w-full flex-row items-center justify-between rounded-xl border-4 border-gray-300 pr-4">
<View className="flex size-10 items-center justify-center">
<Icon
name={"user"}
size={24}
color={"var(--color-neutral-darkest)"}
/>
</View>
<Input
type="text"
id="username"
name="username"
style={{
// @ts-ignore
"--nutui-input-font-size": "var(--text-sm)",
"--nutui-input-lineheight":
"var(--tw-leading, var(--text-sm--line-height))",
"--nutui-color-title": "#9CA3AF",
}}
placeholder="请输入您的手机号"
value={username}
onChange={(value) => {
setUsername(value);
}}
/>
</View>
</View>
<View>
<View className="mb-2 block text-sm font-bold text-gray-900">
</View>
<View className="border-primary-200 flex w-full flex-row items-center justify-between rounded-xl border-4 border-gray-300 pr-4">
<View className="flex size-10 items-center justify-center">
<Icon
name={"lock"}
size={24}
color={"var(--color-neutral-darkest)"}
/>
</View>
<Input
style={{
// @ts-ignore
"--nutui-input-font-size": "var(--text-sm)",
"--nutui-input-lineheight":
"var(--tw-leading, var(--text-sm--line-height))",
"--nutui-color-title": "#9CA3AF",
}}
type="password"
id="password"
name="password"
placeholder="请输入您的密码"
value={password}
onChange={(value) => {
setPassword(value);
}}
/>
</View>
</View>
<Button
block
size={"xlarge"}
type={"primary"}
onClick={async () => {
if (!username || !password) {
Toast.show("toast", {
title: "",
content: "请输入手机号和密码",
icon: "warn",
});
return;
}
if (username.trim() === "" || password.trim() === "") {
Toast.show("toast", {
title: "",
content: "请输入手机号和密码",
icon: "warn",
});
return;
}
// 密码强度校验
const passwordRegex =
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
if (!passwordRegex.test(password)) {
Toast.show("toast", {
title: "",
content:
"密码必须至少8个字符包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符",
icon: "warn",
});
return;
}
setShowBasic(true);
}}
>
</Button>
<View className="pt-2 text-center">
<Text className="text-sm text-gray-600 hover:text-gray-800">
</Text>
</View>
</View>
</View>
<View className="fixed bottom-0 flex w-full flex-col py-4 text-center">
<Text className="text-xs text-gray-500">{APP_VERSION}</Text>
<Text className="mt-1 text-xs text-gray-500">
© {dayjs().format("YYYY")} {channel?.technicalSupport}
</Text>
<SafeArea position={"bottom"} />
</View>
<SafeArea position={"bottom"} />
</View>
);
});