feat(前端): 统一表单组件样式并添加数据库迁移文档

refactor(前端): 提取表单样式到共享配置文件
docs: 添加数据库迁移说明到README
This commit is contained in:
zhang1106
2026-03-05 10:41:49 +08:00
parent 61d9b0ebab
commit 56f59cf5b8
6 changed files with 493 additions and 65 deletions
+23 -13
View File
@@ -16,6 +16,15 @@ import {
} from 'antd';
import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
import axios from 'axios';
import {
inputStyles,
selectStyles,
textAreaStyles,
inputNumberStyles,
filterInputStyles,
inputPlaceholders,
inputValidationRules,
} from '../styles/deviceManagementStyles';
const { Option } = Select;
@@ -183,18 +192,19 @@ function CategoryManagement() {
<Card size="small" style={{ marginBottom: 16 }}>
<Space>
<Input
placeholder="搜索分类名称、描述"
style={{ width: 300 }}
placeholder={inputPlaceholders.searchCategory}
style={{ ...inputStyles.search, width: 300 }}
value={keyword}
onChange={e => setKeyword(e.target.value)}
allowClear
prefix={<SearchOutlined />}
/>
<Select value={status} onChange={setStatus} style={{ width: 120 }}>
<Select value={status} onChange={setStatus} style={{ ...selectStyles.base, width: 120 }}>
<Option value="all">所有状态</Option>
<Option value="active">启用</Option>
<Option value="inactive">停用</Option>
</Select>
<Button onClick={() => fetchCategories()}>刷新</Button>
<Button onClick={() => fetchCategories()} style={{ height: '40px', borderRadius: '10px' }}>刷新</Button>
</Space>
</Card>
@@ -221,30 +231,30 @@ function CategoryManagement() {
name="name"
label="分类名称"
rules={[
{ required: true, message: '请输入分类名称' },
{ max: 50, message: '分类名称不能超过50个字符' },
inputValidationRules.required('请输入分类名称'),
inputValidationRules.maxLength(50, '分类名称不能超过50个字符'),
]}
>
<Input placeholder="请输入分类名称" />
<Input placeholder="请输入分类名称" style={inputStyles.form} />
</Form.Item>
<Form.Item name="description" label="描述">
<Input.TextArea rows={3} placeholder="请输入分类描述" maxLength={200} showCount />
<Input.TextArea rows={3} placeholder={inputPlaceholders.description} maxLength={200} showCount style={textAreaStyles.base} />
</Form.Item>
<Form.Item name="sortOrder" label="排序">
<InputNumber min={0} placeholder="数值越小越靠前" style={{ width: '100%' }} />
<InputNumber min={0} placeholder="数值越小越靠前" style={inputNumberStyles.base} />
</Form.Item>
<Form.Item name="status" label="状态" rules={[{ required: true, message: '请选择状态' }]}>
<Select>
<Form.Item name="status" label="状态" rules={[inputValidationRules.required('请选择状态')]}>
<Select style={selectStyles.base}>
<Option value="active">启用</Option>
<Option value="inactive">停用</Option>
</Select>
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
<Button type="primary" htmlType="submit" style={{ height: '40px', borderRadius: '10px' }}>
{editingCategory ? '更新' : '创建'}
</Button>
<Button onClick={handleCancel}>取消</Button>
<Button onClick={handleCancel} style={{ height: '40px', borderRadius: '10px' }}>取消</Button>
</Space>
</Form.Item>
</Form>
+22 -11
View File
@@ -38,6 +38,15 @@ import {
import axios from 'axios';
import dayjs from 'dayjs';
import * as XLSX from 'xlsx';
import {
inputStyles,
selectStyles,
textAreaStyles,
filterInputStyles,
datePickerStyles,
inputPlaceholders,
inputValidationRules,
} from '../styles/deviceManagementStyles';
const { RangePicker } = DatePicker;
const { Option } = Select;
@@ -575,8 +584,8 @@ function ConsumableLogs() {
<Card size="small" style={{ marginBottom: 16 }}>
<Space wrap>
<Input
placeholder="搜索耗材ID"
style={{ width: 200 }}
placeholder={inputPlaceholders.consumableId}
style={{ ...inputStyles.search, width: 200 }}
allowClear
value={filters.consumableId}
onChange={e => handleFilterChange('consumableId', e.target.value)}
@@ -586,7 +595,7 @@ function ConsumableLogs() {
mode="multiple"
value={filters.operationType}
onChange={value => handleFilterChange('operationType', value)}
style={{ width: 200 }}
style={{ ...selectStyles.base, width: 200 }}
placeholder="选择操作类型"
allowClear
maxTagCount="responsive"
@@ -602,7 +611,8 @@ function ConsumableLogs() {
<RangePicker
value={filters.dateRange}
onChange={dates => handleFilterChange('dateRange', dates)}
placeholder={['开始日期', '结束日期']}
placeholder={inputPlaceholders.dateRange}
style={datePickerStyles.range}
/>
<Button
icon={<HistoryOutlined />}
@@ -610,6 +620,7 @@ function ConsumableLogs() {
setFilters({ operationType: ['in', 'out'], consumableId: '', dateRange: null });
fetchLogs(1, pagination.pageSize);
}}
style={{ height: '40px', borderRadius: '10px' }}
>
重置筛选
</Button>
@@ -631,11 +642,11 @@ function ConsumableLogs() {
],
}}
>
<Button icon={<DownloadOutlined />}>
<Button icon={<DownloadOutlined />} style={{ height: '40px', borderRadius: '10px' }}>
导出 <DownOutlined />
</Button>
</Dropdown>
<Button icon={<UploadOutlined />} onClick={() => setImportModalVisible(true)}>
<Button icon={<UploadOutlined />} onClick={() => setImportModalVisible(true)} style={{ height: '40px', borderRadius: '10px' }}>
导入
</Button>
</Space>
@@ -720,20 +731,20 @@ function ConsumableLogs() {
>
<Form form={form} layout="vertical" onFinish={handleEditSubmit}>
<Form.Item label="操作原因" name="reason">
<Input.TextArea rows={2} placeholder="请输入操作原因" />
<Input.TextArea rows={2} placeholder={inputPlaceholders.reason} style={textAreaStyles.base} />
</Form.Item>
<Form.Item label="备注" name="notes">
<Input.TextArea rows={3} placeholder="请输入备注信息" />
<Input.TextArea rows={3} placeholder={inputPlaceholders.notes} style={textAreaStyles.base} />
</Form.Item>
<Form.Item
label="修改原因"
name="modificationReason"
rules={[{ required: true, message: '请输入修改原因' }]}
rules={[inputValidationRules.required('请输入修改原因')]}
>
<Input.TextArea rows={2} placeholder="请输入修改原因(必填)" />
<Input.TextArea rows={2} placeholder="请输入修改原因(必填)" style={textAreaStyles.base} />
</Form.Item>
<Form.Item label="修改人" name="operator">
<Input placeholder="请输入修改人姓名" />
<Input placeholder={inputPlaceholders.operator} style={inputStyles.form} />
</Form.Item>
</Form>
</Modal>
+48 -37
View File
@@ -46,6 +46,15 @@ import {
} from '@ant-design/icons';
import axios from 'axios';
import { motion, AnimatePresence } from 'framer-motion';
import {
inputStyles,
selectStyles,
inputNumberStyles,
textAreaStyles,
filterInputStyles,
inputPlaceholders,
inputValidationRules,
} from '../styles/deviceManagementStyles';
const { Option } = Select;
const { Text, Title } = Typography;
@@ -871,26 +880,27 @@ function ConsumableManagement() {
>
<Row gutter={[16, 16]} align="middle">
<Col xs={24} sm={12} md={8} lg={8}>
<div style={{ marginBottom: '6px', fontSize: '13px', color: designTokens.colors.neutral[600], fontWeight: 500 }}>
<div style={filterInputStyles.container}>
搜索
</div>
<Input
placeholder="搜索耗材ID、名称、分类、供应商"
placeholder={inputPlaceholders.searchConsumable}
value={keyword}
onChange={e => handleSearch(e.target.value)}
onPressEnter={() => fetchConsumables()}
prefix={<SearchOutlined style={{ color: designTokens.colors.neutral[400] }} />}
allowClear
style={filterInputStyles.input}
/>
</Col>
<Col xs={24} sm={12} md={6} lg={5}>
<div style={{ marginBottom: '6px', fontSize: '13px', color: designTokens.colors.neutral[600], fontWeight: 500 }}>
<div style={filterInputStyles.container}>
分类
</div>
<Select
placeholder="选择分类"
style={{ width: '100%' }}
placeholder={inputPlaceholders.category}
style={filterInputStyles.select}
value={category}
onChange={setCategory}
allowClear
@@ -905,12 +915,12 @@ function ConsumableManagement() {
</Col>
<Col xs={24} sm={12} md={6} lg={5}>
<div style={{ marginBottom: '6px', fontSize: '13px', color: designTokens.colors.neutral[600], fontWeight: 500 }}>
<div style={filterInputStyles.container}>
状态
</div>
<Select
placeholder="选择状态"
style={{ width: '100%' }}
style={filterInputStyles.select}
value={status}
onChange={setStatus}
>
@@ -931,6 +941,7 @@ function ConsumableManagement() {
background: designTokens.colors.primary.gradient,
border: 'none',
borderRadius: designTokens.borderRadius.sm,
height: '40px',
}}
>
筛选
@@ -939,7 +950,7 @@ function ConsumableManagement() {
<Button
icon={<ClearOutlined />}
onClick={handleReset}
style={{ borderRadius: designTokens.borderRadius.sm }}
style={{ borderRadius: designTokens.borderRadius.sm, height: '40px' }}
/>
</Tooltip>
</Space>
@@ -1092,17 +1103,17 @@ function ConsumableManagement() {
<Form form={form} layout="vertical" onFinish={handleSubmit} style={{ marginTop: '16px' }}>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="name" label="名称" rules={[{ required: true, message: '请输入名称' }]}>
<Input placeholder="请输入耗材名称" />
<Form.Item name="name" label="名称" rules={[inputValidationRules.required('请输入名称')]}>
<Input placeholder={inputPlaceholders.consumableName} style={inputStyles.form} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="category"
label="分类"
rules={[{ required: true, message: '请选择分类' }]}
rules={[inputValidationRules.required('请选择分类')]}
>
<Select placeholder="请选择分类" allowClear>
<Select placeholder={inputPlaceholders.category} allowClear style={selectStyles.base}>
{categories.map(cat => (
<Option key={cat.id} value={cat.name}>
{cat.name}
@@ -1118,28 +1129,28 @@ function ConsumableManagement() {
<Form.Item
name="unit"
label="单位"
rules={[{ required: true, message: '请输入单位' }]}
rules={[inputValidationRules.required('请输入单位')]}
initialValue="个"
>
<Input placeholder="如: 个、盒、卷、箱" />
<Input placeholder={inputPlaceholders.unit} style={inputStyles.form} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="currentStock"
label="当前库存"
rules={[{ required: true, message: '请输入当前库存' }]}
rules={[inputValidationRules.required('请输入当前库存')]}
>
<InputNumber min={0} style={{ width: '100%' }} placeholder="请输入当前库存" />
<InputNumber min={0} style={inputNumberStyles.base} placeholder={inputPlaceholders.stock} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="minStock"
label="最小库存"
rules={[{ required: true, message: '请输入最小库存' }]}
rules={[inputValidationRules.required('请输入最小库存')]}
>
<InputNumber min={0} style={{ width: '100%' }} placeholder="请输入最小库存" />
<InputNumber min={0} style={inputNumberStyles.base} placeholder={inputPlaceholders.minStock} />
</Form.Item>
</Col>
</Row>
@@ -1163,9 +1174,9 @@ function ConsumableManagement() {
<Form.Item
name="maxStock"
noStyle
rules={[{ required: true, message: '请输入最大库存' }]}
rules={[inputValidationRules.required('请输入最大库存')]}
>
<InputNumber min={0} style={{ width: '100%' }} placeholder="请输入最大库存" />
<InputNumber min={0} style={inputNumberStyles.base} placeholder={inputPlaceholders.maxStock} />
</Form.Item>
)}
</Space>
@@ -1177,8 +1188,8 @@ function ConsumableManagement() {
min={0}
step={0.01}
precision={2}
style={{ width: '100%' }}
placeholder="请输入单价"
style={inputNumberStyles.base}
placeholder={inputPlaceholders.unitPrice}
prefix="¥"
/>
</Form.Item>
@@ -1188,18 +1199,18 @@ function ConsumableManagement() {
<Row gutter={16}>
<Col span={12}>
<Form.Item name="supplier" label="供应商">
<Input placeholder="请输入供应商" />
<Input placeholder={inputPlaceholders.supplier} style={inputStyles.form} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="location" label="存放位置">
<Input placeholder="如: A柜-01层、B区货架3" />
<Input placeholder={inputPlaceholders.location} style={inputStyles.form} />
</Form.Item>
</Col>
</Row>
<Form.Item name="description" label="描述">
<TextArea rows={3} placeholder="请输入描述信息" />
<TextArea rows={3} placeholder={inputPlaceholders.description} style={textAreaStyles.base} />
</Form.Item>
<Form.Item label={
@@ -1289,8 +1300,8 @@ function ConsumableManagement() {
)}
</Form.Item>
<Form.Item name="status" label="状态" rules={[{ required: true, message: '请选择状态' }]}>
<Select placeholder="请选择状态">
<Form.Item name="status" label="状态" rules={[inputValidationRules.required('请选择状态')]}>
<Select placeholder="请选择状态" style={selectStyles.base}>
<Option value="active">启用</Option>
<Option value="inactive">停用</Option>
</Select>
@@ -1478,10 +1489,10 @@ function ConsumableManagement() {
>
<Form form={stockForm} layout="vertical" onFinish={handleStockSubmit} style={{ marginTop: '16px' }}>
<Form.Item name="consumableId" label="耗材ID">
<Input disabled />
<Input disabled style={{ ...inputStyles.form, ...inputStyles.disabled }} />
</Form.Item>
<Form.Item name="consumableName" label="耗材名称">
<Input disabled />
<Input disabled style={{ ...inputStyles.form, ...inputStyles.disabled }} />
</Form.Item>
{stockType === 'out' && stockRecord?.snList && stockRecord.snList.length > 0 && (
@@ -1500,7 +1511,7 @@ function ConsumableManagement() {
allowClear
value={snSearchKeyword}
onChange={e => setSnSearchKeyword(e.target.value)}
style={{ marginBottom: '8px' }}
style={{ ...inputStyles.search, marginBottom: '8px' }}
/>
<Space size="small" style={{ marginBottom: '8px' }}>
<Button
@@ -1576,8 +1587,8 @@ function ConsumableManagement() {
<Form.Item name="snList" label="入库SN序列号(可选)">
<Select
mode="tags"
style={{ width: '100%' }}
placeholder="输入SN后按回车添加"
style={selectStyles.base}
placeholder={inputPlaceholders.snList}
tokenSeparators={[',', '\n']}
/>
</Form.Item>
@@ -1586,23 +1597,23 @@ function ConsumableManagement() {
<Form.Item
name="quantity"
label="数量"
rules={[{ required: true, message: '请输入数量' }]}
rules={[inputValidationRules.required('请输入数量')]}
>
<InputNumber
min={1}
max={stockType === 'out' && stockRecord?.snList?.length > 0 ? stockRecord.snList.length : undefined}
style={{ width: '100%' }}
style={inputNumberStyles.base}
placeholder="请输入数量"
/>
</Form.Item>
<Form.Item name="operator" label="操作人">
<Input placeholder="请输入操作人姓名" />
<Input placeholder={inputPlaceholders.operator} style={inputStyles.form} />
</Form.Item>
<Form.Item name="reason" label={stockType === 'in' ? '入库原因' : '出库原因'}>
<Input placeholder={stockType === 'in' ? '如: 采购入库' : '如: 部门领用、报损出库'} />
<Input placeholder={stockType === 'in' ? '如: 采购入库' : '如: 部门领用、报损出库'} style={inputStyles.form} />
</Form.Item>
<Form.Item name="notes" label="备注">
<TextArea rows={2} placeholder="请输入备注信息" />
<TextArea rows={2} placeholder={inputPlaceholders.notes} style={textAreaStyles.base} />
</Form.Item>
<Form.Item>
<Space>
+9 -3
View File
@@ -38,6 +38,11 @@ import styled from 'styled-components';
import dayjs from 'dayjs';
import api from '../api';
import { message } from 'antd';
import {
selectStyles,
datePickerStyles,
inputPlaceholders,
} from '../styles/deviceManagementStyles';
const { Title, Text } = Typography;
const { RangePicker } = DatePicker;
@@ -762,8 +767,9 @@ const ConsumableStatistics = () => {
<RangePicker
value={dateRange}
onChange={setDateRange}
style={{ width: '100%' }}
style={datePickerStyles.range}
allowClear={false}
placeholder={inputPlaceholders.dateRange}
/>
</Col>
<Col xs={24} sm={12} md={8} lg={6}>
@@ -774,7 +780,7 @@ const ConsumableStatistics = () => {
<Select
value={categoryFilter}
onChange={setCategoryFilter}
style={{ width: '100%' }}
style={selectStyles.base}
placeholder="选择类别"
>
<Option value="all">全部类别</Option>
@@ -791,7 +797,7 @@ const ConsumableStatistics = () => {
onClick={loadStatistics}
loading={loading}
style={{
height: 40,
height: '40px',
borderRadius: designTokens.borderRadius.medium,
background: designTokens.colors.primary.gradient,
border: 'none',
@@ -450,6 +450,369 @@ export const resizableTitleStyles = {
},
};
// ============================================
// 输入框统一样式配置
// ============================================
// 输入框基础样式
export const inputStyles = {
// 基础输入框样式
base: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
transition: `all ${transitions.fast}`,
},
// 搜索输入框样式
search: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
transition: `all ${transitions.fast}`,
backgroundColor: colors.background.primary,
},
// 表单输入框样式
form: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
transition: `all ${transitions.fast}`,
},
// 小尺寸输入框
small: {
height: '32px',
borderRadius: borderRadius.small,
fontSize: '13px',
},
// 大尺寸输入框
large: {
height: '48px',
borderRadius: borderRadius.medium,
fontSize: '16px',
},
// 禁用状态
disabled: {
backgroundColor: colors.background.tertiary,
color: colors.text.tertiary,
cursor: 'not-allowed',
},
// 错误状态
error: {
borderColor: colors.error.main,
boxShadow: `0 0 0 2px ${colors.error.main}20`,
},
// 焦点状态
focus: {
borderColor: colors.primary.main,
boxShadow: `0 0 0 3px ${colors.primary.main}15`,
},
};
// Select 选择器样式
export const selectStyles = {
// 基础选择器样式
base: {
height: '40px',
borderRadius: borderRadius.medium,
fontSize: '14px',
},
// 小尺寸选择器
small: {
height: '32px',
borderRadius: borderRadius.small,
fontSize: '13px',
},
// 大尺寸选择器
large: {
height: '48px',
borderRadius: borderRadius.medium,
fontSize: '16px',
},
// 下拉菜单样式
dropdown: {
borderRadius: borderRadius.medium,
boxShadow: shadows.large,
border: `1px solid ${colors.border.light}`,
},
// 选项样式
option: {
padding: '8px 12px',
fontSize: '14px',
transition: `background-color ${transitions.fast}`,
},
};
// InputNumber 数字输入框样式
export const inputNumberStyles = {
// 基础样式
base: {
width: '100%',
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
},
// 小尺寸
small: {
height: '32px',
borderRadius: borderRadius.small,
fontSize: '13px',
},
// 大尺寸
large: {
height: '48px',
borderRadius: borderRadius.medium,
fontSize: '16px',
},
};
// TextArea 文本域样式
export const textAreaStyles = {
// 基础样式
base: {
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
padding: '10px 12px',
transition: `all ${transitions.fast}`,
resize: 'vertical',
minHeight: '80px',
},
// 小尺寸
small: {
fontSize: '13px',
padding: '8px 10px',
minHeight: '60px',
},
// 大尺寸
large: {
fontSize: '16px',
padding: '12px 14px',
minHeight: '100px',
},
};
// DatePicker 日期选择器样式
export const datePickerStyles = {
// 基础样式
base: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
width: '100%',
},
// 小尺寸
small: {
height: '32px',
borderRadius: borderRadius.small,
fontSize: '13px',
},
// 大尺寸
large: {
height: '48px',
borderRadius: borderRadius.medium,
fontSize: '16px',
},
// 范围选择器
range: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
},
};
// 表单标签样式
export const formLabelStyles = {
// 基础标签样式
base: {
fontSize: '14px',
fontWeight: '500',
color: colors.text.primary,
marginBottom: '6px',
display: 'block',
},
// 必填标签样式
required: {
fontSize: '14px',
fontWeight: '500',
color: colors.text.primary,
marginBottom: '6px',
},
// 小标签
small: {
fontSize: '13px',
fontWeight: '500',
color: colors.text.secondary,
marginBottom: '4px',
},
};
// 表单项样式
export const formItemStyles = {
// 基础表单项
base: {
marginBottom: '20px',
},
// 紧凑表单项
compact: {
marginBottom: '12px',
},
// 错误状态
error: {
marginBottom: '20px',
},
// 错误提示文字
errorText: {
color: colors.error.main,
fontSize: '12px',
marginTop: '4px',
display: 'flex',
alignItems: 'center',
gap: '4px',
},
};
// 过滤器区域输入框样式
export const filterInputStyles = {
// 过滤器输入框容器
container: {
marginBottom: '6px',
fontSize: '13px',
color: colors.text.secondary,
fontWeight: '500',
},
// 过滤器输入框
input: {
height: '40px',
borderRadius: borderRadius.medium,
border: `1px solid ${colors.border.light}`,
fontSize: '14px',
width: '100%',
},
// 过滤器选择器
select: {
height: '40px',
borderRadius: borderRadius.medium,
fontSize: '14px',
width: '100%',
},
};
// 输入框验证规则配置
export const inputValidationRules = {
// 必填规则
required: (message = '此字段为必填项') => ({
required: true,
message,
}),
// 最大长度规则
maxLength: (max, message) => ({
max,
message: message || `不能超过${max}个字符`,
}),
// 最小长度规则
minLength: (min, message) => ({
min,
message: message || `不能少于${min}个字符`,
}),
// 数字范围规则
numberRange: (min, max, message) => ({
type: 'number',
min,
max,
message: message || `数值应在${min}${max}之间`,
}),
// 正整数规则
positiveInteger: () => ({
pattern: /^\d+$/,
message: '请输入正整数',
}),
// 价格规则(两位小数)
price: () => ({
pattern: /^\d+(\.\d{1,2})?$/,
message: '请输入有效的价格(最多两位小数)',
}),
// 邮箱规则
email: () => ({
type: 'email',
message: '请输入有效的邮箱地址',
}),
// 手机号规则
phone: () => ({
pattern: /^1[3-9]\d{9}$/,
message: '请输入有效的手机号码',
}),
};
// 输入框占位符文本配置
export const inputPlaceholders = {
// 耗材相关
consumableName: '请输入耗材名称',
consumableId: '请输入耗材ID',
category: '请选择分类',
unit: '如: 个、盒、卷、箱',
stock: '请输入库存数量',
minStock: '请输入最小库存',
maxStock: '请输入最大库存',
unitPrice: '请输入单价',
supplier: '请输入供应商名称',
location: '如: A柜-01层、B区货架3',
description: '请输入描述信息',
operator: '请输入操作人姓名',
reason: '请输入原因',
notes: '请输入备注信息',
snList: '输入SN后按回车添加',
// 搜索相关
search: '搜索...',
searchConsumable: '搜索耗材ID、名称、分类、供应商',
searchCategory: '搜索分类名称、描述',
// 日期相关
dateRange: ['开始日期', '结束日期'],
// 通用
select: '请选择',
input: '请输入',
};
// CSS-in-JS 样式字符串生成函数
export const generateGlobalStyles = tokens => `
.device-modal .ant-modal-close {