🎨 chore(web): apply ESLint and Prettier auto-fixes (baseline)

- Ran: bun run eslint:fix && bun run lint:fix
- Inserted AGPL license header via eslint-plugin-header
- Enforced no-multiple-empty-lines and other lint rules
- Formatted code using Prettier v3 (@so1ve/prettier-config)
- No functional changes; formatting-only baseline across JS/JSX files
This commit is contained in:
t0ng7u
2025-08-30 21:15:10 +08:00
parent 41cf516ec5
commit 0d57b1acd4
274 changed files with 11025 additions and 7659 deletions

View File

@@ -20,27 +20,19 @@ For commercial licensing, please contact support@quantumnous.com
import React from 'react';
import { Button } from '@douyinfe/semi-ui';
const UsersActions = ({
setShowAddUser,
t
}) => {
const UsersActions = ({ setShowAddUser, t }) => {
// Add new user
const handleAddUser = () => {
setShowAddUser(true);
};
return (
<div className="flex gap-2 w-full md:w-auto order-2 md:order-1">
<Button
className="w-full md:w-auto"
onClick={handleAddUser}
size="small"
>
<div className='flex gap-2 w-full md:w-auto order-2 md:order-1'>
<Button className='w-full md:w-auto' onClick={handleAddUser} size='small'>
{t('添加用户')}
</Button>
</div>
);
};
export default UsersActions;
export default UsersActions;

View File

@@ -70,14 +70,18 @@ const renderUsername = (text, record) => {
return <span>{text}</span>;
}
const maxLen = 10;
const displayRemark = remark.length > maxLen ? remark.slice(0, maxLen) + '…' : remark;
const displayRemark =
remark.length > maxLen ? remark.slice(0, maxLen) + '…' : remark;
return (
<Space spacing={2}>
<span>{text}</span>
<Tooltip content={remark} position="top" showArrow>
<Tag color='white' shape='circle' className="!text-xs">
<div className="flex items-center gap-1">
<div className="w-2 h-2 flex-shrink-0 rounded-full" style={{ backgroundColor: '#10b981' }} />
<Tooltip content={remark} position='top' showArrow>
<Tag color='white' shape='circle' className='!text-xs'>
<div className='flex items-center gap-1'>
<div
className='w-2 h-2 flex-shrink-0 rounded-full'
style={{ backgroundColor: '#10b981' }}
/>
{displayRemark}
</div>
</Tag>
@@ -107,18 +111,16 @@ const renderStatistics = (text, record, showEnableDisableModal, t) => {
}
const content = (
<Tag
color={tagColor}
shape='circle'
size='small'
>
<Tag color={tagColor} shape='circle' size='small'>
{tagText}
</Tag>
);
const tooltipContent = (
<div className='text-xs'>
<div>{t('调用次数')}: {renderNumber(record.request_count)}</div>
<div>
{t('调用次数')}: {renderNumber(record.request_count)}
</div>
</div>
);
@@ -173,14 +175,16 @@ const renderInviteInfo = (text, record, t) => {
return (
<div>
<Space spacing={1}>
<Tag color='white' shape='circle' className="!text-xs">
<Tag color='white' shape='circle' className='!text-xs'>
{t('邀请')}: {renderNumber(record.aff_count)}
</Tag>
<Tag color='white' shape='circle' className="!text-xs">
<Tag color='white' shape='circle' className='!text-xs'>
{t('收益')}: {renderQuota(record.aff_history_quota)}
</Tag>
<Tag color='white' shape='circle' className="!text-xs">
{record.inviter_id === 0 ? t('无邀请人') : `${t('邀请人')}: ${record.inviter_id}`}
<Tag color='white' shape='circle' className='!text-xs'>
{record.inviter_id === 0
? t('无邀请人')
: `${t('邀请人')}: ${record.inviter_id}`}
</Tag>
</Space>
</div>
@@ -190,15 +194,19 @@ const renderInviteInfo = (text, record, t) => {
/**
* Render operations column
*/
const renderOperations = (text, record, {
setEditingUser,
setShowEditUser,
showPromoteModal,
showDemoteModal,
showEnableDisableModal,
showDeleteModal,
t
}) => {
const renderOperations = (
text,
record,
{
setEditingUser,
setShowEditUser,
showPromoteModal,
showDemoteModal,
showEnableDisableModal,
showDeleteModal,
t,
},
) => {
if (record.DeletedAt !== null) {
return <></>;
}
@@ -208,14 +216,14 @@ const renderOperations = (text, record, {
{record.status === 1 ? (
<Button
type='danger'
size="small"
size='small'
onClick={() => showEnableDisableModal(record, 'disable')}
>
{t('禁用')}
</Button>
) : (
<Button
size="small"
size='small'
onClick={() => showEnableDisableModal(record, 'enable')}
>
{t('启用')}
@@ -223,7 +231,7 @@ const renderOperations = (text, record, {
)}
<Button
type='tertiary'
size="small"
size='small'
onClick={() => {
setEditingUser(record);
setShowEditUser(true);
@@ -233,21 +241,21 @@ const renderOperations = (text, record, {
</Button>
<Button
type='warning'
size="small"
size='small'
onClick={() => showPromoteModal(record)}
>
{t('提升')}
</Button>
<Button
type='secondary'
size="small"
size='small'
onClick={() => showDemoteModal(record)}
>
{t('降级')}
</Button>
<Button
type='danger'
size="small"
size='small'
onClick={() => showDeleteModal(record)}
>
{t('注销')}
@@ -266,7 +274,7 @@ export const getUsersColumns = ({
showPromoteModal,
showDemoteModal,
showEnableDisableModal,
showDeleteModal
showDeleteModal,
}) => {
return [
{
@@ -281,7 +289,8 @@ export const getUsersColumns = ({
{
title: t('状态'),
dataIndex: 'info',
render: (text, record, index) => renderStatistics(text, record, showEnableDisableModal, t),
render: (text, record, index) =>
renderStatistics(text, record, showEnableDisableModal, t),
},
{
title: t('剩余额度/总额度'),
@@ -312,15 +321,16 @@ export const getUsersColumns = ({
dataIndex: 'operate',
fixed: 'right',
width: 200,
render: (text, record, index) => renderOperations(text, record, {
setEditingUser,
setShowEditUser,
showPromoteModal,
showDemoteModal,
showEnableDisableModal,
showDeleteModal,
t
}),
render: (text, record, index) =>
renderOperations(text, record, {
setEditingUser,
setShowEditUser,
showPromoteModal,
showDemoteModal,
showEnableDisableModal,
showDeleteModal,
t,
}),
},
];
};
};

View File

@@ -26,9 +26,9 @@ const { Text } = Typography;
const UsersDescription = ({ compactMode, setCompactMode, t }) => {
return (
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full">
<div className="flex items-center text-blue-500">
<IconUserAdd className="mr-2" />
<div className='flex flex-col md:flex-row justify-between items-start md:items-center gap-2 w-full'>
<div className='flex items-center text-blue-500'>
<IconUserAdd className='mr-2' />
<Text>{t('用户管理')}</Text>
</div>
<CompactModeToggle
@@ -40,4 +40,4 @@ const UsersDescription = ({ compactMode, setCompactMode, t }) => {
);
};
export default UsersDescription;
export default UsersDescription;

View File

@@ -31,9 +31,8 @@ const UsersFilters = ({
groupOptions,
loading,
searching,
t
t,
}) => {
const formApiRef = useRef(null);
const handleReset = () => {
@@ -55,26 +54,26 @@ const UsersFilters = ({
searchUsers(1, pageSize);
}}
allowEmpty={true}
autoComplete="off"
layout="horizontal"
trigger="change"
autoComplete='off'
layout='horizontal'
trigger='change'
stopValidateWithError={false}
className="w-full md:w-auto order-1 md:order-2"
className='w-full md:w-auto order-1 md:order-2'
>
<div className="flex flex-col md:flex-row items-center gap-2 w-full md:w-auto">
<div className="relative w-full md:w-64">
<div className='flex flex-col md:flex-row items-center gap-2 w-full md:w-auto'>
<div className='relative w-full md:w-64'>
<Form.Input
field="searchKeyword"
field='searchKeyword'
prefix={<IconSearch />}
placeholder={t('支持搜索用户的 ID、用户名、显示名称和邮箱地址')}
showClear
pure
size="small"
size='small'
/>
</div>
<div className="w-full md:w-48">
<div className='w-full md:w-48'>
<Form.Select
field="searchGroup"
field='searchGroup'
placeholder={t('选择分组')}
optionList={groupOptions}
onChange={(value) => {
@@ -83,27 +82,27 @@ const UsersFilters = ({
searchUsers(1, pageSize);
}, 100);
}}
className="w-full"
className='w-full'
showClear
pure
size="small"
size='small'
/>
</div>
<div className="flex gap-2 w-full md:w-auto">
<div className='flex gap-2 w-full md:w-auto'>
<Button
type="tertiary"
htmlType="submit"
type='tertiary'
htmlType='submit'
loading={loading || searching}
className="flex-1 md:flex-initial md:w-auto"
size="small"
className='flex-1 md:flex-initial md:w-auto'
size='small'
>
{t('查询')}
</Button>
<Button
type='tertiary'
onClick={handleReset}
className="flex-1 md:flex-initial md:w-auto"
size="small"
className='flex-1 md:flex-initial md:w-auto'
size='small'
>
{t('重置')}
</Button>
@@ -113,4 +112,4 @@ const UsersFilters = ({
);
};
export default UsersFilters;
export default UsersFilters;

View File

@@ -22,7 +22,7 @@ import { Empty } from '@douyinfe/semi-ui';
import CardTable from '../../common/ui/CardTable';
import {
IllustrationNoResult,
IllustrationNoResultDark
IllustrationNoResultDark,
} from '@douyinfe/semi-illustrations';
import { getUsersColumns } from './UsersColumnDefs';
import PromoteUserModal from './modals/PromoteUserModal';
@@ -103,23 +103,21 @@ const UsersTable = (usersData) => {
showPromoteModal: showPromoteUserModal,
showDemoteModal: showDemoteUserModal,
showEnableDisableModal: showEnableDisableUserModal,
showDeleteModal: showDeleteUserModal
showDeleteModal: showDeleteUserModal,
});
}, [
t,
setEditingUser,
setShowEditUser,
]);
}, [t, setEditingUser, setShowEditUser]);
// Handle compact mode by removing fixed positioning
const tableColumns = useMemo(() => {
return compactMode ? columns.map(col => {
if (col.dataIndex === 'operate') {
const { fixed, ...rest } = col;
return rest;
}
return col;
}) : columns;
return compactMode
? columns.map((col) => {
if (col.dataIndex === 'operate') {
const { fixed, ...rest } = col;
return rest;
}
return col;
})
: columns;
}, [compactMode, columns]);
return (
@@ -143,13 +141,15 @@ const UsersTable = (usersData) => {
empty={
<Empty
image={<IllustrationNoResult style={{ width: 150, height: 150 }} />}
darkModeImage={<IllustrationNoResultDark style={{ width: 150, height: 150 }} />}
darkModeImage={
<IllustrationNoResultDark style={{ width: 150, height: 150 }} />
}
description={t('搜索无结果')}
style={{ padding: 30 }}
/>
}
className="overflow-hidden"
size="middle"
className='overflow-hidden'
size='middle'
/>
{/* Modal components */}
@@ -192,4 +192,4 @@ const UsersTable = (usersData) => {
);
};
export default UsersTable;
export default UsersTable;

View File

@@ -78,7 +78,7 @@ const UsersPage = () => {
/>
<CardPro
type="type1"
type='type1'
descriptionArea={
<UsersDescription
compactMode={compactMode}
@@ -87,11 +87,8 @@ const UsersPage = () => {
/>
}
actionsArea={
<div className="flex flex-col md:flex-row justify-between items-center gap-2 w-full">
<UsersActions
setShowAddUser={setShowAddUser}
t={t}
/>
<div className='flex flex-col md:flex-row justify-between items-center gap-2 w-full'>
<UsersActions setShowAddUser={setShowAddUser} t={t} />
<UsersFilters
formInitValues={formInitValues}
@@ -124,4 +121,4 @@ const UsersPage = () => {
);
};
export default UsersPage;
export default UsersPage;

View File

@@ -33,11 +33,7 @@ import {
Row,
Col,
} from '@douyinfe/semi-ui';
import {
IconSave,
IconClose,
IconUserAdd,
} from '@douyinfe/semi-icons';
import { IconSave, IconClose, IconUserAdd } from '@douyinfe/semi-icons';
import { useTranslation } from 'react-i18next';
const { Text, Title } = Typography;
@@ -80,8 +76,10 @@ const AddUserModal = (props) => {
placement={'left'}
title={
<Space>
<Tag color="green" shape="circle">{t('新建')}</Tag>
<Title heading={4} className="m-0">
<Tag color='green' shape='circle'>
{t('新建')}
</Tag>
<Title heading={4} className='m-0'>
{t('添加用户')}
</Title>
</Space>
@@ -90,10 +88,10 @@ const AddUserModal = (props) => {
visible={props.visible}
width={isMobile ? '100%' : 600}
footer={
<div className="flex justify-end bg-white">
<div className='flex justify-end bg-white'>
<Space>
<Button
theme="solid"
theme='solid'
onClick={() => formApiRef.current?.submitForm()}
icon={<IconSave />}
loading={loading}
@@ -101,8 +99,8 @@ const AddUserModal = (props) => {
{t('提交')}
</Button>
<Button
theme="light"
type="primary"
theme='light'
type='primary'
onClick={handleCancel}
icon={<IconClose />}
>
@@ -117,7 +115,7 @@ const AddUserModal = (props) => {
<Spin spinning={loading}>
<Form
initValues={getInitValues()}
getFormApi={(api) => formApiRef.current = api}
getFormApi={(api) => (formApiRef.current = api)}
onSubmit={submit}
onSubmitFail={(errs) => {
const first = Object.values(errs)[0];
@@ -125,15 +123,17 @@ const AddUserModal = (props) => {
formApiRef.current?.scrollToError();
}}
>
<div className="p-2">
<Card className="!rounded-2xl shadow-sm border-0">
<div className="flex items-center mb-2">
<Avatar size="small" color="blue" className="mr-2 shadow-md">
<div className='p-2'>
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='blue' className='mr-2 shadow-md'>
<IconUserAdd size={16} />
</Avatar>
<div>
<Text className="text-lg font-medium">{t('用户信息')}</Text>
<div className="text-xs text-gray-600">{t('创建新用户账户')}</div>
<Text className='text-lg font-medium'>{t('用户信息')}</Text>
<div className='text-xs text-gray-600'>
{t('创建新用户账户')}
</div>
</div>
</div>
@@ -183,4 +183,4 @@ const AddUserModal = (props) => {
);
};
export default AddUserModal;
export default AddUserModal;

View File

@@ -29,7 +29,7 @@ const DeleteUserModal = ({
activePage,
refresh,
manageUser,
t
t,
}) => {
const handleConfirm = async () => {
await manageUser(user.id, 'delete', user);
@@ -48,11 +48,11 @@ const DeleteUserModal = ({
visible={visible}
onCancel={onCancel}
onOk={handleConfirm}
type="danger"
type='danger'
>
{t('相当于删除用户,此修改将不可逆')}
</Modal>
);
};
export default DeleteUserModal;
export default DeleteUserModal;

View File

@@ -27,11 +27,11 @@ const DemoteUserModal = ({ visible, onCancel, onConfirm, user, t }) => {
visible={visible}
onCancel={onCancel}
onOk={onConfirm}
type="warning"
type='warning'
>
{t('此操作将降低用户的权限级别')}
</Modal>
);
};
export default DemoteUserModal;
export default DemoteUserModal;

View File

@@ -83,9 +83,7 @@ const EditUserModal = (props) => {
const fetchGroups = async () => {
try {
let res = await API.get(`/api/group/`);
setGroupOptions(
res.data.data.map((g) => ({ label: g, value: g }))
);
setGroupOptions(res.data.data.map((g) => ({ label: g, value: g })));
} catch (e) {
showError(e.message);
}
@@ -116,7 +114,8 @@ const EditUserModal = (props) => {
const submit = async (values) => {
setLoading(true);
let payload = { ...values };
if (typeof payload.quota === 'string') payload.quota = parseInt(payload.quota) || 0;
if (typeof payload.quota === 'string')
payload.quota = parseInt(payload.quota) || 0;
if (userId) {
payload.id = parseInt(userId);
}
@@ -194,12 +193,20 @@ const EditUserModal = (props) => {
{/* 基本信息 */}
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='blue' className='mr-2 shadow-md'>
<Avatar
size='small'
color='blue'
className='mr-2 shadow-md'
>
<IconUser size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('基本信息')}</Text>
<div className='text-xs text-gray-600'>{t('用户的基本账户信息')}</div>
<Text className='text-lg font-medium'>
{t('基本信息')}
</Text>
<div className='text-xs text-gray-600'>
{t('用户的基本账户信息')}
</div>
</div>
</div>
@@ -248,12 +255,20 @@ const EditUserModal = (props) => {
{userId && (
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='green' className='mr-2 shadow-md'>
<Avatar
size='small'
color='green'
className='mr-2 shadow-md'
>
<IconUserGroup size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('权限设置')}</Text>
<div className='text-xs text-gray-600'>{t('用户分组和额度管理')}</div>
<Text className='text-lg font-medium'>
{t('权限设置')}
</Text>
<div className='text-xs text-gray-600'>
{t('用户分组和额度管理')}
</div>
</div>
</div>
@@ -297,23 +312,41 @@ const EditUserModal = (props) => {
{/* 绑定信息 */}
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='purple' className='mr-2 shadow-md'>
<Avatar
size='small'
color='purple'
className='mr-2 shadow-md'
>
<IconLink size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('绑定信息')}</Text>
<div className='text-xs text-gray-600'>{t('第三方账户绑定状态(只读)')}</div>
<Text className='text-lg font-medium'>
{t('绑定信息')}
</Text>
<div className='text-xs text-gray-600'>
{t('第三方账户绑定状态(只读)')}
</div>
</div>
</div>
<Row gutter={12}>
{['github_id', 'oidc_id', 'wechat_id', 'email', 'telegram_id'].map((field) => (
{[
'github_id',
'oidc_id',
'wechat_id',
'email',
'telegram_id',
].map((field) => (
<Col span={24} key={field}>
<Form.Input
field={field}
label={t(`已绑定的 ${field.replace('_id', '').toUpperCase()} 账户`)}
label={t(
`已绑定的 ${field.replace('_id', '').toUpperCase()} 账户`,
)}
readonly
placeholder={t('此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改')}
placeholder={t(
'此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改',
)}
/>
</Col>
))}
@@ -343,16 +376,14 @@ const EditUserModal = (props) => {
}
>
<div className='mb-4'>
{
(() => {
const current = formApiRef.current?.getValue('quota') || 0;
return (
<Text type='secondary' className='block mb-2'>
{`${t('新额度:')}${renderQuota(current)} + ${renderQuota(addQuotaLocal)} = ${renderQuota(current + parseInt(addQuotaLocal || 0))}`}
</Text>
);
})()
}
{(() => {
const current = formApiRef.current?.getValue('quota') || 0;
return (
<Text type='secondary' className='block mb-2'>
{`${t('新额度:')}${renderQuota(current)} + ${renderQuota(addQuotaLocal)} = ${renderQuota(current + parseInt(addQuotaLocal || 0))}`}
</Text>
);
})()}
</div>
<InputNumber
placeholder={t('需要添加的额度(支持负数)')}
@@ -367,4 +398,4 @@ const EditUserModal = (props) => {
);
};
export default EditUserModal;
export default EditUserModal;

View File

@@ -26,7 +26,7 @@ const EnableDisableUserModal = ({
onConfirm,
user,
action,
t
t,
}) => {
const isDisable = action === 'disable';
@@ -36,11 +36,11 @@ const EnableDisableUserModal = ({
visible={visible}
onCancel={onCancel}
onOk={onConfirm}
type="warning"
type='warning'
>
{isDisable ? t('此操作将禁用用户账户') : t('此操作将启用用户账户')}
</Modal>
);
};
export default EnableDisableUserModal;
export default EnableDisableUserModal;

View File

@@ -27,11 +27,11 @@ const PromoteUserModal = ({ visible, onCancel, onConfirm, user, t }) => {
visible={visible}
onCancel={onCancel}
onOk={onConfirm}
type="warning"
type='warning'
>
{t('此操作将提升用户的权限级别')}
</Modal>
);
};
export default PromoteUserModal;
export default PromoteUserModal;