Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-book
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-book
Commits
ccf0b20e
提交
ccf0b20e
authored
7月 20, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(admin): migrate books label module
上级
21a3d404
显示空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
309 行增加
和
2 行删除
+309
-2
api.ts
apps/admin/src/modules/books/label/api.ts
+23
-0
query.ts
apps/admin/src/modules/books/label/query.ts
+21
-0
routes.tsx
apps/admin/src/modules/books/label/routes.tsx
+8
-0
useLabelList.ts
apps/admin/src/modules/books/label/useLabelList.ts
+70
-0
LabelView.tsx
apps/admin/src/modules/books/label/views/LabelView.tsx
+185
-0
routes.tsx
apps/admin/src/modules/books/routes.tsx
+2
-2
没有找到文件。
apps/admin/src/modules/books/label/api.ts
0 → 100644
浏览文件 @
ccf0b20e
import
{
message
}
from
"antd"
;
import
request
from
"@/utils/request"
;
import
type
{
LabelQuery
}
from
"./query"
;
async
function
post
(
path
:
string
,
data
:
Record
<
string
,
unknown
>
,
notify
=
false
)
{
try
{
const
response
=
(
await
request
.
post
(
path
,
new
URLSearchParams
(
data
as
Record
<
string
,
string
>
).
toString
(),
))
as
{
data
?:
{
code
?:
number
;
data
?:
any
;
message
?:
string
}
};
if
(
response
.
data
?.
code
===
200
)
{
if
(
notify
)
message
.
success
(
response
.
data
.
message
);
return
response
.
data
.
data
;
}
message
.
error
(
response
.
data
?.
message
||
"数据获取失败!"
);
}
catch
{}
return
false
;
}
export
const
getLabelList
=
(
query
:
LabelQuery
)
=>
post
(
"/book/label/getList"
,
query
);
export
const
getAllBooks
=
()
=>
post
(
"/book/label/getAllBooks"
,
{});
export
const
getLabel
=
(
id
:
string
|
number
)
=>
post
(
"/book/label/getInfoById"
,
{
id
});
export
const
addLabel
=
(
data
:
Record
<
string
,
unknown
>
)
=>
post
(
"/book/label/add"
,
data
,
true
);
export
const
editLabel
=
(
data
:
Record
<
string
,
unknown
>
)
=>
post
(
"/book/label/edit"
,
data
,
true
);
export
const
deleteLabel
=
(
id
:
string
|
number
)
=>
post
(
"/book/label/del"
,
{
id
},
true
);
apps/admin/src/modules/books/label/query.ts
0 → 100644
浏览文件 @
ccf0b20e
import
type
{
Dayjs
}
from
"dayjs"
;
export
interface
LabelFilters
{
name
?:
string
;
time
?:
[
Dayjs
|
null
,
Dayjs
|
null
]
|
null
;
}
export
interface
LabelQuery
{
page
:
number
;
page_size
:
number
;
name
?:
string
;
start_time
?:
number
;
end_time
?:
number
;
}
export
function
buildLabelQuery
(
page
:
number
,
pageSize
:
number
,
filters
:
LabelFilters
):
LabelQuery
{
const
query
:
LabelQuery
=
{
page
,
page_size
:
pageSize
};
if
(
filters
.
name
)
query
.
name
=
filters
.
name
;
if
(
filters
.
time
?.[
0
]
&&
filters
.
time
[
1
])
{
query
.
start_time
=
filters
.
time
[
0
].
startOf
(
"day"
).
unix
();
query
.
end_time
=
filters
.
time
[
1
].
endOf
(
"day"
).
unix
();
}
return
query
;
}
apps/admin/src/modules/books/label/routes.tsx
0 → 100644
浏览文件 @
ccf0b20e
import
{
Navigate
,
useRoutes
}
from
"react-router"
;
import
LabelView
from
"./views/LabelView"
;
export
default
function
LabelRoutes
()
{
return
useRoutes
([
{
index
:
true
,
Component
:
LabelView
},
{
path
:
"*"
,
element
:
<
Navigate
to=
"/books/label"
/>
},
]);
}
apps/admin/src/modules/books/label/useLabelList.ts
0 → 100644
浏览文件 @
ccf0b20e
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
getLabelList
}
from
"./api"
;
import
{
buildLabelQuery
,
type
LabelFilters
,
type
LabelQuery
}
from
"./query"
;
export
function
useLabelList
()
{
const
[
filters
,
setFilters
]
=
useState
<
LabelFilters
>
({});
const
[
applied
,
setApplied
]
=
useState
<
LabelFilters
>
({});
const
[
page
,
setPage
]
=
useState
(
1
);
const
[
pageSize
,
setPageSize
]
=
useState
(
10
);
const
[
rows
,
setRows
]
=
useState
<
any
[]
>
([]);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
<
Error
|
null
>
(
null
);
const
last
=
useRef
<
LabelQuery
>
(
buildLabelQuery
(
1
,
10
,
{}));
const
load
=
useCallback
(
async
(
query
:
LabelQuery
)
=>
{
last
.
current
=
query
;
setLoading
(
true
);
setError
(
null
);
try
{
const
result
:
any
=
await
getLabelList
(
query
);
if
(
!
result
)
throw
new
Error
(
"请求失败"
);
setRows
(
result
.
list
||
[]);
setTotal
(
result
.
total
||
0
);
}
catch
(
e
)
{
setError
(
e
instanceof
Error
?
e
:
new
Error
(
"请求失败"
));
}
finally
{
setLoading
(
false
);
}
},
[]);
useEffect
(()
=>
{
void
load
(
last
.
current
);
},
[
load
]);
const
run
=
(
p
:
number
,
s
:
number
,
f
:
LabelFilters
)
=>
void
load
(
buildLabelQuery
(
p
,
s
,
f
));
const
search
=
()
=>
{
setApplied
(
filters
);
setPage
(
1
);
run
(
1
,
pageSize
,
filters
);
};
return
{
filters
,
setFilters
,
page
,
pageSize
,
rows
,
total
,
loading
,
error
,
search
,
reset
:
()
=>
{
setFilters
({});
setApplied
({});
setPage
(
1
);
run
(
1
,
pageSize
,
{});
},
refresh
:
()
=>
{
setApplied
(
filters
);
run
(
page
,
pageSize
,
filters
);
},
retry
:
()
=>
void
load
(
last
.
current
),
reloadFirst
:
search
,
changePage
:
(
p
:
number
)
=>
{
setPage
(
p
);
run
(
p
,
pageSize
,
applied
);
},
changePageSize
:
(
s
:
number
)
=>
{
setPage
(
1
);
setPageSize
(
s
);
run
(
1
,
s
,
applied
);
},
};
}
apps/admin/src/modules/books/label/views/LabelView.tsx
0 → 100644
浏览文件 @
ccf0b20e
import
{
App
,
Button
,
DatePicker
,
Drawer
,
Form
,
Input
,
Row
,
Space
}
from
"antd"
;
import
type
{
ColumnsType
}
from
"antd/es/table"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useSelector
}
from
"react-redux"
;
import
{
AppList
,
type
AppListFilterItem
}
from
"@/shared/components/AppList"
;
import
{
addLabel
,
deleteLabel
,
editLabel
,
getAllBooks
,
getLabel
}
from
"../api"
;
import
type
{
LabelFilters
}
from
"../query"
;
import
{
useLabelList
}
from
"../useLabelList"
;
const
{
RangePicker
}
=
DatePicker
;
const
items
:
AppListFilterItem
<
LabelFilters
>
[]
=
[
{
name
:
"name"
,
label
:
"标签名称"
,
render
:
(
field
)
=>
(
<
Input
allowClear
placeholder=
"请输入标签名称"
value=
{
field
.
value
||
""
}
onChange=
{
(
e
)
=>
field
.
onChange
(
e
.
target
.
value
)
}
/>
),
},
{
name
:
"time"
,
label
:
"创建时间"
,
render
:
(
field
)
=>
(
<
RangePicker
value=
{
field
.
value
}
onChange=
{
(
value
)
=>
field
.
onChange
(
value
)
}
/>
),
},
];
export
default
function
LabelView
()
{
const
list
=
useLabelList
();
const
{
modal
}
=
App
.
useApp
();
const
{
operationPermissionsList
=
[]
}
=
useSelector
((
state
:
any
)
=>
state
.
user
);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
id
,
setId
]
=
useState
<
any
>
(
""
);
const
[
books
,
setBooks
]
=
useState
<
any
[]
>
([]);
const
[
bookIds
,
setBookIds
]
=
useState
<
any
[]
>
([]);
const
[
form
]
=
Form
.
useForm
();
useEffect
(()
=>
{
void
getAllBooks
().
then
((
data
:
any
)
=>
data
&&
setBooks
(
data
));
},
[]);
const
edit
=
async
(
value
:
any
)
=>
{
setId
(
value
);
const
data
:
any
=
await
getLabel
(
value
);
if
(
data
)
{
form
.
setFieldsValue
({
name
:
data
.
name
});
setBookIds
(
data
.
books
||
[]);
}
setOpen
(
true
);
};
const
submit
=
async
(
values
:
any
)
=>
{
const
result
=
id
?
await
editLabel
({
...
values
,
id
,
book_ids
:
bookIds
})
:
await
addLabel
({
...
values
,
book_ids
:
bookIds
});
if
(
result
)
{
setOpen
(
false
);
list
.
reloadFirst
();
}
};
const
toggle
=
(
value
:
any
)
=>
setBookIds
((
old
)
=>
old
.
includes
(
value
)
?
old
.
filter
((
item
)
=>
item
!==
value
)
:
[...
old
,
value
],
);
const
columns
:
ColumnsType
<
any
>
=
[
"ID:id"
,
"标签名称:name"
,
"创建时间:create_time"
,
"更新时间:update_time"
,
].
map
((
item
)
=>
{
const
[
title
,
dataIndex
]
=
item
.
split
(
":"
);
return
{
title
,
key
:
dataIndex
,
dataIndex
,
align
:
"center"
};
});
columns
.
push
({
title
:
"操作"
,
key
:
"handle"
,
render
:
(
_
,
row
)
=>
(
<
Space
>
{
operationPermissionsList
.
includes
(
"/books/label/getInfoById"
)
&&
(
<
Button
onClick=
{
()
=>
edit
(
row
.
id
)
}
>
编辑
</
Button
>
)
}
{
operationPermissionsList
.
includes
(
"/books/label/del"
)
&&
(
<
Button
onClick=
{
()
=>
modal
.
confirm
({
title
:
"提示"
,
content
:
"标签将永久删除,是否继续?"
,
onOk
:
async
()
=>
{
if
(
await
deleteLabel
(
row
.
id
))
list
.
reloadFirst
();
},
})
}
>
删除
</
Button
>
)
}
</
Space
>
),
});
return
(
<
div
className=
"label"
>
<
AppList
rowKey=
"id"
columns=
{
columns
}
data=
{
{
rows
:
list
.
rows
,
total
:
list
.
total
,
loading
:
list
.
loading
,
error
:
list
.
error
}
}
filters=
{
{
value
:
list
.
filters
,
items
,
onChange
:
list
.
setFilters
,
onSearch
:
list
.
search
,
onReset
:
list
.
reset
,
onRefresh
:
list
.
refresh
,
}
}
pagination=
{
{
page
:
list
.
page
,
pageSize
:
list
.
pageSize
,
pageSizeOptions
:
[
10
,
20
,
30
,
40
],
onChange
:
list
.
changePage
,
onPageSizeChange
:
list
.
changePageSize
,
}
}
toolbar=
{
operationPermissionsList
.
includes
(
"/books/label/add"
)
?
(
<
Button
type=
"primary"
ghost
onClick=
{
()
=>
{
setId
(
""
);
setBookIds
([]);
form
.
resetFields
();
setOpen
(
true
);
}
}
>
添加
</
Button
>
)
:
null
}
onRetry=
{
list
.
retry
}
/>
<
Drawer
placement=
"right"
open=
{
open
}
mask=
{
false
}
onClose=
{
()
=>
setOpen
(
false
)
}
>
<
Form
form=
{
form
}
onFinish=
{
submit
}
labelCol=
{
{
span
:
5
}
}
>
<
Form
.
Item
label=
"标签名称"
name=
"name"
rules=
{
[{
required
:
true
,
message
:
"请输入标签名称"
}]
}
>
<
Input
placeholder=
"请输入标签名称"
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"书籍"
rules=
{
[{
required
:
true
,
message
:
"请选择书籍"
}]
}
>
<
Button
type=
"primary"
ghost
onClick=
{
()
=>
setBookIds
(
bookIds
.
length
===
books
.
length
?
[]
:
books
.
map
((
book
)
=>
book
.
id
))
}
>
全选
</
Button
>
<
br
/>
<
br
/>
<
Row
gutter=
{
20
}
>
{
books
.
map
((
book
)
=>
(
<
Button
key=
{
book
.
id
}
type=
{
bookIds
.
includes
(
book
.
id
)
?
"primary"
:
"default"
}
ghost=
{
bookIds
.
includes
(
book
.
id
)
}
onClick=
{
()
=>
toggle
(
book
.
id
)
}
>
{
book
.
name
}
</
Button
>
))
}
</
Row
>
</
Form
.
Item
>
<
Form
.
Item
wrapperCol=
{
{
offset
:
5
,
span
:
16
}
}
>
<
Space
size=
{
20
}
>
<
Button
onClick=
{
()
=>
setOpen
(
false
)
}
>
取消
</
Button
>
<
Button
type=
"primary"
htmlType=
"submit"
>
提交
</
Button
>
</
Space
>
</
Form
.
Item
>
</
Form
>
</
Drawer
>
</
div
>
);
}
apps/admin/src/modules/books/routes.tsx
浏览文件 @
ccf0b20e
...
...
@@ -11,7 +11,7 @@ const AuditLayout = lazy(() => import("@/pages/books/audit/index"));
const
AuditTable
=
lazy
(()
=>
import
(
"@/pages/books/audit/table"
));
const
AuditDetail
=
lazy
(()
=>
import
(
"@/pages/books/audit/detail"
));
const
ClassifyRoutes
=
lazy
(()
=>
import
(
"./classify/routes"
));
const
Label
=
lazy
(()
=>
import
(
"@/pages/books/label/index
"
));
const
Label
Routes
=
lazy
(()
=>
import
(
"./label/routes
"
));
const
SaleLayout
=
lazy
(()
=>
import
(
"@/pages/books/sale/index"
));
const
SaleTable
=
lazy
(()
=>
import
(
"@/pages/books/sale/table"
));
const
SaleEdit
=
lazy
(()
=>
import
(
"@/pages/books/sale/edit"
));
...
...
@@ -50,7 +50,7 @@ export default function BooksRoutes() {
],
},
{
path
:
"classify/*"
,
Component
:
ClassifyRoutes
},
{
path
:
"label
"
,
Component
:
Label
},
{
path
:
"label
/*"
,
Component
:
LabelRoutes
},
{
path
:
"sale"
,
Component
:
SaleLayout
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论