Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
risk_case_library
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
risk_case_library
Commits
894205db
Commit
894205db
authored
Sep 30, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: improve case search and detail interactions
parent
753f8f99
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
114 additions
and
41 deletions
+114
-41
manifest.json
public/manifest.json
+3
-2
audit-material-center.business-flow.md
...project_manager_xy/audit-material-center.business-flow.md
+9
-5
index.jsx
src/pages/project_manager_xy/resource-booking/index.jsx
+102
-34
No files found.
public/manifest.json
View file @
894205db
...
@@ -2,7 +2,8 @@
...
@@ -2,7 +2,8 @@
"name"
:
"risk_case_library"
,
"name"
:
"risk_case_library"
,
"version"
:
"1.0.4"
,
"version"
:
"1.0.4"
,
"build"
:
"abc"
,
"build"
:
"abc"
,
"description"
:
"
merge master
"
,
"description"
:
"
警示案例库
"
,
"date"
:
"2025-07-14 19:27:20"
,
"date"
:
"2025-07-14 19:27:20"
,
"author"
:
"yang"
"author"
:
"yang"
,
"spa"
:
true
}
}
src/pages/project_manager_xy/audit-material-center.business-flow.md
View file @
894205db
...
@@ -79,6 +79,7 @@
...
@@ -79,6 +79,7 @@
1.
用户进入
`案例管理`
1.
用户进入
`案例管理`
2.
点击
`手动新建`
2.
点击
`手动新建`
3.
填写标题、分类、标签、案例类型、案例属性、案例详情、案例警示、关键字、案例来源、案例等级、案例年份
3.
填写标题、分类、标签、案例类型、案例属性、案例详情、案例警示、关键字、案例来源、案例等级、案例年份
-
标题、案例类型、案例详情至少填写一项;未满足时在三个相关表单字段内部展示必填校验、标记错误状态并聚焦标题输入框,弹框保持打开
4.
前端调用
`POST /record`
4.
前端调用
`POST /record`
5.
成功后生成一条
`risk_case_library`
记录
5.
成功后生成一条
`risk_case_library`
记录
6.
页面顶部提示创建成功,并刷新当前列表
6.
页面顶部提示创建成功,并刷新当前列表
...
@@ -110,7 +111,7 @@
...
@@ -110,7 +111,7 @@
1.
用户进入
`案例管理`
1.
用户进入
`案例管理`
2.
点击
`Excel 批量导出`
2.
点击
`Excel 批量导出`
3.
前端按当前
全文搜索、案例性质、案例来源、案例类型、问题属性、分类标签等筛选条件查询全部案例
3.
前端按当前
案例性质及最近一次点击“查询”提交的全文搜索、案例来源、案例类型、问题属性、分类标签等筛选条件查询全部案例;尚未提交的输入不影响导出范围
4.
导出文件统一输出以下 11 列:
4.
导出文件统一输出以下 11 列:
-
`标题`
-
`标题`
-
`分类`
-
`分类`
...
@@ -138,7 +139,7 @@
...
@@ -138,7 +139,7 @@
8.
切换案例性质标签后,从第一页通过
`POST /record/query`
的
`filter.metadata.category`
远程查询;
`未分类`
使用
`$in: [null, "", "未分类"]`
兼容缺失及空字符串分类。页面不对当前页案例做本地二次搜索
8.
切换案例性质标签后,从第一页通过
`POST /record/query`
的
`filter.metadata.category`
远程查询;
`未分类`
使用
`$in: [null, "", "未分类"]`
兼容缺失及空字符串分类。页面不对当前页案例做本地二次搜索
9.
页面顶部提供
`Segment`
视图切换,可在“卡片视图 / 表格视图”之间切换
9.
页面顶部提供
`Segment`
视图切换,可在“卡片视图 / 表格视图”之间切换
10.
卡片视图用于浏览案例摘要;每条案例使用独立一级业务卡片,分类/等级/标签、标题、类型、摘要和时间信息按层级展示,点击卡片后以弹框方式查看并编辑详情
10.
卡片视图用于浏览案例摘要;每条案例使用独立一级业务卡片,分类/等级/标签、标题、类型、摘要和时间信息按层级展示,点击卡片后以弹框方式查看并编辑详情
11.
表格视图展示标题、分类、标签、案例类型、关键字、来源、等级、年份、更新时间等字段;宽表在 DataGrid 内部横向滚动,各字段只在所属单元格内单行截断,完整值通过 HeroUI Tooltip 查看,不允许跨列覆盖;
首列标题仅用于展示,不承担点击操作,查看详情统一从右侧操作列进入
11.
表格视图展示标题、分类、标签、案例类型、关键字、来源、等级、年份、更新时间等字段;宽表在 DataGrid 内部横向滚动,各字段只在所属单元格内单行截断,完整值通过 HeroUI Tooltip 查看,不允许跨列覆盖;
点击标题(
`title`
或
`metadata.label`
)或右侧操作列的“查看详情”按钮均打开当前案例详情弹框,默认进入查看态。标题使用 HeroUI Button,支持键盘操作,点击不改变表格勾选状态;两处入口复用同一打开逻辑及异常处理,不新增请求或修改案例字段
12.
表格视图按页加载案例,默认每页 20 条,并显示页码、当前页和匹配总数;分页栏提供 20、50、100 条/页选择器,切换后回到第一页并按原查询条件重新加载
12.
表格视图按页加载案例,默认每页 20 条,并显示页码、当前页和匹配总数;分页栏提供 20、50、100 条/页选择器,切换后回到第一页并按原查询条件重新加载
13.
表格视图支持单选、全选当前页案例,并显示当前勾选数量
13.
表格视图支持单选、全选当前页案例,并显示当前勾选数量
...
@@ -257,7 +258,9 @@
...
@@ -257,7 +258,9 @@
-
问题属性筛选
-
问题属性筛选
-
分类标签筛选
-
分类标签筛选
-
筛选项为普通文本输入框,不提供下拉框
-
筛选项为普通文本输入框,不提供下拉框
-
默认首行展示三个筛选项,剩余筛选项通过 HeroUI
`Disclosure`
展开;不展示刷新或查询按钮
-
各分类 Tab 共用筛选区,默认首行展示三个筛选项及 HeroUI
`Button`
查询按钮,剩余筛选项通过 HeroUI
`Disclosure`
展开
-
修改或清空全文关键词、案例来源、案例类型、问题属性、分类标签只更新输入;点击“查询”后统一提交(去除首尾空格),清空勾选并从第一页加载结果,相同条件可再次点击查询
-
查询期间按钮禁用并显示加载状态;查询失败沿用列表错误提示,保留输入,完成后可再次点击查询重试
-
`Segment`
视图切换(卡片 / 表格)
-
`Segment`
视图切换(卡片 / 表格)
-
顶部快捷操作区采用紧凑工具条呈现,保留手动新建、Excel 导入和 Excel 导出入口
-
顶部快捷操作区采用紧凑工具条呈现,保留手动新建、Excel 导入和 Excel 导出入口
-
手动新建按钮
-
手动新建按钮
...
@@ -328,8 +331,9 @@
...
@@ -328,8 +331,9 @@
-
首屏只加载第一页,默认每页 20 条
-
首屏只加载第一页,默认每页 20 条
-
表格与卡片列表通过页码分页加载,不使用下滑自动加载
-
表格与卡片列表通过页码分页加载,不使用下滑自动加载
-
每页固定加载 20 条,不展示或提供每页条数选择器
-
每页固定加载 20 条,不展示或提供每页条数选择器
-
当用户修改全文搜索、任一结构化筛选或切换案例性质时,实时从第一页重新加载
-
修改全文搜索或任一结构化筛选不触发请求;点击“查询”后从第一页重新加载。切换案例性质时使用最近已提交的筛选条件加载第一页,不提交尚未查询的输入
-
搜索与筛选统一发起远程查询,不在当前页结果中做本地搜索;连续请求只采用最新筛选状态对应的结果
-
分页、保存后的列表刷新和批量导出均沿用已提交的筛选条件;清空筛选项后也需点击“查询”才生效
-
搜索与筛选在提交后统一发起远程查询,不在当前页结果中做本地搜索;连续筛选请求只采用最新已提交筛选状态对应的结果
-
分类标签使用独立 aggregate 请求;列表仍按页查询,不得先拉取全量案例后再生成标签
-
分类标签使用独立 aggregate 请求;列表仍按页查询,不得先拉取全量案例后再生成标签
-
总数优先读取
`POST /record/query`
返回的
`total_records`
;接口未返回总数时再回退到
`count`
接口
-
总数优先读取
`POST /record/query`
返回的
`total_records`
;接口未返回总数时再回退到
`count`
接口
...
...
src/pages/project_manager_xy/resource-booking/index.jsx
View file @
894205db
...
@@ -21,6 +21,7 @@ import {
...
@@ -21,6 +21,7 @@ import {
Chip
,
Chip
,
CloseButton
,
CloseButton
,
Disclosure
,
Disclosure
,
FieldError
,
Input
,
Input
,
Label
,
Label
,
Modal
,
Modal
,
...
@@ -79,6 +80,7 @@ const ALL_CATEGORY_KEY = '__all__';
...
@@ -79,6 +80,7 @@ const ALL_CATEGORY_KEY = '__all__';
const
CARD_VIEW_MODE
=
'card'
;
const
CARD_VIEW_MODE
=
'card'
;
const
TABLE_VIEW_MODE
=
'table'
;
const
TABLE_VIEW_MODE
=
'table'
;
const
XINYUAN_4XL_DIALOG_CLASS
=
'bg-background p-7 sm:max-w-[68rem]'
;
const
XINYUAN_4XL_DIALOG_CLASS
=
'bg-background p-7 sm:max-w-[68rem]'
;
const
CREATE_CASE_REQUIRED_ERROR
=
'请至少填写标题、案例类型或案例详情中的一项。'
;
const
FALLBACK_CASE_FIELDS
=
[
const
FALLBACK_CASE_FIELDS
=
[
{
name
:
'label'
,
label
:
'标题'
,
type
:
'text'
},
{
name
:
'label'
,
label
:
'标题'
,
type
:
'text'
},
{
name
:
'category'
,
label
:
'分类'
,
type
:
'text'
},
{
name
:
'category'
,
label
:
'分类'
,
type
:
'text'
},
...
@@ -514,6 +516,7 @@ export default function ResourceBookingPage() {
...
@@ -514,6 +516,7 @@ export default function ResourceBookingPage() {
const
[
caseSourceFilter
,
setCaseSourceFilter
]
=
useState
(
''
);
const
[
caseSourceFilter
,
setCaseSourceFilter
]
=
useState
(
''
);
const
[
caseTypeFilter
,
setCaseTypeFilter
]
=
useState
(
''
);
const
[
caseTypeFilter
,
setCaseTypeFilter
]
=
useState
(
''
);
const
[
caseAttributeFilter
,
setCaseAttributeFilter
]
=
useState
(
''
);
const
[
caseAttributeFilter
,
setCaseAttributeFilter
]
=
useState
(
''
);
const
[
submittedFilters
,
setSubmittedFilters
]
=
useState
({});
const
[
activeCategory
,
setActiveCategory
]
=
useState
(
ALL_CATEGORY_KEY
);
const
[
activeCategory
,
setActiveCategory
]
=
useState
(
ALL_CATEGORY_KEY
);
const
[
categoryTabItems
,
setCategoryTabItems
]
=
useState
(
DEFAULT_CATEGORY_TABS
);
const
[
categoryTabItems
,
setCategoryTabItems
]
=
useState
(
DEFAULT_CATEGORY_TABS
);
const
[
categoryTabLoading
,
setCategoryTabLoading
]
=
useState
(
true
);
const
[
categoryTabLoading
,
setCategoryTabLoading
]
=
useState
(
true
);
...
@@ -539,6 +542,7 @@ export default function ResourceBookingPage() {
...
@@ -539,6 +542,7 @@ export default function ResourceBookingPage() {
const
[
exportingTemplate
,
setExportingTemplate
]
=
useState
(
false
);
const
[
exportingTemplate
,
setExportingTemplate
]
=
useState
(
false
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
notice
,
setNotice
]
=
useState
(
''
);
const
[
notice
,
setNotice
]
=
useState
(
''
);
const
[
createError
,
setCreateError
]
=
useState
(
''
);
const
[
isDemoMode
,
setIsDemoMode
]
=
useState
(
false
);
const
[
isDemoMode
,
setIsDemoMode
]
=
useState
(
false
);
const
[
isCreateOpen
,
setIsCreateOpen
]
=
useState
(
false
);
const
[
isCreateOpen
,
setIsCreateOpen
]
=
useState
(
false
);
const
[
isDetailOpen
,
setIsDetailOpen
]
=
useState
(
false
);
const
[
isDetailOpen
,
setIsDetailOpen
]
=
useState
(
false
);
...
@@ -562,6 +566,7 @@ export default function ResourceBookingPage() {
...
@@ -562,6 +566,7 @@ export default function ResourceBookingPage() {
const
pendingLocalMaterialsRef
=
useRef
({});
const
pendingLocalMaterialsRef
=
useRef
({});
const
editSessionRef
=
useRef
(
0
);
const
editSessionRef
=
useRef
(
0
);
const
categoryTabRequestRef
=
useRef
(
0
);
const
categoryTabRequestRef
=
useRef
(
0
);
const
createTitleInputRef
=
useRef
(
null
);
const
activeGridView
=
useMemo
(
const
activeGridView
=
useMemo
(
()
=>
gridViews
.
find
((
view
)
=>
view
.
name
===
activeGridViewName
)
||
null
,
()
=>
gridViews
.
find
((
view
)
=>
view
.
name
===
activeGridViewName
)
||
null
,
...
@@ -602,22 +607,22 @@ export default function ResourceBookingPage() {
...
@@ -602,22 +607,22 @@ export default function ResourceBookingPage() {
const
activeFilters
=
useMemo
(
const
activeFilters
=
useMemo
(
()
=>
({
()
=>
({
...
submittedFilters
,
category
:
activeCategory
===
ALL_CATEGORY_KEY
?
''
:
activeCategory
,
}),
[
activeCategory
,
submittedFilters
],
);
function
handleSearch
()
{
setSelectedCaseIds
([]);
setSubmittedFilters
({
keyword
:
String
(
query
||
''
).
trim
(),
keyword
:
String
(
query
||
''
).
trim
(),
tag
:
String
(
tagFilter
||
''
).
trim
(),
tag
:
String
(
tagFilter
||
''
).
trim
(),
caseSource
:
String
(
caseSourceFilter
||
''
).
trim
(),
caseSource
:
String
(
caseSourceFilter
||
''
).
trim
(),
caseType
:
String
(
caseTypeFilter
||
''
).
trim
(),
caseType
:
String
(
caseTypeFilter
||
''
).
trim
(),
caseAttribute
:
String
(
caseAttributeFilter
||
''
).
trim
(),
caseAttribute
:
String
(
caseAttributeFilter
||
''
).
trim
(),
category
:
activeCategory
===
ALL_CATEGORY_KEY
?
''
:
activeCategory
,
});
}),
}
[
activeCategory
,
caseAttributeFilter
,
caseSourceFilter
,
caseTypeFilter
,
query
,
tagFilter
,
],
);
const
selectedCaseIdSet
=
useMemo
(
const
selectedCaseIdSet
=
useMemo
(
()
=>
new
Set
(
selectedCaseIds
),
()
=>
new
Set
(
selectedCaseIds
),
...
@@ -645,12 +650,30 @@ export default function ResourceBookingPage() {
...
@@ -645,12 +650,30 @@ export default function ResourceBookingPage() {
pin
:
column
.
fixed
===
'left'
||
column
.
pin
===
'start'
?
'start'
:
undefined
,
pin
:
column
.
fixed
===
'left'
||
column
.
pin
===
'start'
?
'start'
:
undefined
,
isPrimary
:
index
===
0
,
isPrimary
:
index
===
0
,
sortable
:
Boolean
(
column
.
sortable
||
column
.
sort
),
sortable
:
Boolean
(
column
.
sortable
||
column
.
sort
),
render
:
(
item
)
=>
(
render
:
(
item
)
=>
{
<
DataTableText
const
text
=
getCaseColumnDisplayValue
(
item
,
column
)
||
'-'
;
showTooltip
const
isTitle
=
column
.
field
===
'title'
||
getFieldNameFromPath
(
column
.
field
)
===
'label'
;
text=
{
getCaseColumnDisplayValue
(
item
,
column
)
||
'-'
}
/>
return
isTitle
?
(
),
<
Tooltip
>
<
Button
aria
-
label=
{
`查看详情:${text}`
}
className=
"h-auto min-w-0 max-w-full justify-start rounded-sm px-0 py-1 text-left font-medium text-accent hover:underline"
variant=
"ghost"
onPress=
{
()
=>
openCaseDetail
(
item
)
}
>
<
span
className=
"min-w-0 truncate"
>
{
text
}
</
span
>
</
Button
>
<
Tooltip
.
Content
>
<
span
className=
"block max-w-[min(32rem,calc(100vw-2rem))] whitespace-pre-wrap break-words"
>
{
text
}
</
span
>
</
Tooltip
.
Content
>
</
Tooltip
>
)
:
(
<
DataTableText
showTooltip
text=
{
text
}
/>
);
},
})),
})),
{
{
key
:
'actions'
,
key
:
'actions'
,
...
@@ -852,6 +875,16 @@ export default function ResourceBookingPage() {
...
@@ -852,6 +875,16 @@ export default function ResourceBookingPage() {
function
resetCreateForm
()
{
function
resetCreateForm
()
{
setCreateForm
(
buildEmptyCaseForm
());
setCreateForm
(
buildEmptyCaseForm
());
setCreateError
(
''
);
}
function
handleCreateOpenChange
(
isOpen
)
{
if
(
!
isOpen
&&
creating
)
{
return
;
}
setCreateError
(
''
);
setIsCreateOpen
(
isOpen
);
}
}
function
resetBatchEditForm
()
{
function
resetBatchEditForm
()
{
...
@@ -933,11 +966,13 @@ export default function ResourceBookingPage() {
...
@@ -933,11 +966,13 @@ export default function ResourceBookingPage() {
!
String
(
createForm
.
caseType
||
''
).
trim
()
&&
!
String
(
createForm
.
caseType
||
''
).
trim
()
&&
!
String
(
createForm
.
caseDetails
||
''
).
trim
()
!
String
(
createForm
.
caseDetails
||
''
).
trim
()
)
{
)
{
setError
(
'请至少填写标题、案例类型或案例详情中的一项。'
);
setCreateError
(
CREATE_CASE_REQUIRED_ERROR
);
createTitleInputRef
.
current
?.
focus
();
return
;
return
;
}
}
setCreating
(
true
);
setCreating
(
true
);
setCreateError
(
''
);
setError
(
''
);
setError
(
''
);
setNotice
(
''
);
setNotice
(
''
);
...
@@ -950,7 +985,7 @@ export default function ResourceBookingPage() {
...
@@ -950,7 +985,7 @@ export default function ResourceBookingPage() {
await
Promise
.
all
([
refreshCurrentList
(
0
),
loadCategoryTabItems
()]);
await
Promise
.
all
([
refreshCurrentList
(
0
),
loadCategoryTabItems
()]);
setActiveCaseId
(
created
.
id
||
''
);
setActiveCaseId
(
created
.
id
||
''
);
}
catch
(
createError
)
{
}
catch
(
createError
)
{
setError
(
createError
?.
message
||
'案例创建失败,请稍后重试。'
);
set
Create
Error
(
createError
?.
message
||
'案例创建失败,请稍后重试。'
);
}
finally
{
}
finally
{
setCreating
(
false
);
setCreating
(
false
);
}
}
...
@@ -1348,7 +1383,15 @@ export default function ResourceBookingPage() {
...
@@ -1348,7 +1383,15 @@ export default function ResourceBookingPage() {
</div>
</div>
</div>
</div>
<div className="flex min-w-0 items-end justify-end">
<div className="flex min-w-0 items-end justify-end gap-2">
<Button
isDisabled={loading}
onPress={handleSearch}
variant="primary"
>
{loading ? <Spinner size="sm" /> : <MagnifyingGlassIcon size={16} />}
查询
</Button>
<Disclosure.Trigger className="button button--sm button--ghost">
<Disclosure.Trigger className="button button--sm button--ghost">
<span>{showAdvancedFilters ? '收起' : '展开'}</span>
<span>{showAdvancedFilters ? '收起' : '展开'}</span>
<Disclosure.Indicator>
<Disclosure.Indicator>
...
@@ -1461,6 +1504,7 @@ export default function ResourceBookingPage() {
...
@@ -1461,6 +1504,7 @@ export default function ResourceBookingPage() {
onPress={() => {
onPress={() => {
setError('');
setError('');
setNotice('');
setNotice('');
setCreateError('');
setIsCreateOpen(true);
setIsCreateOpen(true);
}}
}}
>
>
...
@@ -1547,7 +1591,7 @@ export default function ResourceBookingPage() {
...
@@ -1547,7 +1591,7 @@ export default function ResourceBookingPage() {
</div>
</div>
)}
)}
<Modal.Root isOpen={isCreateOpen} onOpenChange={
setIsCreateOpen
}>
<Modal.Root isOpen={isCreateOpen} onOpenChange={
handleCreateOpenChange
}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Container placement="center" scroll="inside" size="lg">
...
@@ -1557,21 +1601,34 @@ export default function ResourceBookingPage() {
...
@@ -1557,21 +1601,34 @@ export default function ResourceBookingPage() {
<Modal.Heading>手动新建案例</Modal.Heading>
<Modal.Heading>手动新建案例</Modal.Heading>
</Modal.Header>
</Modal.Header>
<Modal.Body>
<Modal.Body>
{createError && createError !== CREATE_CASE_REQUIRED_ERROR ? (
<Alert className="mb-4" status="danger" role="alert">
<Alert.Content>
<Alert.Description>{createError}</Alert.Description>
</Alert.Content>
</Alert>
) : null}
<div className="grid gap-4 sm:grid-cols-2">
<div className="grid gap-4 sm:grid-cols-2">
<TextField className="sm:col-span-2">
<TextField
className="sm:col-span-2"
isInvalid={createError === CREATE_CASE_REQUIRED_ERROR}
>
<Label>标题</Label>
<Label>标题</Label>
<Input
<Input
ref={createTitleInputRef}
fullWidth
fullWidth
value={createForm.label}
value={createForm.label}
variant="secondary"
variant="secondary"
onChange={(event) =>
onChange={(event) => {
setCreateError('');
setCreateForm((prev) => ({
setCreateForm((prev) => ({
...prev,
...prev,
label: event.target.value,
label: event.target.value,
}))
}))
;
}
}
}
placeholder="例如:采购审批绕行典型案例"
placeholder="例如:采购审批绕行典型案例"
/>
/>
<FieldError>{createError === CREATE_CASE_REQUIRED_ERROR ? createError : null}</FieldError>
</TextField>
</TextField>
<TextField>
<TextField>
<Label>分类</Label>
<Label>分类</Label>
...
@@ -1603,20 +1660,24 @@ export default function ResourceBookingPage() {
...
@@ -1603,20 +1660,24 @@ export default function ResourceBookingPage() {
placeholder="例如:采购审批"
placeholder="例如:采购审批"
/>
/>
</TextField>
</TextField>
<TextField>
<TextField
isInvalid={createError === CREATE_CASE_REQUIRED_ERROR}
>
<Label>案例类型</Label>
<Label>案例类型</Label>
<Input
<Input
fullWidth
fullWidth
value={createForm.caseType}
value={createForm.caseType}
variant="secondary"
variant="secondary"
onChange={(event) =>
onChange={(event) => {
setCreateError('');
setCreateForm((prev) => ({
setCreateForm((prev) => ({
...prev,
...prev,
caseType: event.target.value,
caseType: event.target.value,
}))
}))
;
}
}
}
placeholder="例如:审批绕行"
placeholder="例如:审批绕行"
/>
/>
<FieldError>
{createError === CREATE_CASE_REQUIRED_ERROR ? '请填写案例类型,或改填标题、案例详情。' : null}
</FieldError>
</TextField>
</TextField>
<TextField>
<TextField>
<Label>案例属性</Label>
<Label>案例属性</Label>
...
@@ -1692,7 +1753,10 @@ export default function ResourceBookingPage() {
...
@@ -1692,7 +1753,10 @@ export default function ResourceBookingPage() {
placeholder="例如:2024"
placeholder="例如:2024"
/>
/>
</TextField>
</TextField>
<TextField className="sm:col-span-2">
<TextField
className="sm:col-span-2"
isInvalid={createError === CREATE_CASE_REQUIRED_ERROR}
>
<div className="mb-2 flex items-center justify-between gap-3">
<div className="mb-2 flex items-center justify-between gap-3">
<Label>案例详情</Label>
<Label>案例详情</Label>
<span>
<span>
...
@@ -1704,14 +1768,18 @@ export default function ResourceBookingPage() {
...
@@ -1704,14 +1768,18 @@ export default function ResourceBookingPage() {
rows={12}
rows={12}
variant="secondary"
variant="secondary"
value={createForm.caseDetails}
value={createForm.caseDetails}
onChange={(event) =>
onChange={(event) => {
setCreateError('');
setCreateForm((prev) => ({
setCreateForm((prev) => ({
...prev,
...prev,
caseDetails: event.target.value,
caseDetails: event.target.value,
}))
}))
;
}
}
}
placeholder="粘贴或录入完整案例详情"
placeholder="粘贴或录入完整案例详情"
/>
/>
<FieldError>
{createError === CREATE_CASE_REQUIRED_ERROR ? '请填写案例详情,或改填标题、案例类型。' : null}
</FieldError>
</TextField>
</TextField>
<TextField className="sm:col-span-2">
<TextField className="sm:col-span-2">
<Label>案例警示</Label>
<Label>案例警示</Label>
...
@@ -1737,7 +1805,7 @@ export default function ResourceBookingPage() {
...
@@ -1737,7 +1805,7 @@ export default function ResourceBookingPage() {
size="sm"
size="sm"
variant="secondary"
variant="secondary"
onPress={() => {
onPress={() => {
setIsCreateOpen
(false);
handleCreateOpenChange
(false);
resetCreateForm();
resetCreateForm();
}}
}}
>
>
...
...
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