Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
A
audit_material_manage
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
audit_material_manage
Commits
a4933ad8
Commit
a4933ad8
authored
Sep 03, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refine material center controls and surfaces
parent
811086b9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
27 additions
and
48 deletions
+27
-48
xinyuan-design-system.md
docs/xinyuan-design-system.md
+15
-0
DataTable.jsx
src/components/DataTable.jsx
+3
-19
XinyuanAutocomplete.jsx
src/components/XinyuanAutocomplete.jsx
+9
-0
index.jsx
src/pages/project_manager_xy/resource-booking/index.jsx
+0
-0
index.jsx
src/pages/project_manager_xy/resource-stat/index.jsx
+0
-29
No files found.
docs/xinyuan-design-system.md
View file @
a4933ad8
...
...
@@ -53,6 +53,11 @@ paths are not valid delivery mechanisms.
Filters use a direct HeroUI
`Surface`
; lists remain unframed around the
DataGrid. Cards are reserved for discrete business objects and analytical tools.
Material archive filters use an explicit-submit rhythm: draft fields stay local
until
`查询`
, with a compact secondary reset icon button immediately before the
primary red query button and the native Disclosure
`展开`
control to its right.
Reset and category Tab changes submit their corresponding complete filter state;
typing alone never reloads the list.
## Component Rules
...
...
@@ -60,7 +65,14 @@ DataGrid. Cards are reserved for discrete business objects and analytical tools.
their documented
`@heroui-pro/react/*`
subpaths.
-
Routine text buttons are text-only; icon actions use Ant Design icons,
tooltips and accessible names.
-
Business page, module and field titles stay visually clean without adjacent
information-tip icons; reserve Tooltips for actual icon actions and controls.
-
Dropdown-like selection uses HeroUI Autocomplete/ListBox contracts.
-
Form checkboxes on light surfaces use HeroUI
`Checkbox`
with
`variant="secondary"`
so the unchecked control has a visible neutral fill
against white surfaces. Keep the official
`Checkbox.Content`
->
`Checkbox.Control`
->
`Checkbox.Indicator`
compound structure; selected
controls retain the brand accent, and field values/handlers remain unchanged.
-
Date and date-time fields use HeroUI DatePicker and preserve the existing
string protocol at the page boundary.
-
Files use HeroUI Pro DropZone while preserving the page-owned
`File`
object.
...
...
@@ -69,6 +81,9 @@ DataGrid. Cards are reserved for discrete business objects and analytical tools.
-
Routine success feedback is a fixed, auto-dismissing Toast.
-
Modal view mode uses one secondary Surface for the complete read-only field
group; edit mode removes that Surface and renders secondary fields directly.
-
Detail view modal footers expose only the contextual edit action; destructive
material actions stay in the DataGrid row menu or batch ActionBar to reduce
accidental deletion from a read-only view.
-
Empty results stay empty and request failures stay errors. UI code must never
populate dashboard or list surfaces with fabricated records or numbers.
...
...
src/components/DataTable.jsx
View file @
a4933ad8
import
{
Avatar
,
Button
,
Chip
,
Pagination
,
Spinner
,
Tooltip
}
from
"@heroui/react"
;
import
{
Button
,
Chip
,
Pagination
,
Spinner
,
Tooltip
}
from
"@heroui/react"
;
import
{
ActionBar
}
from
"@heroui-pro/react/action-bar"
;
import
{
DataGrid
}
from
"@heroui-pro/react/data-grid"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
...
...
@@ -240,18 +240,6 @@ export function DataTableTextPair({ primary, secondary, className = "" }) {
);
}
function
getPersonFallback
(
name
)
{
const
normalized
=
String
(
name
??
""
).
trim
();
if
(
!
normalized
||
normalized
===
"-"
)
{
return
"?"
;
}
const
compact
=
normalized
.
replace
(
/
\s
+/g
,
""
);
if
(
/^
[\u
3400-
\u
9fff
]
/
.
test
(
compact
))
{
return
Array
.
from
(
compact
)[
0
];
}
return
Array
.
from
(
compact
).
slice
(
0
,
2
).
join
(
""
).
toUpperCase
();
}
export
function
DataTablePersonIdentity
({
name
,
account
,
...
...
@@ -265,15 +253,11 @@ export function DataTablePersonIdentity({
return
(
<
Tooltip
delay=
{
0
}
>
<
div
className=
{
[
"flex min-w-0 items-center
gap-2
"
,
className
]
className=
{
[
"flex min-w-0 items-center"
,
className
]
.
filter
(
Boolean
)
.
join
(
" "
)
}
tabIndex=
{
0
}
>
<
Avatar
size=
"sm"
variant=
"soft"
className=
"shrink-0"
>
{
avatar
?
<
Avatar
.
Image
alt=
{
primaryText
}
src=
{
avatar
}
/>
:
null
}
<
Avatar
.
Fallback
>
{
getPersonFallback
(
primaryText
)
}
</
Avatar
.
Fallback
>
</
Avatar
>
<
span
className=
"grid min-w-0 gap-1"
>
<
span
className=
"min-w-0 truncate text-sm font-medium"
>
{
primaryText
}
...
...
@@ -347,7 +331,7 @@ export function DataTablePagination({
{
hasPageSizePicker
?
(
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-
24
shrink-0"
className=
"w-
32
shrink-0"
isDisabled=
{
isDisabled
}
options=
{
pageSizeOptionsForPicker
}
placeholder=
"每页条数"
...
...
src/components/XinyuanAutocomplete.jsx
View file @
a4933ad8
...
...
@@ -41,11 +41,13 @@ export default function XinyuanAutocomplete({
fullWidth
=
true
,
inputValue
,
isDisabled
=
false
,
isClearable
=
false
,
isLoading
=
false
,
isOpen
,
isRequired
=
false
,
name
,
onInputChange
,
onClear
,
onOpenChange
,
onSelectionChange
,
options
=
[],
...
...
@@ -80,6 +82,7 @@ export default function XinyuanAutocomplete({
(
selectedOptions
.
length
>
0
?
selectedOptions
.
map
((
option
)
=>
option
.
label
).
join
(
"、"
)
:
placeholder
);
const
hasSelection
=
Array
.
from
(
selectedKeyStringSet
).
some
(
Boolean
);
const
rootSelectionProps
=
selectionMode
===
"multiple"
?
{
selectedKeys
}
:
{
selectedKey
};
const
listBoxSelectionProps
=
...
...
@@ -118,6 +121,7 @@ export default function XinyuanAutocomplete({
isOpen=
{
isOpen
}
isRequired=
{
isRequired
}
name=
{
name
}
onClear=
{
onClear
}
selectionMode=
{
selectionMode
}
variant=
{
variant
}
onOpenChange=
{
onOpenChange
}
...
...
@@ -129,6 +133,11 @@ export default function XinyuanAutocomplete({
{
resolvedValueText
}
</
span
>
</
Autocomplete
.
Value
>
{
isClearable
&&
hasSelection
?
(
<
Autocomplete
.
ClearButton
aria
-
label=
{
`清除${ariaLabel || placeholder}`
}
/>
)
:
null
}
<
Autocomplete
.
Indicator
>
<
ChevronDown
size=
{
16
}
style=
{
FIELD_SUFFIX_ICON_STYLE
}
/>
</
Autocomplete
.
Indicator
>
...
...
src/pages/project_manager_xy/resource-booking/index.jsx
View file @
a4933ad8
This diff is collapsed.
Click to expand it.
src/pages/project_manager_xy/resource-stat/index.jsx
View file @
a4933ad8
...
...
@@ -13,7 +13,6 @@ import {
CircleStackIcon
,
DocumentTextIcon
,
FolderOpenIcon
,
InformationCircleIcon
,
ShieldCheckIcon
,
ShieldExclamationIcon
,
}
from
"@/components/AppIcons"
;
...
...
@@ -29,7 +28,6 @@ import {
Chip
,
ProgressBar
as
HeroProgressBar
,
Spinner
,
Tooltip
,
}
from
"@heroui/react"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
import
{
KPI
}
from
"@heroui-pro/react/kpi"
;
...
...
@@ -48,9 +46,6 @@ function Panel({ title, titleInfo, className, children }) {
<
Card
.
Title
className=
"rc-module-title min-w-0 flex-1"
>
{
title
}
</
Card
.
Title
>
{
titleInfo
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
titleInfo
}
/>
)
:
null
}
</
Card
.
Header
>
)
:
null
}
<
Card
.
Content
className=
{
className
}
>
{
children
}
</
Card
.
Content
>
...
...
@@ -65,9 +60,6 @@ function GovernanceCard({ title, titleInfo, icon: Icon, tone, children }) {
<
div
className=
"flex w-full min-w-0 items-center justify-between gap-4"
>
<
Card
.
Title
className=
"rc-module-title inline-flex min-w-0 items-center gap-1.5"
>
<
span
>
{
title
}
</
span
>
{
titleInfo
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
titleInfo
}
/>
)
:
null
}
</
Card
.
Title
>
<
span
aria
-
hidden=
"true"
...
...
@@ -85,23 +77,6 @@ function GovernanceCard({ title, titleInfo, icon: Icon, tone, children }) {
);
}
function
TitleInfoTooltip
({
label
,
text
})
{
return
(
<
Tooltip
delay=
{
0
}
>
<
Button
isIconOnly
aria
-
label=
{
`${label}说明`
}
className=
"rc-title-info-trigger"
type=
"button"
variant=
"ghost"
>
<
InformationCircleIcon
size=
{
14
}
/>
</
Button
>
<
Tooltip
.
Content
>
{
text
}
</
Tooltip
.
Content
>
</
Tooltip
>
);
}
function
MetricCard
({
icon
:
Icon
,
label
,
value
,
hint
,
tone
})
{
const
numericValue
=
Number
(
value
||
0
);
...
...
@@ -111,7 +86,6 @@ function MetricCard({ icon: Icon, label, value, hint, tone }) {
<
KPI
.
Title
>
<
span
className=
"inline-flex items-center gap-1.5"
>
{
label
}
{
hint
?
<
TitleInfoTooltip
label=
{
label
}
text=
{
hint
}
/>
:
null
}
</
span
>
</
KPI
.
Title
>
</
KPI
.
Header
>
...
...
@@ -135,9 +109,6 @@ function SectionHeader({ title, description }) {
return
(
<
h2
className=
"rc-section-title inline-flex items-center gap-1.5"
>
<
span
>
{
title
}
</
span
>
{
description
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
description
}
/>
)
:
null
}
</
h2
>
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment