Để nguyên câu hỏi này, nếu không mô tả thêm cụ thể như thế nào thì chẳng hiểu gì để giúp.Dạ Chào Anh chị,
Em đang gặp lỗi code thêm hình ảnh và ngày tháng đảo lộn trong file nhập liệu nhân sự bằng userform
Nhờ anh chị hỗ trợ sửa giúp em với ạ
Em cám ơn ạ,
Vâng, sorry ạĐể nguyên câu hỏi này, nếu không mô tả thêm cụ thể như thế nào thì chẳng hiểu gì để giúp.




1. Thêm hình ảnh: Userform chỉ chấp nhận file ảnh với định dạng: jpg, bmp, svg. Do đó nếu bạn chọn khác định dạng (png) sẽ báo lỗi. Để giới hạn chỉ chọn file đúng định dạng thì bạn phải thiết lập thuộc tính Filter (chỉ hiển thị file jpg, bmp) trong hộp thoại chọn file để người dùng dễ lựa chọn.Em đang gặp lỗi code thêm hình ảnh và ngày tháng đảo lộn trong file nhập liệu nhân sự bằng userform



Vâng, mình mới đang học VBA, còn gà mờ1. Thêm hình ảnh: Userform chỉ chấp nhận file ảnh với định dạng: jpg, bmp, svg. Do đó nếu bạn chọn khác định dạng (png) sẽ báo lỗi. Để giới hạn chỉ chọn file đúng định dạng thì bạn phải thiết lập thuộc tính Filter (chỉ hiển thị file jpg, bmp) trong hộp thoại chọn file để người dùng dễ lựa chọn.
2. Ngày tháng: Theo tôi biết VBA xử lý ngày tháng theo dạng mm/dd/yyyy. Do đó bạn phải xử lý ngay ở Textbox nhập liệu.
- Textbox ngày phải nhập dạng: dd/mm/yyyy. 2 ký tự ngày, 2 ký tự cho tháng và 4 ký tự cho năm. Bạn phải bẫy lỗi nhập liệu này để người dùng nhập cho đúng định dạng.
- Code chuyển đổi ngày như bên dưới.
View attachment 310073
3. Form còn nhiều lỗi nhập liệu:
- Khi mở form, bấm thêm mới sẽ thêm liên tục mặc dù không có dữ liệu.
- Sau khi nhập msnv, bấm Search sẽ nạp dữ liệu lên UF. Bấm cập nhật nó sẽ tạo thêm dòng mới giống như vậy --> lỗi trùng dữ liệu.
- Nói chung khi mở UF lên, bấm lung tung các nút lệnh sẽ thấy lỗi tùm lum.
- Form cập nhật dữ liệu lâu mặc dùng không có nhiều trường dữ liệu.
- Form nên thiết kế tách thông tin thành các tab (TabStrip) để dễ nhìn vào nhập liệu. VD: thông tin người phụ thuộc tách ra 1 tab khác.
- Nên dùng vòng lặp duyệt qua các control (textbox, comboBox...) để cập nhật giá trị từ Userform xuống sheet và ngược lại để code ngắn gọn hơn và cũng dễ điều chỉnh. (Thay vì gán từng textbox xuống từng cell như hiện tại).
Tham khảo:
View attachment 310074
View attachment 310075
Vâng ạ, việc phân loại trường dữ liệu ra cũng giúp dễ nhìn, dễ nhập liệu và dễ quản lý hơnĐầu tiên mình muốn lưu ý với bạn là vấn đề thiết kế CSDL;
1./ Mã số nhân viên
Hiện bạn đang xài dẫy số vô tri giác;
Nếu là mình thì xài bộ mã sau:
View attachment 310072
2./ Cũng trang CSDL này cần tách ra thành chí ít là 3 trang tính;
Trang đầu là những gì bất biến trong đời người sẽ lao động ở cơ quan bạn;
Ví du [Mã NV], [HoTen], [Ngày sinh], [Giới tính], [Địa chỉ], [SĐT],. . . .
Trang thứ 2 sẽ là
[Mã NV], [Ngày], Loại HĐLĐ], [Ghi chú]
Trang thứ 3 sẽ là về BHXH:
[Mã NV], [Số sổ BHXH], [Hôn nhân], [QH], [Họ tên người QH], [Ghi chú]
Hai trang này ghi dữ liệu theo chiều dọc; Không phải chiều ngang như bạn đang làm;
. . . .
Vâng, em xin bác nhé! Em cám ơnNếu là mình thì sẽ theo đường hướng được phát thảo theo file!
![]()
![]()
- Gõ chữ thường và nhấn tìm kiếm nó trơ trơ. Hay là thêm cái Ucase?Bạn xem thêm file mới & tiếp tục sửa chữa các Controls sao chúng tường minh hơn phần tên gọi
Private Sub cmdThem_Click()
Dim ws As Worksheet
Dim nextRow As Long
Set ws = ThisWorkbook.Sheets("HDLD")
nextRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
ws.Cells(nextRow, "A").Value = nextRow - 1 ' STT
ws.Cells(nextRow, "B").Value = txtMaNV.Value
ws.Cells(nextRow, "C").Value = dtpNgayHD.Value
ws.Cells(nextRow, "D").Value = cmbLoaiHD.Value
ws.Cells(nextRow, "E").Value = txtGhiChu.Value
MsgBox "Đã thêm hợp đồng mới!"
Call LoadDanhSachHDLD
End Sub
[/HEADING]
Private Sub cmdSua_Click()
Dim ws As Worksheet\
Dim selectedRow As Long
If lstHDLD.ListIndex = -1 Then
MsgBox "Bạn chưa chọn dòng để sửa!"
Exit Sub
End If
Set ws = ThisWorkbook.Sheets("HDLD")
selectedRow = lstHDLD.List(lstHDLD.ListIndex, 0) + 1 ' STT + 1 vì dòng bắt đầu từ 2
ws.Cells(selectedRow + 1, "B").Value = txtMaNV.Value
ws.Cells(selectedRow + 1, "C").Value = dtpNgayHD.Value
ws.Cells(selectedRow + 1, "D").Value = cmbLoaiHD.Value
ws.Cells(selectedRow + 1, "E").Value = txtGhiChu.Value
MsgBox "Đã sửa hợp đồng!"
Call LoadDanhSachHDLD
End Sub
Private Sub cmdXoa_Click()
Dim ws As Worksheet
Dim selectedRow As Long
If lstHDLD.ListIndex = -1 Then
MsgBox "Bạn chưa chọn dòng để xóa!"
Exit Sub
End If
Set ws = ThisWorkbook.Sheets("HDLD")
selectedRow = lstHDLD.List(lstHDLD.ListIndex, 0) + 1 ws.Rows(selectedRow + 1).Delete
MsgBox "Đã xóa hợp đồng!"
Call LoadDanhSachHDLD
End Sub
Sub LoadDanhSachHDLD()
Dim ws As Worksheet
Dim i As Long, lastRow As Long
Set ws = ThisWorkbook.Sheets("HDLD")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lstHDLD.Clear
lstHDLD.ColumnCount = 5
lstHDLD.ColumnWidths = "40;80;100;100;150"
For i = 2 To lastRow
lstHDLD.AddItem ws.Cells(i, "A").Value
lstHDLD.List(lstHDLD.ListCount - 1, 1) = ws.Cells(i, "B").Value
lstHDLD.List(lstHDLD.ListCount - 1, 2) = Format(ws.Cells(i, "C").Value, "dd/mm/yyyy")
lstHDLD.List(lstHDLD.ListCount - 1, 3) = ws.Cells(i, "D").Value
lstHDLD.List(lstHDLD.ListCount - 1, 4) = ws.Cells(i, "E").Value
Next i
End Sub
Vâng, bác hoàn thiện file giúp em với ạ để em được mở mang tầm mắt và học hỏi từ từng đoạn code đó. Em cảm ơn ạ[Copilot & Hợp đồng lao động]
Bạn đang đi đúng hướng rồi đó! Việc hiểu Dictionary sẽ giúp bạn xử lý dữ liệu hiệu quả hơn sau này, nhưng nếu chưa quen thì mình có thể hướng dẫn bạn cách nhập mới, sửa, xóa hợp đồng lao động theo cách đơn giản hơn — không cần dùng Dictionary ngay đâu
Cách xử lý dữ liệu HĐLĐ: Nhập mới, sửa, xóa
Giả sử bạn có một sheet tên là HDLD với các cột:
A: STT
B: MaNV
C: NgayHD
D: LoaiHD
E: GhiChu
Trên UserForm, bạn có thể có:
- Các ô nhập liệu: txtMaNV, dtpNgayHD, cmbLoaiHD, txtGhiChu
- Một ListBox tên lstHDLD để hiển thị danh sách hợp đồng
- Các nút: cmdThem, cmdSua, cmdXoa
1. Nhập mới hợp đồng
PHP:Private Sub cmdThem_Click() Dim ws As Worksheet Dim nextRow As Long Set ws = ThisWorkbook.Sheets("HDLD") nextRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1 ws.Cells(nextRow, "A").Value = nextRow - 1 ' STT ws.Cells(nextRow, "B").Value = txtMaNV.Value ws.Cells(nextRow, "C").Value = dtpNgayHD.Value ws.Cells(nextRow, "D").Value = cmbLoaiHD.Value ws.Cells(nextRow, "E").Value = txtGhiChu.Value MsgBox "Đã thêm hợp đồng mới!" Call LoadDanhSachHDLD End Sub
2. Sửa hợp đồng đã chọn
Mã:[/HEADING][/HEADING] [HEADING=2]Private Sub cmdSua_Click()[/HEADING] [HEADING=2]Dim ws As Worksheet\[/HEADING] [HEADING=2]Dim selectedRow As Long[/HEADING] [HEADING=2]If lstHDLD.ListIndex = -1 Then[/HEADING] [HEADING=2] MsgBox "Bạn chưa chọn dòng để sửa!"[/HEADING] [HEADING=2] Exit Sub[/HEADING] [HEADING=2]End If[/HEADING] [HEADING=2]Set ws = ThisWorkbook.Sheets("HDLD")[/HEADING] [HEADING=2]selectedRow = lstHDLD.List(lstHDLD.ListIndex, 0) + 1 ' STT + 1 vì dòng bắt đầu từ 2[/HEADING] [HEADING=2]ws.Cells(selectedRow + 1, "B").Value = txtMaNV.Value[/HEADING] [HEADING=2]ws.Cells(selectedRow + 1, "C").Value = dtpNgayHD.Value[/HEADING] [HEADING=2]ws.Cells(selectedRow + 1, "D").Value = cmbLoaiHD.Value[/HEADING] [HEADING=2]ws.Cells(selectedRow + 1, "E").Value = txtGhiChu.Value[/HEADING] [HEADING=2]MsgBox "Đã sửa hợp đồng!"[/HEADING] [HEADING=2] Call LoadDanhSachHDLD[/HEADING] [HEADING=2]End Sub
️ 3. Xóa hợp đồng đã chọn
PHP:Private Sub cmdXoa_Click()[/HEADING] [HEADING=2] Dim ws As Worksheet[/HEADING] [HEADING=2] Dim selectedRow As Long[/HEADING] [HEADING=2] If lstHDLD.ListIndex = -1 Then[/HEADING] [HEADING=2] MsgBox "Bạn chưa chọn dòng để xóa!"[/HEADING] [HEADING=2] Exit Sub[/HEADING] [HEADING=2] End If[/HEADING] [HEADING=2] Set ws = ThisWorkbook.Sheets("HDLD")[/HEADING] [HEADING=2] selectedRow = lstHDLD.List(lstHDLD.ListIndex, 0) + 1 ws.Rows(selectedRow + 1).Delete[/HEADING] [HEADING=2] MsgBox "Đã xóa hợp đồng!"[/HEADING] [HEADING=2] Call LoadDanhSachHDLD[/HEADING] [HEADING=2]End Sub
Hàm nạp lại danh sách vào ListBox
Mã:Sub LoadDanhSachHDLD()[/HEADING] [HEADING=2] Dim ws As Worksheet[/HEADING] [HEADING=2] Dim i As Long, lastRow As Long[/HEADING] [HEADING=2] Set ws = ThisWorkbook.Sheets("HDLD")[/HEADING] [HEADING=2] lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row[/HEADING] [HEADING=2] lstHDLD.Clear[/HEADING] [HEADING=2] lstHDLD.ColumnCount = 5[/HEADING] [HEADING=2] lstHDLD.ColumnWidths = "40;80;100;100;150"[/HEADING] [HEADING=2] For i = 2 To lastRow[/HEADING] [HEADING=2] lstHDLD.AddItem ws.Cells(i, "A").Value[/HEADING] [HEADING=2] lstHDLD.List(lstHDLD.ListCount - 1, 1) = ws.Cells(i, "B").Value[/HEADING] [HEADING=2] lstHDLD.List(lstHDLD.ListCount - 1, 2) = Format(ws.Cells(i, "C").Value, "dd/mm/yyyy")[/HEADING] [HEADING=2] lstHDLD.List(lstHDLD.ListCount - 1, 3) = ws.Cells(i, "D").Value[/HEADING] [HEADING=2] lstHDLD.List(lstHDLD.ListCount - 1, 4) = ws.Cells(i, "E").Value[/HEADING] [HEADING=2] Next i[/HEADING] [HEADING=2]End Sub
Bạn có thể thử từng phần một, rồi mình sẽ giúp bạn gắn kết lại thành một hệ thống hoàn chỉnh. Nếu bạn muốn mình tạo sơ đồ luồng xử lý hoặc gợi ý cách tổ chức form đẹp hơn, mình làm ngay nhé!
Bạn không để ý ở đoạn trên, Bác ấy copy lời của AI Copilot. Chứ có phải bác ấy làm đâu.Vâng, bác hoàn thiện file giúp em với ạ để em được mở mang tầm mắt và học hỏi từ từng đoạn code đó. Em cảm ơn ạ
Không đơn giản thế. Khi đã có mục tìm kiếm thì danh sách sẽ rút gọn lại. Thứ tự trên list không còn là thứ tự trên sheet nữa. Tìm kiếm với danh sách ngắn dần là biện pháp chủ yếu để sửa xóa khi list có sẵn rất dài.Copilot & Hợp đồng lao động
Cái AI nào cũng vậy, phải biết cách hỏi, mà muốn hỏi phải biết rõ vấn đề.Bác có xài qua DeepSeek chưa? Em thấy DSeek nó trả lời và đưa code mẫu nhiều trường hợp, từ code cơ bản đến code nâng cao cho 1 vấn đề mình hỏi.


Mình cho rằng cần lưu ý mạnh mẽ hơn đến bạn chưa phải là Code như thế nào mà thiết kế lại CSDL;Vâng, bác hoàn thiện file giúp em với ạ để em được mở mang tầm mắt và học hỏi từ từng đoạn code đó. Em cảm ơn ạ





Vâng bác, đúng là thiếu sót rồi. Em xin phép gửi lại bản này, đầy đủ hơn chút so với bản #1 ạMình cho rằng cần lưu ý mạnh mẽ hơn đến bạn chưa phải là Code như thế nào mà thiết kế lại CSDL;
Ngay trong file của bạn (Ở #1) cũng chưa chú tâm đến dữ liệu
→ Chỉ có 1 mống & chưa đầy đủ nữa, đến tệ
Chí ít CQ (cơ quan) của bạn ~100 thì cần chí ít mươi người;
Chí ít CQ có 7 đơn vị thì mươi người đó rãi đều khắp ở 7 đơn vị;
Chí ít có 2 loại hợp đồng dài hạn & ngắn hạn (từ 1 đến 3 năm) thì cần 4 loại hợp đồng tương ứng được rãi khắp
→ Một số người thường người ta lập các danh mục, như danh mục các đơn vị/bộ phận
Danh mục các loại hợp đồng lao động, danh mục các trình độ học thức hay chuyên môn/bậc thợ,. . .
Các danh mục này chí ít có 2 trường; đó là [Mã danh mục] & [Tên danh mục]
Trên trang dữ liệu các cột sẽ không thể hiện tên danh mục mà là mã danh mục;
& cuối cùng đó là nếu bạn không thiết kế lại CSDL thì ai đó giúp bạn trên nền tảng file #1 là vô tính hay hữu ý hại bạn mà thôi!
Hay quá ạ, bác cho em xin contact, e hỏi kỹ hơn đc k?Thấy bài cũng xôm tụ nên tôi cũng góp 1 file demo cho chủ thớt. Chỉ làm mẫu nhập liệu cơ bảng chừng 10 trường (cột) của bảng thôi. Chủ yếu là chức năng:
- Tìm kiếm trong listbox
- Lưu, Thêm, Xoá dữ liệu dùng cách lặp qua các control trên userform để lấy dữ liệu lên form hoặc ghi xuống sheet. Chịu khó thêm các tham số trong thuộc tính Tag của control.
Form chưa bẫy lỗi gì nhiều nên sẽ có phát sinh các hoạt động không như ý muốn. Chủ yếu tham khảo cái qui trình nhập liệu (tôi hay làm theo kiểu này).
- Tôi có tách cái bảng của chủ thớt thành 3 bảng con để CSDL cho nó chuẩn hoá.
- Thuộc tính Tag: "2_req": Tôi qui ước số 2 là cột lưu trường [Họ tên], "req" là bắt buộc phải nhập liệu, từ khoá này dùng trong hàm kiểm tra tính hợp lệ của dữ liệu nhập trước khi [Lưu].
View attachment 310128
View attachment 310129