♻️refactor: Modernize edit and add user components with unified design system
- Refactor EditRedemption.js with card-based layout and modern UI components - Refactor EditUser.js with three-section card layout (basic info, permissions, bindings) - Refactor AddUser.js with modern card design and improved user experience - Replace inline styles with Tailwind CSS 3 classes throughout all components - Add semantic icons (IconUser, IconKey, IconGift, IconCreditCard, etc.) for better UX - Implement unified header design with colored tags and consistent typography - Replace deprecated Title imports with destructured Typography components - Add proper internationalization support with useTranslation hook - Standardize form layouts with consistent spacing, rounded corners, and shadows - Improve button styling with rounded design and loading states - Fix IconTicket import error by replacing with existing IconGift - Enhance modal designs with modern styling and icon integration - Ensure responsive design consistency across all edit/add components This update brings all user management interfaces in line with the modern design system established in EditToken.js, providing a cohesive and professional user experience.
This commit is contained in:
@@ -1,9 +1,28 @@
|
||||
import React, { useState } from 'react';
|
||||
import { API, isMobile, showError, showSuccess } from '../../helpers';
|
||||
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
|
||||
import { Button, Input, SideSheet, Space, Spin } from '@douyinfe/semi-ui';
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
SideSheet,
|
||||
Space,
|
||||
Spin,
|
||||
Typography,
|
||||
Card,
|
||||
Tag
|
||||
} from '@douyinfe/semi-ui';
|
||||
import {
|
||||
IconUser,
|
||||
IconSave,
|
||||
IconClose,
|
||||
IconKey,
|
||||
IconUserAdd,
|
||||
} from '@douyinfe/semi-icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
const AddUser = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const originInputs = {
|
||||
username: '',
|
||||
display_name: '',
|
||||
@@ -21,13 +40,13 @@ const AddUser = (props) => {
|
||||
setLoading(true);
|
||||
if (inputs.username === '' || inputs.password === '') {
|
||||
setLoading(false);
|
||||
showError('用户名和密码不能为空!');
|
||||
showError(t('用户名和密码不能为空!'));
|
||||
return;
|
||||
}
|
||||
const res = await API.post(`/api/user/`, inputs);
|
||||
const { success, message } = res.data;
|
||||
if (success) {
|
||||
showSuccess('用户账户创建成功!');
|
||||
showSuccess(t('用户账户创建成功!'));
|
||||
setInputs(originInputs);
|
||||
props.refresh();
|
||||
props.handleClose();
|
||||
@@ -45,63 +64,113 @@ const AddUser = (props) => {
|
||||
<>
|
||||
<SideSheet
|
||||
placement={'left'}
|
||||
title={<Title level={3}>{'添加用户'}</Title>}
|
||||
headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
|
||||
bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
|
||||
title={
|
||||
<Space>
|
||||
<Tag color="green" shape="circle">{t('新建')}</Tag>
|
||||
<Title heading={4} className="m-0">
|
||||
{t('添加用户')}
|
||||
</Title>
|
||||
</Space>
|
||||
}
|
||||
headerStyle={{
|
||||
borderBottom: '1px solid var(--semi-color-border)',
|
||||
padding: '24px'
|
||||
}}
|
||||
bodyStyle={{
|
||||
backgroundColor: 'var(--semi-color-bg-0)',
|
||||
padding: '0'
|
||||
}}
|
||||
visible={props.visible}
|
||||
width={isMobile() ? '100%' : 600}
|
||||
footer={
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<div className="flex justify-end bg-white">
|
||||
<Space>
|
||||
<Button theme='solid' size={'large'} onClick={submit}>
|
||||
提交
|
||||
<Button
|
||||
theme="solid"
|
||||
size="large"
|
||||
className="!rounded-full"
|
||||
onClick={submit}
|
||||
icon={<IconSave />}
|
||||
loading={loading}
|
||||
>
|
||||
{t('提交')}
|
||||
</Button>
|
||||
<Button
|
||||
theme='solid'
|
||||
size={'large'}
|
||||
type={'tertiary'}
|
||||
theme="light"
|
||||
size="large"
|
||||
className="!rounded-full"
|
||||
type="primary"
|
||||
onClick={handleCancel}
|
||||
icon={<IconClose />}
|
||||
>
|
||||
取消
|
||||
{t('取消')}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
}
|
||||
closeIcon={null}
|
||||
onCancel={() => handleCancel()}
|
||||
width={isMobile() ? '100%' : 600}
|
||||
>
|
||||
<Spin spinning={loading}>
|
||||
<Input
|
||||
style={{ marginTop: 20 }}
|
||||
label='用户名'
|
||||
name='username'
|
||||
addonBefore={'用户名'}
|
||||
placeholder={'请输入用户名'}
|
||||
onChange={(value) => handleInputChange('username', value)}
|
||||
value={username}
|
||||
autoComplete='off'
|
||||
/>
|
||||
<Input
|
||||
style={{ marginTop: 20 }}
|
||||
addonBefore={'显示名'}
|
||||
label='显示名称'
|
||||
name='display_name'
|
||||
autoComplete='off'
|
||||
placeholder={'请输入显示名称'}
|
||||
onChange={(value) => handleInputChange('display_name', value)}
|
||||
value={display_name}
|
||||
/>
|
||||
<Input
|
||||
style={{ marginTop: 20 }}
|
||||
label='密 码'
|
||||
name='password'
|
||||
type={'password'}
|
||||
addonBefore={'密码'}
|
||||
placeholder={'请输入密码'}
|
||||
onChange={(value) => handleInputChange('password', value)}
|
||||
value={password}
|
||||
autoComplete='off'
|
||||
/>
|
||||
<div className="p-6">
|
||||
<Card className="!rounded-2xl shadow-sm border-0">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="w-10 h-10 rounded-full bg-green-50 flex items-center justify-center mr-4">
|
||||
<IconUserAdd size="large" className="text-green-500" />
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-lg font-medium">{t('用户信息')}</Text>
|
||||
<div className="text-gray-500 text-sm">{t('创建新用户账户')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Text strong className="block mb-2">{t('用户名')}</Text>
|
||||
<Input
|
||||
placeholder={t('请输入用户名')}
|
||||
onChange={(value) => handleInputChange('username', value)}
|
||||
value={username}
|
||||
autoComplete="off"
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconUser />}
|
||||
showClear
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text strong className="block mb-2">{t('显示名称')}</Text>
|
||||
<Input
|
||||
placeholder={t('请输入显示名称')}
|
||||
onChange={(value) => handleInputChange('display_name', value)}
|
||||
value={display_name}
|
||||
autoComplete="off"
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconUser />}
|
||||
showClear
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text strong className="block mb-2">{t('密码')}</Text>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={t('请输入密码')}
|
||||
onChange={(value) => handleInputChange('password', value)}
|
||||
value={password}
|
||||
autoComplete="off"
|
||||
size="large"
|
||||
className="!rounded-lg"
|
||||
prefix={<IconKey />}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Spin>
|
||||
</SideSheet>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user