Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
center-book
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
center-book
Commits
d238f10c
提交
d238f10c
authored
7月 20, 2026
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(admin): migrate members list module
上级
08581ef2
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
508 行增加
和
12 行删除
+508
-12
api.ts
apps/admin/src/modules/members/list/api.ts
+35
-0
MemberDetailView.tsx
.../src/modules/members/list/components/MemberDetailView.tsx
+117
-0
MemberDrawer.tsx
...dmin/src/modules/members/list/components/MemberDrawer.tsx
+85
-0
query.ts
apps/admin/src/modules/members/list/query.ts
+30
-0
routes.tsx
apps/admin/src/modules/members/list/routes.tsx
+11
-0
useMemberList.ts
apps/admin/src/modules/members/list/useMemberList.ts
+82
-0
MemberListView.tsx
apps/admin/src/modules/members/list/views/MemberListView.tsx
+146
-0
routes.tsx
apps/admin/src/modules/members/routes.tsx
+2
-12
没有找到文件。
apps/admin/src/modules/members/list/api.ts
0 → 100644
浏览文件 @
d238f10c
import
{
message
}
from
"antd"
;
import
request
from
"@/utils/request"
;
import
type
{
MemberQuery
}
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
;
}
return
false
;
}
export
const
getMemberList
=
(
query
:
MemberQuery
)
=>
post
(
"/members/members/getList"
,
query
);
export
const
getMemberInfo
=
(
id
:
string
|
number
)
=>
post
(
"/members/members/getInfoById"
,
{
id
});
export
const
addMember
=
(
data
:
Record
<
string
,
unknown
>
)
=>
post
(
"/members/members/add"
,
data
,
true
);
export
const
editMember
=
(
data
:
Record
<
string
,
unknown
>
)
=>
post
(
"/members/members/edit"
,
data
,
true
);
export
const
deleteMember
=
(
id
:
string
|
number
)
=>
post
(
"/members/members/del"
,
{
id
},
true
);
export
const
getOrders
=
(
id
:
string
|
number
)
=>
post
(
"/members/members/getOrdersList"
,
{
id
});
export
const
getIntegralRecords
=
(
id
:
string
|
number
)
=>
post
(
"/members/members/getIntegralRecordList"
,
{
id
});
export
const
getCouponRecords
=
(
id
:
string
|
number
)
=>
post
(
"/members/members/getCouponList"
,
{
id
});
apps/admin/src/modules/members/list/components/MemberDetailView.tsx
0 → 100644
浏览文件 @
d238f10c
import
{
Segmented
,
Table
}
from
"antd"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router"
;
import
PaginationCom
from
"@/common/Pagination"
;
import
{
getCouponRecords
,
getIntegralRecords
,
getOrders
}
from
"../api"
;
const
records
=
{
1
:
{
load
:
getOrders
,
columns
:
[
{
title
:
"订单编号"
,
dataIndex
:
"id"
},
{
title
:
"书籍名称"
,
dataIndex
:
"book_name"
},
{
title
:
"总金额"
,
dataIndex
:
"total_price"
},
{
title
:
"实际付款金额"
,
dataIndex
:
"final_total_price"
},
{
title
:
"下单时间"
,
dataIndex
:
"create_time"
},
{
title
:
"支付时间"
,
dataIndex
:
"pay_time"
},
{
title
:
"支付方式"
,
dataIndex
:
"pay_type"
,
render
:
(
value
:
number
)
=>
({
1
:
"微信"
,
2
:
"支付宝"
,
3
:
"紫荆币"
})[
value
]
||
"-"
,
},
{
title
:
"结算状态"
,
dataIndex
:
"status"
,
render
:
(
_
:
unknown
,
row
:
any
)
=>
({
1
:
"待支付"
,
2
:
"取消支付"
,
3
:
"已支付"
})[
row
.
pay_type
]
||
"-"
,
},
],
},
2
:
{
load
:
getIntegralRecords
,
columns
:
[
{
title
:
"积分变更"
,
dataIndex
:
"options"
,
render
:
(
value
:
number
,
row
:
any
)
=>
(
<
div
>
{
value
===
1
?
"加"
:
value
===
2
?
"减"
:
""
}
{
row
.
numbers
}
</
div
>
),
},
{
title
:
"最终积分"
,
dataIndex
:
"result"
},
{
title
:
"备注"
,
dataIndex
:
"remarks"
},
{
title
:
"创建时间"
,
dataIndex
:
"create_time"
},
],
},
3
:
{
load
:
getCouponRecords
,
columns
:
[
{
title
:
"优惠券名称"
,
dataIndex
:
"coupon_name"
},
{
title
:
"领取时间"
,
dataIndex
:
"create_time"
},
{
title
:
"有效期"
,
dataIndex
:
"end_time"
},
{
title
:
"使用状态"
,
dataIndex
:
"use_status_name"
},
],
},
}
as
const
;
function
RecordTable
({
type
,
id
}:
{
type
:
1
|
2
|
3
;
id
:
string
|
number
})
{
const
[
rows
,
setRows
]
=
useState
<
any
[]
>
([]);
const
[
total
,
setTotal
]
=
useState
(
type
===
2
?
4
:
0
);
const
[
page
,
setPage
]
=
useState
(
1
);
const
[
pageSize
,
setPageSize
]
=
useState
(
type
===
2
?
2
:
10
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
init
=
async
()
=>
{
setLoading
(
true
);
const
result
:
any
=
await
records
[
type
].
load
(
id
);
if
(
result
)
{
setRows
(
result
.
list
||
[]);
setTotal
(
result
.
total
||
0
);
}
setLoading
(
false
);
};
useEffect
(()
=>
{
void
init
();
},
[
id
,
type
]);
return
(
<
div
>
<
Table
columns=
{
records
[
type
].
columns
as
any
}
rowKey=
{
(
row
:
any
)
=>
row
.
ID
||
row
.
id
}
dataSource=
{
rows
}
loading=
{
loading
}
pagination=
{
false
}
scroll=
{
type
===
3
?
{
y
:
600
,
x
:
true
}
:
undefined
}
/>
<
br
/>
<
PaginationCom
total=
{
total
}
page_size=
{
pageSize
}
setpage_size=
{
setPageSize
}
page=
{
page
}
setPage=
{
setPage
}
init=
{
init
}
/>
</
div
>
);
}
export
default
function
MemberDetailView
()
{
const
location
=
useLocation
();
const
[
current
,
setCurrent
]
=
useState
<
1
|
2
|
3
>
(
1
);
const
id
=
(
location
.
state
as
{
id
?:
string
|
number
}
|
null
)?.
id
;
return
(
<
div
>
<
Segmented
options=
{
[
{
label
:
"订单记录"
,
value
:
1
},
{
label
:
"积分记录"
,
value
:
2
},
{
label
:
"优惠券记录"
,
value
:
3
},
]
}
value=
{
current
}
onChange=
{
(
value
)
=>
setCurrent
(
value
as
1
|
2
|
3
)
}
style=
{
{
marginBottom
:
20
}
}
/>
{
id
?
<
RecordTable
type=
{
current
}
id=
{
id
}
/>
:
null
}
</
div
>
);
}
apps/admin/src/modules/members/list/components/MemberDrawer.tsx
0 → 100644
浏览文件 @
d238f10c
import
{
Button
,
DatePicker
,
Drawer
,
Form
,
Input
,
Radio
,
Space
}
from
"antd"
;
import
dayjs
from
"dayjs"
;
import
{
useEffect
}
from
"react"
;
import
{
addMember
,
editMember
,
getMemberInfo
}
from
"../api"
;
export
default
function
MemberDrawer
({
open
,
id
,
onClose
,
onComplete
}:
any
)
{
const
[
form
]
=
Form
.
useForm
();
useEffect
(()
=>
{
if
(
!
open
)
{
form
.
setFieldsValue
({
name
:
""
,
phone
:
""
,
sex
:
"1"
,
birthday_time
:
""
});
return
;
}
if
(
id
)
void
getMemberInfo
(
id
).
then
(
(
data
:
any
)
=>
data
&&
form
.
setFieldsValue
({
...
data
,
birthday_time
:
dayjs
(
data
.
birthday_time
),
sex
:
String
(
data
.
sex
),
}),
);
},
[
form
,
id
,
open
]);
const
submit
=
async
(
values
:
any
)
=>
{
const
result
=
id
?
await
editMember
({
...
values
,
id
,
birthday_time
:
dayjs
(
values
.
birthday_time
).
unix
()
})
:
await
addMember
({
...
values
,
birthday_time
:
dayjs
(
values
.
birthday_time
).
unix
()
});
if
(
result
)
{
onClose
();
onComplete
();
}
};
return
(
<
Drawer
open=
{
open
}
mask=
{
false
}
centered
footer=
{
null
}
onClose=
{
onClose
}
>
<
Form
form=
{
form
}
onFinish=
{
submit
}
labelCol=
{
{
span
:
7
}
}
>
<
Form
.
Item
name=
"name"
label=
"用户名称"
rules=
{
[
{
required
:
true
,
message
:
"请输入用户名称"
},
{
max
:
30
,
message
:
"最大30字符"
},
]
}
>
<
Input
autoComplete=
"off"
placeholder=
"请输入用户名称"
/>
</
Form
.
Item
>
<
Form
.
Item
name=
"phone"
label=
"手机号名称"
rules=
{
[
{
required
:
true
,
message
:
"请输入手机号名称"
},
{
pattern
:
/^
(?:(?:\+
|00
)
86
)?
1
[
3-9
]\d
{9}$/
,
message
:
"请输入正确格式的手机号"
,
trigger
:
"blur"
,
},
]
}
>
<
Input
autoComplete=
"off"
placeholder=
"请输入手机号名称"
/>
</
Form
.
Item
>
<
Form
.
Item
name=
"sex"
label=
"性别"
rules=
{
[{
required
:
true
,
message
:
"请选择性别"
}]
}
>
<
Radio
.
Group
>
<
Radio
value=
"1"
>
男
</
Radio
>
<
Radio
value=
"2"
>
女
</
Radio
>
<
Radio
value=
"3"
>
保密
</
Radio
>
</
Radio
.
Group
>
</
Form
.
Item
>
<
Form
.
Item
name=
"birthday_time"
label=
"出生日期"
rules=
{
[{
required
:
true
,
message
:
"请选择出生日期"
}]
}
>
<
DatePicker
/>
</
Form
.
Item
>
<
Form
.
Item
wrapperCol=
{
{
offset
:
9
,
span
:
16
}
}
>
<
Space
size=
{
20
}
>
<
Button
onClick=
{
onClose
}
>
取消
</
Button
>
<
Button
type=
"primary"
htmlType=
"submit"
>
提交
</
Button
>
</
Space
>
</
Form
.
Item
>
</
Form
>
</
Drawer
>
);
}
apps/admin/src/modules/members/list/query.ts
0 → 100644
浏览文件 @
d238f10c
import
type
{
Dayjs
}
from
"dayjs"
;
export
interface
MemberFilters
{
name
?:
string
;
phone
?:
string
;
time
?:
[
Dayjs
|
null
,
Dayjs
|
null
]
|
null
;
}
export
interface
MemberQuery
{
page
:
number
;
page_size
:
number
;
name
?:
string
;
phone
?:
string
;
start_time
?:
number
;
end_time
?:
number
;
}
export
function
buildMemberQuery
(
page
:
number
,
pageSize
:
number
,
filters
:
MemberFilters
,
):
MemberQuery
{
const
query
:
MemberQuery
=
{
page
,
page_size
:
pageSize
};
if
(
filters
.
name
)
query
.
name
=
filters
.
name
;
if
(
filters
.
phone
)
query
.
phone
=
filters
.
phone
;
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/members/list/routes.tsx
0 → 100644
浏览文件 @
d238f10c
import
{
Navigate
,
useRoutes
}
from
"react-router"
;
import
MemberDetailView
from
"./components/MemberDetailView"
;
import
MemberListView
from
"./views/MemberListView"
;
export
default
function
MemberListRoutes
()
{
return
useRoutes
([
{
index
:
true
,
Component
:
MemberListView
},
{
path
:
"query"
,
Component
:
MemberListView
},
{
path
:
"detail"
,
Component
:
MemberDetailView
},
{
path
:
"*"
,
element
:
<
Navigate
to=
"/member/list"
/>
},
]);
}
apps/admin/src/modules/members/list/useMemberList.ts
0 → 100644
浏览文件 @
d238f10c
import
{
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
getMemberList
}
from
"./api"
;
import
{
buildMemberQuery
,
type
MemberFilters
,
type
MemberQuery
}
from
"./query"
;
export
function
useMemberList
()
{
const
[
filters
,
setFilters
]
=
useState
<
MemberFilters
>
({});
const
[
applied
,
setApplied
]
=
useState
<
MemberFilters
>
({});
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
<
MemberQuery
>
(
buildMemberQuery
(
1
,
10
,
{}));
const
requestId
=
useRef
(
0
);
const
load
=
useCallback
(
async
(
query
:
MemberQuery
)
=>
{
const
id
=
++
requestId
.
current
;
last
.
current
=
query
;
setLoading
(
true
);
setError
(
null
);
try
{
const
result
=
await
getMemberList
(
query
);
if
(
!
result
)
throw
new
Error
(
"请求失败"
);
if
(
id
===
requestId
.
current
)
{
setRows
(
result
.
list
||
[]);
setTotal
(
result
.
total
||
0
);
}
}
catch
(
reason
)
{
if
(
id
===
requestId
.
current
)
setError
(
reason
instanceof
Error
?
reason
:
new
Error
(
"请求失败"
));
}
finally
{
if
(
id
===
requestId
.
current
)
setLoading
(
false
);
}
},
[]);
useEffect
(()
=>
{
void
load
(
last
.
current
);
},
[
load
]);
const
run
=
useCallback
(
(
nextPage
:
number
,
nextSize
:
number
,
nextFilters
:
MemberFilters
)
=>
void
load
(
buildMemberQuery
(
nextPage
,
nextSize
,
nextFilters
)),
[
load
],
);
const
search
=
useCallback
(()
=>
{
setApplied
(
filters
);
setPage
(
1
);
run
(
1
,
pageSize
,
filters
);
},
[
filters
,
pageSize
,
run
]);
const
reset
=
useCallback
(()
=>
{
setFilters
({});
setApplied
({});
setPage
(
1
);
run
(
1
,
pageSize
,
{});
},
[
pageSize
,
run
]);
const
refresh
=
useCallback
(()
=>
{
setApplied
(
filters
);
run
(
page
,
pageSize
,
filters
);
},
[
filters
,
page
,
pageSize
,
run
]);
return
{
filters
,
setFilters
,
page
,
pageSize
,
rows
,
total
,
loading
,
error
,
search
,
reset
,
refresh
,
reloadFirst
:
search
,
retry
:
()
=>
void
load
(
last
.
current
),
changePage
:
(
next
:
number
)
=>
{
setPage
(
next
);
run
(
next
,
pageSize
,
applied
);
},
changePageSize
:
(
next
:
number
)
=>
{
setPage
(
1
);
setPageSize
(
next
);
run
(
1
,
next
,
applied
);
},
};
}
apps/admin/src/modules/members/list/views/MemberListView.tsx
0 → 100644
浏览文件 @
d238f10c
import
{
App
,
Button
,
DatePicker
,
Input
,
Space
}
from
"antd"
;
import
type
{
ColumnsType
}
from
"antd/es/table"
;
import
{
useState
}
from
"react"
;
import
{
useNavigate
}
from
"react-router"
;
import
{
useSelector
}
from
"react-redux"
;
import
{
AppList
,
type
AppListFilterItem
}
from
"@/shared/components/AppList"
;
import
{
deleteMember
}
from
"../api"
;
import
MemberDrawer
from
"../components/MemberDrawer"
;
import
type
{
MemberFilters
}
from
"../query"
;
import
{
useMemberList
}
from
"../useMemberList"
;
const
{
RangePicker
}
=
DatePicker
;
const
items
:
AppListFilterItem
<
MemberFilters
>
[]
=
[
{
name
:
"name"
,
label
:
"用户名称"
,
render
:
(
field
)
=>
(
<
Input
allowClear
placeholder=
"请输入用户名称"
value=
{
field
.
value
||
""
}
onChange=
{
(
e
)
=>
field
.
onChange
(
e
.
target
.
value
)
}
/>
),
},
{
name
:
"phone"
,
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
MemberListView
()
{
const
list
=
useMemberList
();
const
navigate
=
useNavigate
();
const
{
modal
}
=
App
.
useApp
();
const
{
operationPermissionsList
=
[]
}
=
useSelector
((
state
:
any
)
=>
state
.
user
);
const
[
id
,
setId
]
=
useState
<
any
>
(
""
);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
columns
:
ColumnsType
<
any
>
=
[
"ID:id"
,
"用户名:name"
,
"用户手机号:phone"
,
"创建时间:create_time"
,
"最后登录时间:last_login_time"
,
"最后登录IP:last_ip"
,
].
map
((
item
)
=>
{
const
[
title
,
dataIndex
]
=
item
.
split
(
":"
);
return
{
title
,
key
:
dataIndex
,
dataIndex
,
align
:
"center"
};
});
columns
.
push
({
title
:
"操作"
,
key
:
"handle"
,
render
:
(
_
,
row
)
=>
(
<
Space
>
{
operationPermissionsList
.
includes
(
"/member/list/getInfoById"
)
&&
(
<
Button
onClick=
{
()
=>
{
setId
(
row
.
id
);
setOpen
(
true
);
}
}
>
编辑
</
Button
>
)
}
{
operationPermissionsList
.
includes
(
"/member/list/del"
)
&&
(
<
Button
onClick=
{
()
=>
modal
.
confirm
({
title
:
"提示"
,
content
:
"用户将永久删除,是否继续?"
,
onOk
:
async
()
=>
{
if
(
await
deleteMember
(
row
.
id
))
list
.
reloadFirst
();
},
})
}
>
删除
</
Button
>
)
}
{
operationPermissionsList
.
includes
(
"/member/list/detail"
)
&&
(
<
Button
onClick=
{
()
=>
navigate
(
"/member/list/detail"
,
{
state
:
{
id
:
row
.
id
}
})
}
>
详情
</
Button
>
)
}
</
Space
>
),
});
return
(
<
div
className=
"classify"
>
<
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
(
"/member/list/add"
)
?
(
<
Button
type=
"primary"
ghost
onClick=
{
()
=>
{
setId
(
""
);
setOpen
(
true
);
}
}
>
添加
</
Button
>
)
:
null
}
onRetry=
{
list
.
retry
}
/>
<
MemberDrawer
open=
{
open
}
id=
{
id
}
onClose=
{
()
=>
setOpen
(
false
)
}
onComplete=
{
list
.
reloadFirst
}
/>
</
div
>
);
}
apps/admin/src/modules/members/routes.tsx
浏览文件 @
d238f10c
...
...
@@ -3,9 +3,7 @@ import { Navigate, useRoutes } from "react-router";
import
ModuleBoundary
from
"@/app/ModuleBoundary"
;
const
MembersLayout
=
lazy
(()
=>
import
(
"@/pages/member/index"
));
const
MemberListLayout
=
lazy
(()
=>
import
(
"@/pages/member/list/index"
));
const
MemberList
=
lazy
(()
=>
import
(
"@/pages/member/list/list"
));
const
MemberDetail
=
lazy
(()
=>
import
(
"@/pages/member/detail/index"
));
const
MemberListRoutes
=
lazy
(()
=>
import
(
"./list/routes"
));
const
UserLevel
=
lazy
(()
=>
import
(
"@/pages/member/userlevel/index"
));
export
default
function
MembersRoutes
()
{
...
...
@@ -14,15 +12,7 @@ export default function MembersRoutes() {
Component
:
MembersLayout
,
children
:
[
{
index
:
true
,
element
:
<
Navigate
to=
"/member/list"
/>
},
{
path
:
"list"
,
Component
:
MemberListLayout
,
children
:
[
{
index
:
true
,
Component
:
MemberList
},
{
path
:
"query"
,
Component
:
MemberList
},
{
path
:
"detail"
,
Component
:
MemberDetail
},
],
},
{
path
:
"list/*"
,
Component
:
MemberListRoutes
},
{
path
:
"userlevel"
,
Component
:
UserLevel
},
],
},
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论