Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
AppUms_Lecturer
Overview
Overview
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tungnq
AppUms_Lecturer
Commits
9ce41d07
Commit
9ce41d07
authored
Sep 11, 2025
by
tungnq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO: Đã bổ sung thêm logic để lọc công việc theo role và status
parent
fb8e80c7
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
197 additions
and
95 deletions
+197
-95
actionTypes.js
src/actions/actionTypes.js
+33
-0
index.js
src/screens/list_work/index.js
+137
-71
view.js
src/screens/list_work/modal_add/view.js
+0
-2
style.js
src/screens/list_work/style.js
+20
-0
view.js
src/screens/list_work/view.js
+7
-22
No files found.
src/actions/actionTypes.js
View file @
9ce41d07
...
...
@@ -33,3 +33,35 @@ export const ADD_PRODUCT = "ADD_PRODUCT";
export
const
REMOVE_PRODUCT
=
"REMOVE_PRODUCT"
;
export
const
CLEAR_CART
=
"CLEAR_CART"
;
//ACTION CÔNG VIỆC VAI TRÒ
export
const
ROLE
=
{
ALL
:
'ALL'
,
ASSIGNEE
:
'ASSIGNEE'
,
//Giao cho tôi (Giảng viên nhận công việc)
SUPERVISOR
:
'SUPERVISOR'
//Đang giám sát (Giảng viên giám sát)
}
//ACTION TRẠNG THÁI THEO VAI TRÒ
export
const
STATUS_BY_ROLE
=
{
[
ROLE
.
ASSIGNEE
]:
[
'Đang thực hiện'
,
'Cần chỉnh sửa'
,
'Chờ duyệt'
,
'Đợi báo cáo'
,
'Đã hoàn thành'
],
[
ROLE
.
SUPERVISOR
]:[
'Đang thực hiện'
,
'Đợi chỉnh sửa'
,
'Chờ duyệt'
,
'Đợi báo cáo'
,
'Đã hoàn thành'
]
}
//ACTION TIẾN ĐỘ CÔNG VIỆC
export
const
WORK_PROGRESS
=
{
ALL_WORK_PROGRESS
:
'ALL_WORK_PROGRESS'
,
SUCCESS_WORK_PROGRESS
:
'SUCCESS_WORK_PROGRESS'
,
CONTINUE_WORK_PROGRESS
:
'CONTINUE_WORK_PROGRESS'
,
}
\ No newline at end of file
src/screens/list_work/index.js
View file @
9ce41d07
import
React
,
{
useState
}
from
'react'
;
import
React
,
{
useState
,
useMemo
}
from
'react'
;
import
{
useNavigation
}
from
'@react-navigation/native'
;
import
ListWorkView
from
'./view'
;
import
*
as
ScreenName
from
'../../routers/ScreenNames'
;
import
{
WORK_PROGRESS
,
ROLE
}
from
'../../actions/actionTypes'
;
import
R
from
'../../assets/R'
;
/**
* Container component quản lý logic nghiệp vụ cho màn hình danh sách công việc
* Chứa tất cả state và business logic, truyền xuống view component thông qua props
*/
const
ListWork
=
props
=>
{
const
{
searchQuery
,
setSearchQuery
}
=
props
;
const
navigation
=
useNavigation
();
// ==================== STATE MANAGEMENT ====================
// Trạng thái hiển thị modal thêm công việc
const
[
searchQuery
,
setSearchQuery
]
=
useState
(
''
);
const
[
modalVisible
,
setModalVisible
]
=
useState
(
false
);
const
[
currentTabKey
,
setCurrentTabKey
]
=
useState
(
ROLE
.
ALL
);
const
[
currentDropDownKey
,
setCurrentDropDownKey
]
=
useState
(
WORK_PROGRESS
.
ALL_WORK_PROGRESS
,
);
// Danh sách công việc mẫu với các trạng thái khác nhau
const
[
dataList
,
setDataList
]
=
useState
([
{
id
:
1
,
title
:
'Tạo thời khóa biểu cho sinh vi
ế
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'Đang thực hiện'
,
title
:
'Tạo thời khóa biểu cho sinh vi
ê
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'Đang thực hiện'
,
// hợp lệ cho cả 2 role
deadline
:
'2025-09-04'
,
assignedToMe
:
true
,
supervisedByMe
:
false
,
supervisor
:
[
{
id
:
1
,
name
:
'Trần Văn Hùng'
},
{
id
:
2
,
name
:
'Nguyễn Văn A'
},
],
document
:
'BM255, Nguyễn Minh Đức'
,
workProgress
:
'Đang thực hiện'
,
},
{
id
:
2
,
title
:
'Tạo thời khóa biểu cho sinh vi
ế
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'Cần chỉnh sửa'
,
title
:
'Tạo thời khóa biểu cho sinh vi
ê
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'Cần chỉnh sửa'
,
// chỉ hợp lệ với role Giao cho tôi
deadline
:
'2025-09-04'
,
assignedToMe
:
true
,
supervisedByMe
:
false
,
supervisor
:
[
{
id
:
1
,
name
:
'Trần Văn Hùng'
},
{
id
:
2
,
name
:
'Nguyễn Văn A'
},
],
document
:
'BM255, Nguyễn Minh Đức'
,
workProgress
:
'Đang hoàn thành'
,
},
{
id
:
3
,
title
:
'Tạo thời khóa biểu cho sinh vi
ế
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'
Chờ duyệt'
,
title
:
'Tạo thời khóa biểu cho sinh vi
ê
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'
Hoàn thành'
,
// hợp lệ cho cả 2 role
deadline
:
'2025-09-04'
,
assignedToMe
:
true
,
supervisedByMe
:
false
,
supervisor
:
[
{
id
:
1
,
name
:
'Trần Văn Hùng'
},
{
id
:
2
,
name
:
'Nguyễn Văn A'
},
],
document
:
'BM255, Nguyễn Minh Đức'
,
workProgress
:
'Đang hoàn thành'
,
},
{
id
:
4
,
title
:
'Tạo thời khóa biểu cho sinh viên khai giảng và học kỳ 2 năm 2025'
,
status
:
'Đợi báo cáo'
,
status
:
'Đợi báo cáo'
,
// chỉ hợp lệ với role Đang giám sát
deadline
:
'2025-09-04'
,
assignedToMe
:
false
,
supervisedByMe
:
true
,
supervisor
:
[
{
id
:
1
,
name
:
'Trần Văn Hùng'
},
{
id
:
2
,
name
:
'Nguyễn Văn A'
},
],
document
:
'BM255, Nguyễn Minh Đức'
,
workProgress
:
'Đang hoàn thành'
,
},
{
id
:
5
,
title
:
'Tạo thời khóa biểu cho sinh vi
ế
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'
Đã h
oàn thành'
,
title
:
'Tạo thời khóa biểu cho sinh vi
ê
n khai giảng và học kỳ 2 năm 2025'
,
status
:
'
H
oàn thành'
,
deadline
:
'2025-09-04'
,
assignedToMe
:
false
,
supervisedByMe
:
true
,
supervisor
:
[
{
id
:
1
,
name
:
'Trần Văn Hùng'
},
{
id
:
2
,
name
:
'Nguyễn Văn A'
},
],
document
:
'Văn bản thông báo lịch nộp thời khóa biểu của học kỳ 2 năm 2025'
,
workProgress
:
'Đang thực hiện'
,
},
]);
...
...
@@ -99,9 +111,43 @@ const ListWork = props => {
// Xử lý thay đổi bộ lọc tab
const
handleFilterChange
=
item
=>
{
console
.
log
(
'Bộ lọc đã thay đổi:'
,
item
);
// TODO: Thêm logic lọc danh sách theo tab được chọn
setCurrentTabKey
(
item
?.
key
||
ROLE
.
ALL
);
console
.
log
(
'Tab changed to:'
,
item
?.
key
);
};
// Hiển thị dữ liệu sau khi chọn
const
filterList
=
useMemo
(()
=>
{
let
base
=
dataList
;
console
.
log
(
'Dữ liệu danh sách đầu vào'
,
base
);
// Lọc theo tab role
if
(
currentTabKey
===
ROLE
.
ASSIGNEE
)
{
base
=
base
.
filter
(
x
=>
x
.
assignedToMe
);
}
else
if
(
currentTabKey
===
ROLE
.
SUPERVISOR
)
{
base
=
base
.
filter
(
x
=>
x
.
supervisedByMe
);
}
// ROLE.ALL không cần filter
// Lọc theo search query
if
(
searchQuery
&&
searchQuery
.
trim
())
{
const
q
=
searchQuery
.
trim
().
toLowerCase
();
base
=
base
.
filter
(
x
=>
x
.
title
.
toLowerCase
().
includes
(
q
)
||
x
.
status
.
toLowerCase
().
includes
(
q
),
);
}
// Lọc theo dropdown progress (chỉ khi không phải ALL)
if
(
currentDropDownKey
===
WORK_PROGRESS
.
SUCCESS_WORK_PROGRESS
)
{
base
=
base
.
filter
(
x
=>
x
.
status
===
'Đã hoàn thành'
);
}
else
if
(
currentDropDownKey
===
WORK_PROGRESS
.
CONTINUE_WORK_PROGRESS
)
{
base
=
base
.
filter
(
x
=>
x
.
status
!==
'Đã hoàn thành'
);
}
// WORK_PROGRESS.ALL_WORK_PROGRESS không cần filter
console
.
log
(
'Dữ liệu sau khi lọc:'
,
base
);
return
base
;
},
[
dataList
,
currentTabKey
,
searchQuery
,
currentDropDownKey
]);
// ==================== NAVIGATION HANDLERS ====================
...
...
@@ -151,8 +197,10 @@ const ListWork = props => {
case
'Chờ duyệt'
:
return
'#007AFF'
;
// Xanh dương
case
'Cần chỉnh sửa'
:
return
'#FF9500'
;
// Cam
case
'Đã hoàn thành'
:
return
'#FF9500'
;
// Cam (assignee)
case
'Đợi chỉnh sửa'
:
return
'#FF9500'
;
// Cam (supervisor)
case
'Hoàn thành'
:
return
'#34C759'
;
// Xanh lá
case
'Đợi báo cáo'
:
return
'#007AFF'
;
// Xanh dương
...
...
@@ -163,66 +211,84 @@ const ListWork = props => {
// Lấy danh sách button theo trạng thái công việc
const
getButtonsForStatus
=
status
=>
{
// Ẩn button cho các trạng thái: hoàn thành, cần chỉnh sửa, đợi báo cáo
if
([
'Đã hoàn thành'
,
'Cần chỉnh sửa'
,
'Đợi báo cáo'
].
includes
(
status
))
{
return
[];
// Đang giám sát
if
(
currentTabKey
===
ROLE
.
SUPERVISOR
)
{
switch
(
status
)
{
case
'Đang thực hiện'
:
return
[
{
title
:
'Yêu cầu báo cáo'
,
backgroundColor
:
R
.
colors
.
orange
,
action
:
'requestReport'
},
{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
},
];
case
'Đợi chỉnh sửa'
:
return
[{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
}];
case
'Chờ duyệt'
:
return
[
{
title
:
'Cần chỉnh sửa'
,
backgroundColor
:
R
.
colors
.
orange
,
action
:
'needsEdit'
},
{
title
:
'Phê duyệt'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'approve'
},
{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
},
];
case
'Đợi báo cáo'
:
return
[{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
}];
case
'Đã hoàn thành'
:
return
[{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
}];
default
:
return
[];
}
}
// Trường hợp đặc biệt cho "Chờ duyệt" - hiển thị 2 button
if
(
status
===
'Chờ duyệt'
)
{
return
[
{
title
:
'Cần chỉnh sửa'
,
backgroundColor
:
'#FF9500'
,
action
:
'needsEdit'
,
},
{
title
:
'Phê duyệt'
,
backgroundColor
:
'#007AFF'
,
action
:
'approve'
,
},
];
// Giao cho tôi
if
(
currentTabKey
===
ROLE
.
ASSIGNEE
)
{
switch
(
status
)
{
case
'Đang thực hiện'
:
case
'Cần chỉnh sửa'
:
case
'Đợi báo cáo'
:
return
[
{
title
:
'Báo cáo'
,
backgroundColor
:
R
.
colors
.
orange
,
action
:
'report'
},
{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
},
];
case
'Chờ duyệt'
:
return
[
{
title
:
'Sửa báo cáo'
,
backgroundColor
:
R
.
colors
.
orange
,
action
:
'editReport'
},
{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
},
];
case
'Hoàn thành'
:
return
[{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
}];
default
:
return
[];
}
}
// Button mặc định cho các trạng thái khác
const
buttonTitle
=
status
===
'Đang thực hiện'
?
'Yêu cầu báo cáo'
:
'Báo cáo'
;
return
[
{
title
:
buttonTitle
,
backgroundColor
:
'#FF9500'
,
action
:
'report'
,
},
];
// Tất cả - hiển thị tất cả buttons có thể
return
[{
title
:
'Chi tiết'
,
backgroundColor
:
R
.
colors
.
blue
,
action
:
'detail'
}];
};
const
[
tabView
,
setTabView
]
=
useState
([
{
key
:
'all'
,
label
:
'Tất cả'
},
{
key
:
'public'
,
label
:
'Giao cho tôi'
},
{
key
:
'private'
,
label
:
'Đang giám sát'
},
{
key
:
ROLE
.
ALL
,
label
:
'Tất cả'
},
{
key
:
ROLE
.
ASSIGNEE
,
label
:
'Giao cho tôi'
},
{
key
:
ROLE
.
SUPERVISOR
,
label
:
'Đang giám sát'
},
]);
// ==================== RENDER ====================
return
(
<
ListWorkView
// Props d
ữ liệu
searchQuery
=
{
searchQuery
}
setSearchQuery
=
{
setSearchQuery
}
dataList
=
{
data
List
}
modalVisible
=
{
modalVisible
}
// Props xử lý sự kiện
onFilterChange
=
{
handleFilterChange
}
onAddWork
=
{
handleAddWork
}
onSaveWork
=
{
handleSave
Work
}
onCloseModal
=
{
handleCloseModal
}
onViewDetail
=
{
handleViewDetai
l
}
onReportAction
=
{
handleReportAction
}
onApprovalAction
=
{
handleApproval
Action
}
tabView
=
{
tabView
}
// Props utility function
s
getStatusColor
=
{
getStatusColor
}
getButtonsForStatus
=
{
getButtonsForStatus
}
// D
ữ liệu
searchQuery
=
{
searchQuery
}
setSearchQuery
=
{
setSearchQuery
}
dataList
=
{
filter
List
}
modalVisible
=
{
modalVisible
}
tabView
=
{
tabView
}
// Sự kiện
onFilterChange
=
{
handleFilterChange
}
onAddWork
=
{
handleAdd
Work
}
onSaveWork
=
{
handleSaveWork
}
onCloseModal
=
{
handleCloseModa
l
}
onViewDetail
=
{
handleViewDetail
}
onReportAction
=
{
handleReport
Action
}
onApprovalAction
=
{
handleApprovalAction
}
// Util
s
getStatusColor
=
{
getStatusColor
}
getButtonsForStatus
=
{
getButtonsForStatus
}
/
>
);
};
...
...
src/screens/list_work/modal_add/view.js
View file @
9ce41d07
...
...
@@ -3,10 +3,8 @@ import {
Modal
,
View
,
Text
,
TextInput
,
TouchableOpacity
,
ScrollView
,
StyleSheet
,
Image
,
FlatList
,
}
from
'react-native'
;
...
...
src/screens/list_work/style.js
View file @
9ce41d07
...
...
@@ -37,6 +37,26 @@ const styles = StyleSheet.create({
justifyContent
:
'center'
,
borderColor
:
R
.
colors
.
grayBorderInputTextHeader
,
},
container_tab_view
:{
marginVertical
:
5
},
item_tab_view
:{
backgroundColor
:
R
.
colors
.
gray
,
marginHorizontal
:
5
,
borderRadius
:
10
,
width
:
107
,
justifyContent
:
'center'
,
alignItems
:
'center'
,
},
active_tab_view
:{
backgroundColor
:
R
.
colors
.
blue
,
},
text_tab_view
:{
color
:
R
.
colors
.
white
,
fontWeight
:
'400'
,
fontFamily
:
R
.
fonts
.
fontRegular
,
fontSize
:
R
.
fontsize
.
fontSizeContent
,
},
text
:
{
fontSize
:
R
.
sizes
.
sm
,
color
:
R
.
colors
.
black
,
...
...
src/screens/list_work/view.js
View file @
9ce41d07
...
...
@@ -23,6 +23,7 @@ const ListWorkView = props => {
setSearchQuery
,
dataList
,
modalVisible
,
tabView
,
onFilterChange
,
onAddWork
,
onSaveWork
,
...
...
@@ -31,37 +32,20 @@ const ListWorkView = props => {
onReportAction
,
onApprovalAction
,
getStatusColor
,
getButtonsForStatus
,
tabView
,
getButtonsForStatus
}
=
props
;
const
renderTabView
=
()
=>
{
return
(
<
TabViewComponent
data
=
{
tabView
}
tabStyle
=
{{
backgroundColor
:
R
.
colors
.
gray
,
marginHorizontal
:
5
,
borderRadius
:
10
,
width
:
107
,
justifyContent
:
'center'
,
alignItems
:
'center'
,
}}
style
=
{{
marginVertical
:
5
,
}}
tabStyle
=
{
styles
.
item_tab_view
}
style
=
{
styles
.
container_tab_view
}
mode
=
"filter"
defaultActiveKey
=
"all"
scrollable
=
{
true
}
activeTabStyle
=
{{
backgroundColor
:
R
.
colors
.
blue
,
}}
textStyle
=
{{
color
:
R
.
colors
.
white
,
fontWeight
:
'400'
,
fontFamily
:
R
.
fonts
.
fontRegular
,
fontSize
:
R
.
fontsize
.
fontSizeContent
,
}}
activeTabStyle
=
{
styles
.
active_tab_view
}
textStyle
=
{
styles
.
text_tab_view
}
showActiveIndicator
=
{
false
}
onFilterChange
=
{
onFilterChange
}
/
>
...
...
@@ -69,6 +53,7 @@ const ListWorkView = props => {
};
const
renderActionButtons
=
item
=>
{
const
buttons
=
getButtonsForStatus
(
item
.
status
);
return
buttons
.
map
((
button
,
index
)
=>
(
...
...
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