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.
...
@@ -53,6 +53,11 @@ paths are not valid delivery mechanisms.
Filters use a direct HeroUI
`Surface`
; lists remain unframed around the
Filters use a direct HeroUI
`Surface`
; lists remain unframed around the
DataGrid. Cards are reserved for discrete business objects and analytical tools.
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
## Component Rules
...
@@ -60,7 +65,14 @@ DataGrid. Cards are reserved for discrete business objects and analytical tools.
...
@@ -60,7 +65,14 @@ DataGrid. Cards are reserved for discrete business objects and analytical tools.
their documented
`@heroui-pro/react/*`
subpaths.
their documented
`@heroui-pro/react/*`
subpaths.
-
Routine text buttons are text-only; icon actions use Ant Design icons,
-
Routine text buttons are text-only; icon actions use Ant Design icons,
tooltips and accessible names.
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.
-
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
-
Date and date-time fields use HeroUI DatePicker and preserve the existing
string protocol at the page boundary.
string protocol at the page boundary.
-
Files use HeroUI Pro DropZone while preserving the page-owned
`File`
object.
-
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.
...
@@ -69,6 +81,9 @@ DataGrid. Cards are reserved for discrete business objects and analytical tools.
-
Routine success feedback is a fixed, auto-dismissing Toast.
-
Routine success feedback is a fixed, auto-dismissing Toast.
-
Modal view mode uses one secondary Surface for the complete read-only field
-
Modal view mode uses one secondary Surface for the complete read-only field
group; edit mode removes that Surface and renders secondary fields directly.
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
-
Empty results stay empty and request failures stay errors. UI code must never
populate dashboard or list surfaces with fabricated records or numbers.
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
{
ActionBar
}
from
"@heroui-pro/react/action-bar"
;
import
{
DataGrid
}
from
"@heroui-pro/react/data-grid"
;
import
{
DataGrid
}
from
"@heroui-pro/react/data-grid"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
...
@@ -240,18 +240,6 @@ export function DataTableTextPair({ primary, secondary, className = "" }) {
...
@@ -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
({
export
function
DataTablePersonIdentity
({
name
,
name
,
account
,
account
,
...
@@ -265,15 +253,11 @@ export function DataTablePersonIdentity({
...
@@ -265,15 +253,11 @@ export function DataTablePersonIdentity({
return
(
return
(
<
Tooltip
delay=
{
0
}
>
<
Tooltip
delay=
{
0
}
>
<
div
<
div
className=
{
[
"flex min-w-0 items-center
gap-2
"
,
className
]
className=
{
[
"flex min-w-0 items-center"
,
className
]
.
filter
(
Boolean
)
.
filter
(
Boolean
)
.
join
(
" "
)
}
.
join
(
" "
)
}
tabIndex=
{
0
}
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=
"grid min-w-0 gap-1"
>
<
span
className=
"min-w-0 truncate text-sm font-medium"
>
<
span
className=
"min-w-0 truncate text-sm font-medium"
>
{
primaryText
}
{
primaryText
}
...
@@ -347,7 +331,7 @@ export function DataTablePagination({
...
@@ -347,7 +331,7 @@ export function DataTablePagination({
{
hasPageSizePicker
?
(
{
hasPageSizePicker
?
(
<
XinyuanAutocomplete
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
aria
-
label=
"每页条数"
className=
"w-
24
shrink-0"
className=
"w-
32
shrink-0"
isDisabled=
{
isDisabled
}
isDisabled=
{
isDisabled
}
options=
{
pageSizeOptionsForPicker
}
options=
{
pageSizeOptionsForPicker
}
placeholder=
"每页条数"
placeholder=
"每页条数"
...
...
src/components/XinyuanAutocomplete.jsx
View file @
a4933ad8
...
@@ -41,11 +41,13 @@ export default function XinyuanAutocomplete({
...
@@ -41,11 +41,13 @@ export default function XinyuanAutocomplete({
fullWidth
=
true
,
fullWidth
=
true
,
inputValue
,
inputValue
,
isDisabled
=
false
,
isDisabled
=
false
,
isClearable
=
false
,
isLoading
=
false
,
isLoading
=
false
,
isOpen
,
isOpen
,
isRequired
=
false
,
isRequired
=
false
,
name
,
name
,
onInputChange
,
onInputChange
,
onClear
,
onOpenChange
,
onOpenChange
,
onSelectionChange
,
onSelectionChange
,
options
=
[],
options
=
[],
...
@@ -80,6 +82,7 @@ export default function XinyuanAutocomplete({
...
@@ -80,6 +82,7 @@ export default function XinyuanAutocomplete({
(
selectedOptions
.
length
>
0
(
selectedOptions
.
length
>
0
?
selectedOptions
.
map
((
option
)
=>
option
.
label
).
join
(
"、"
)
?
selectedOptions
.
map
((
option
)
=>
option
.
label
).
join
(
"、"
)
:
placeholder
);
:
placeholder
);
const
hasSelection
=
Array
.
from
(
selectedKeyStringSet
).
some
(
Boolean
);
const
rootSelectionProps
=
const
rootSelectionProps
=
selectionMode
===
"multiple"
?
{
selectedKeys
}
:
{
selectedKey
};
selectionMode
===
"multiple"
?
{
selectedKeys
}
:
{
selectedKey
};
const
listBoxSelectionProps
=
const
listBoxSelectionProps
=
...
@@ -118,6 +121,7 @@ export default function XinyuanAutocomplete({
...
@@ -118,6 +121,7 @@ export default function XinyuanAutocomplete({
isOpen=
{
isOpen
}
isOpen=
{
isOpen
}
isRequired=
{
isRequired
}
isRequired=
{
isRequired
}
name=
{
name
}
name=
{
name
}
onClear=
{
onClear
}
selectionMode=
{
selectionMode
}
selectionMode=
{
selectionMode
}
variant=
{
variant
}
variant=
{
variant
}
onOpenChange=
{
onOpenChange
}
onOpenChange=
{
onOpenChange
}
...
@@ -129,6 +133,11 @@ export default function XinyuanAutocomplete({
...
@@ -129,6 +133,11 @@ export default function XinyuanAutocomplete({
{
resolvedValueText
}
{
resolvedValueText
}
</
span
>
</
span
>
</
Autocomplete
.
Value
>
</
Autocomplete
.
Value
>
{
isClearable
&&
hasSelection
?
(
<
Autocomplete
.
ClearButton
aria
-
label=
{
`清除${ariaLabel || placeholder}`
}
/>
)
:
null
}
<
Autocomplete
.
Indicator
>
<
Autocomplete
.
Indicator
>
<
ChevronDown
size=
{
16
}
style=
{
FIELD_SUFFIX_ICON_STYLE
}
/>
<
ChevronDown
size=
{
16
}
style=
{
FIELD_SUFFIX_ICON_STYLE
}
/>
</
Autocomplete
.
Indicator
>
</
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 {
...
@@ -13,7 +13,6 @@ import {
CircleStackIcon
,
CircleStackIcon
,
DocumentTextIcon
,
DocumentTextIcon
,
FolderOpenIcon
,
FolderOpenIcon
,
InformationCircleIcon
,
ShieldCheckIcon
,
ShieldCheckIcon
,
ShieldExclamationIcon
,
ShieldExclamationIcon
,
}
from
"@/components/AppIcons"
;
}
from
"@/components/AppIcons"
;
...
@@ -29,7 +28,6 @@ import {
...
@@ -29,7 +28,6 @@ import {
Chip
,
Chip
,
ProgressBar
as
HeroProgressBar
,
ProgressBar
as
HeroProgressBar
,
Spinner
,
Spinner
,
Tooltip
,
}
from
"@heroui/react"
;
}
from
"@heroui/react"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
import
{
EmptyState
}
from
"@heroui-pro/react/empty-state"
;
import
{
KPI
}
from
"@heroui-pro/react/kpi"
;
import
{
KPI
}
from
"@heroui-pro/react/kpi"
;
...
@@ -48,9 +46,6 @@ function Panel({ title, titleInfo, className, children }) {
...
@@ -48,9 +46,6 @@ function Panel({ title, titleInfo, className, children }) {
<
Card
.
Title
className=
"rc-module-title min-w-0 flex-1"
>
<
Card
.
Title
className=
"rc-module-title min-w-0 flex-1"
>
{
title
}
{
title
}
</
Card
.
Title
>
</
Card
.
Title
>
{
titleInfo
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
titleInfo
}
/>
)
:
null
}
</
Card
.
Header
>
</
Card
.
Header
>
)
:
null
}
)
:
null
}
<
Card
.
Content
className=
{
className
}
>
{
children
}
</
Card
.
Content
>
<
Card
.
Content
className=
{
className
}
>
{
children
}
</
Card
.
Content
>
...
@@ -65,9 +60,6 @@ function GovernanceCard({ title, titleInfo, icon: Icon, tone, children }) {
...
@@ -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"
>
<
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"
>
<
Card
.
Title
className=
"rc-module-title inline-flex min-w-0 items-center gap-1.5"
>
<
span
>
{
title
}
</
span
>
<
span
>
{
title
}
</
span
>
{
titleInfo
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
titleInfo
}
/>
)
:
null
}
</
Card
.
Title
>
</
Card
.
Title
>
<
span
<
span
aria
-
hidden=
"true"
aria
-
hidden=
"true"
...
@@ -85,23 +77,6 @@ function GovernanceCard({ title, titleInfo, icon: Icon, tone, children }) {
...
@@ -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
})
{
function
MetricCard
({
icon
:
Icon
,
label
,
value
,
hint
,
tone
})
{
const
numericValue
=
Number
(
value
||
0
);
const
numericValue
=
Number
(
value
||
0
);
...
@@ -111,7 +86,6 @@ function MetricCard({ icon: Icon, label, value, hint, tone }) {
...
@@ -111,7 +86,6 @@ function MetricCard({ icon: Icon, label, value, hint, tone }) {
<
KPI
.
Title
>
<
KPI
.
Title
>
<
span
className=
"inline-flex items-center gap-1.5"
>
<
span
className=
"inline-flex items-center gap-1.5"
>
{
label
}
{
label
}
{
hint
?
<
TitleInfoTooltip
label=
{
label
}
text=
{
hint
}
/>
:
null
}
</
span
>
</
span
>
</
KPI
.
Title
>
</
KPI
.
Title
>
</
KPI
.
Header
>
</
KPI
.
Header
>
...
@@ -135,9 +109,6 @@ function SectionHeader({ title, description }) {
...
@@ -135,9 +109,6 @@ function SectionHeader({ title, description }) {
return
(
return
(
<
h2
className=
"rc-section-title inline-flex items-center gap-1.5"
>
<
h2
className=
"rc-section-title inline-flex items-center gap-1.5"
>
<
span
>
{
title
}
</
span
>
<
span
>
{
title
}
</
span
>
{
description
?
(
<
TitleInfoTooltip
label=
{
title
}
text=
{
description
}
/>
)
:
null
}
</
h2
>
</
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