Browse Source

Merge branch 'yuhongzhe' into wangzeyan

master
王泽彦 10 months ago
parent
commit
8d208a6015
  1. 35
      admin/src/app/api/attendance.ts
  2. 25
      admin/src/app/api/contract.ts
  3. 33
      admin/src/app/api/exam_answers.ts
  4. 23
      admin/src/app/api/exam_papers.ts
  5. 23
      admin/src/app/api/exam_questions.ts
  6. 29
      admin/src/app/api/exam_records.ts
  7. 30
      admin/src/app/api/performance_records.ts
  8. 60
      admin/src/app/api/student.ts
  9. 46
      admin/src/app/lang/zh-cn/attendance.attendance.json
  10. 40
      admin/src/app/lang/zh-cn/contract.contract.json
  11. 33
      admin/src/app/lang/zh-cn/exam_answers.exam_answers.json
  12. 28
      admin/src/app/lang/zh-cn/exam_papers.exam_papers.json
  13. 51
      admin/src/app/lang/zh-cn/exam_questions.exam_questions.json
  14. 40
      admin/src/app/lang/zh-cn/exam_records.exam_records.json
  15. 40
      admin/src/app/lang/zh-cn/performance_records.performance_records.json
  16. 31
      admin/src/app/lang/zh-cn/student.student.json
  17. 289
      admin/src/app/views/attendance/attendance.vue
  18. 244
      admin/src/app/views/attendance/components/attendance-edit.vue
  19. 5
      admin/src/app/views/campus_person_role/campus_person_role.vue
  20. 194
      admin/src/app/views/contract/components/contract-edit.vue
  21. 240
      admin/src/app/views/contract/contract.vue
  22. 160
      admin/src/app/views/exam_answers/components/exam-answers-edit.vue
  23. 191
      admin/src/app/views/exam_answers/exam_answers.vue
  24. 323
      admin/src/app/views/exam_papers/components/exam-papers-edit.vue
  25. 155
      admin/src/app/views/exam_papers/exam_papers.vue
  26. 287
      admin/src/app/views/exam_questions/components/exam-questions-edit.vue
  27. 328
      admin/src/app/views/exam_questions/exam_questions.vue
  28. 192
      admin/src/app/views/exam_records/components/exam-records-edit.vue
  29. 232
      admin/src/app/views/exam_records/exam_records.vue
  30. 204
      admin/src/app/views/performance_records/components/performance-records-edit.vue
  31. 262
      admin/src/app/views/performance_records/performance_records.vue
  32. 315
      admin/src/app/views/student/components/student-edit.vue
  33. 240
      admin/src/app/views/student/student.vue
  34. 32
      niucloud/app/adminapi/controller/attendance/Attendance.php
  35. 15
      niucloud/app/adminapi/controller/contract/Contract.php
  36. 4
      niucloud/app/adminapi/controller/customer_resources/CustomerResources.php
  37. 18
      niucloud/app/adminapi/controller/exam_answers/ExamAnswers.php
  38. 7
      niucloud/app/adminapi/controller/exam_papers/ExamPapers.php
  39. 35
      niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php
  40. 26
      niucloud/app/adminapi/controller/exam_records/ExamRecords.php
  41. 20
      niucloud/app/adminapi/controller/performance_records/PerformanceRecords.php
  42. 121
      niucloud/app/adminapi/controller/student/Student.php
  43. 9
      niucloud/app/adminapi/route/attendance.php
  44. 2
      niucloud/app/adminapi/route/contract.php
  45. 9
      niucloud/app/adminapi/route/exam_answers.php
  46. 1
      niucloud/app/adminapi/route/exam_papers.php
  47. 1
      niucloud/app/adminapi/route/exam_questions.php
  48. 7
      niucloud/app/adminapi/route/exam_records.php
  49. 7
      niucloud/app/adminapi/route/performance_records.php
  50. 44
      niucloud/app/adminapi/route/student.php
  51. 64
      niucloud/app/model/attendance/Attendance.php
  52. 128
      niucloud/app/model/contract/Contract.php
  53. 74
      niucloud/app/model/exam_answers/ExamAnswers.php
  54. 40
      niucloud/app/model/exam_papers/ExamPapers.php
  55. 147
      niucloud/app/model/exam_questions/ExamQuestions.php
  56. 80
      niucloud/app/model/exam_records/ExamRecords.php
  57. 92
      niucloud/app/model/performance_records/PerformanceRecords.php
  58. 97
      niucloud/app/model/student/Student.php
  59. 20
      niucloud/app/service/admin/attendance/AttendanceService.php
  60. 2
      niucloud/app/service/admin/contract/ContractService.php
  61. 6
      niucloud/app/service/admin/customer_resources/CustomerResourcesService.php
  62. 23
      niucloud/app/service/admin/exam_answers/ExamAnswersService.php
  63. 6
      niucloud/app/service/admin/exam_papers/ExamPapersService.php
  64. 6
      niucloud/app/service/admin/exam_questions/ExamQuestionsService.php
  65. 22
      niucloud/app/service/admin/exam_records/ExamRecordsService.php
  66. 22
      niucloud/app/service/admin/performance_records/PerformanceRecordsService.php
  67. 117
      niucloud/app/service/admin/student/StudentService.php
  68. 8
      niucloud/app/validate/attendance/Attendance.php
  69. 4
      niucloud/app/validate/contract/Contract.php
  70. 10
      niucloud/app/validate/exam_papers/ExamPapers.php
  71. 10
      niucloud/app/validate/exam_questions/ExamQuestions.php
  72. 2
      niucloud/app/validate/exam_records/ExamRecords.php
  73. 6
      niucloud/app/validate/performance_records/PerformanceRecords.php
  74. 43
      niucloud/app/validate/student/Student.php

35
admin/src/app/api/attendance.ts

@ -1,5 +1,15 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- attendance
/**
*
@ -7,7 +17,7 @@ import request from '@/utils/request'
* @returns
*/
export function getAttendanceList(params: Record<string, any>) {
return request.get(`attendance/attendance`, { params })
return request.get(`attendance/attendance`, {params})
}
/**
@ -16,7 +26,7 @@ export function getAttendanceList(params: Record<string, any>) {
* @returns
*/
export function getAttendanceInfo(id: number) {
return request.get(`attendance/attendance/${id}`)
return request.get(`attendance/attendance/${id}`);
}
/**
@ -25,10 +35,7 @@ export function getAttendanceInfo(id: number) {
* @returns
*/
export function addAttendance(params: Record<string, any>) {
return request.post('attendance/attendance', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('attendance/attendance', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +45,7 @@ export function addAttendance(params: Record<string, any>) {
* @returns
*/
export function editAttendance(params: Record<string, any>) {
return request.put(`attendance/attendance/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`attendance/attendance/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +54,13 @@ export function editAttendance(params: Record<string, any>) {
* @returns
*/
export function deleteAttendance(id: number) {
return request.delete(`attendance/attendance/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`attendance/attendance/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('attendance/campus_all', {params})
}export function getWithPersonnelList(params: Record<string,any>){
return request.get('attendance/personnel_all', {params})
}
// USER_CODE_END -- attendance

25
admin/src/app/api/contract.ts

@ -1,5 +1,9 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- contract
/**
*
@ -7,7 +11,7 @@ import request from '@/utils/request'
* @returns
*/
export function getContractList(params: Record<string, any>) {
return request.get(`contract/contract`, { params })
return request.get(`contract/contract`, {params})
}
/**
@ -16,7 +20,7 @@ export function getContractList(params: Record<string, any>) {
* @returns
*/
export function getContractInfo(id: number) {
return request.get(`contract/contract/${id}`)
return request.get(`contract/contract/${id}`);
}
/**
@ -25,10 +29,7 @@ export function getContractInfo(id: number) {
* @returns
*/
export function addContract(params: Record<string, any>) {
return request.post('contract/contract', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('contract/contract', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +39,7 @@ export function addContract(params: Record<string, any>) {
* @returns
*/
export function editContract(params: Record<string, any>) {
return request.put(`contract/contract/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`contract/contract/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +48,9 @@ export function editContract(params: Record<string, any>) {
* @returns
*/
export function deleteContract(id: number) {
return request.delete(`contract/contract/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`contract/contract/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- contract

33
admin/src/app/api/exam_answers.ts

@ -1,5 +1,11 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_answers
/**
*
@ -7,7 +13,7 @@ import request from '@/utils/request'
* @returns
*/
export function getExamAnswersList(params: Record<string, any>) {
return request.get(`exam_answers/exam_answers`, { params })
return request.get(`exam_answers/exam_answers`, {params})
}
/**
@ -16,7 +22,7 @@ export function getExamAnswersList(params: Record<string, any>) {
* @returns
*/
export function getExamAnswersInfo(id: number) {
return request.get(`exam_answers/exam_answers/${id}`)
return request.get(`exam_answers/exam_answers/${id}`);
}
/**
@ -25,10 +31,7 @@ export function getExamAnswersInfo(id: number) {
* @returns
*/
export function addExamAnswers(params: Record<string, any>) {
return request.post('exam_answers/exam_answers', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('exam_answers/exam_answers', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +41,7 @@ export function addExamAnswers(params: Record<string, any>) {
* @returns
*/
export function editExamAnswers(params: Record<string, any>) {
return request.put(`exam_answers/exam_answers/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`exam_answers/exam_answers/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +50,15 @@ export function editExamAnswers(params: Record<string, any>) {
* @returns
*/
export function deleteExamAnswers(id: number) {
return request.delete(`exam_answers/exam_answers/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`exam_answers/exam_answers/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('exam_answers/campus_all', {params})
}export function getWithPersonnelList(params: Record<string,any>){
return request.get('exam_answers/personnel_all', {params})
}export function getWithExamQuestionsList(params: Record<string,any>){
return request.get('exam_answers/exam_questions_all', {params})
}
// USER_CODE_END -- exam_answers

23
admin/src/app/api/exam_papers.ts

@ -1,5 +1,7 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_papers
/**
*
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns
*/
export function getExamPapersList(params: Record<string, any>) {
return request.get(`exam_papers/exam_papers`, { params })
return request.get(`exam_papers/exam_papers`, {params})
}
/**
@ -16,7 +18,7 @@ export function getExamPapersList(params: Record<string, any>) {
* @returns
*/
export function getExamPapersInfo(id: number) {
return request.get(`exam_papers/exam_papers/${id}`)
return request.get(`exam_papers/exam_papers/${id}`);
}
/**
@ -25,10 +27,7 @@ export function getExamPapersInfo(id: number) {
* @returns
*/
export function addExamPapers(params: Record<string, any>) {
return request.post('exam_papers/exam_papers', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('exam_papers/exam_papers', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +37,7 @@ export function addExamPapers(params: Record<string, any>) {
* @returns
*/
export function editExamPapers(params: Record<string, any>) {
return request.put(`exam_papers/exam_papers/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`exam_papers/exam_papers/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +46,9 @@ export function editExamPapers(params: Record<string, any>) {
* @returns
*/
export function deleteExamPapers(id: number) {
return request.delete(`exam_papers/exam_papers/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`exam_papers/exam_papers/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_papers

23
admin/src/app/api/exam_questions.ts

@ -1,5 +1,7 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_questions
/**
*
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns
*/
export function getExamQuestionsList(params: Record<string, any>) {
return request.get(`exam_questions/exam_questions`, { params })
return request.get(`exam_questions/exam_questions`, {params})
}
/**
@ -16,7 +18,7 @@ export function getExamQuestionsList(params: Record<string, any>) {
* @returns
*/
export function getExamQuestionsInfo(id: number) {
return request.get(`exam_questions/exam_questions/${id}`)
return request.get(`exam_questions/exam_questions/${id}`);
}
/**
@ -25,10 +27,7 @@ export function getExamQuestionsInfo(id: number) {
* @returns
*/
export function addExamQuestions(params: Record<string, any>) {
return request.post('exam_questions/exam_questions', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('exam_questions/exam_questions', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +37,7 @@ export function addExamQuestions(params: Record<string, any>) {
* @returns
*/
export function editExamQuestions(params: Record<string, any>) {
return request.put(`exam_questions/exam_questions/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`exam_questions/exam_questions/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +46,9 @@ export function editExamQuestions(params: Record<string, any>) {
* @returns
*/
export function deleteExamQuestions(id: number) {
return request.delete(`exam_questions/exam_questions/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`exam_questions/exam_questions/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_questions

29
admin/src/app/api/exam_records.ts

@ -1,5 +1,7 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_records
/**
*
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns
*/
export function getExamRecordsList(params: Record<string, any>) {
return request.get(`exam_records/exam_records`, { params })
return request.get(`exam_records/exam_records`, {params})
}
/**
@ -16,7 +18,7 @@ export function getExamRecordsList(params: Record<string, any>) {
* @returns
*/
export function getExamRecordsInfo(id: number) {
return request.get(`exam_records/exam_records/${id}`)
return request.get(`exam_records/exam_records/${id}`);
}
/**
@ -25,10 +27,7 @@ export function getExamRecordsInfo(id: number) {
* @returns
*/
export function addExamRecords(params: Record<string, any>) {
return request.post('exam_records/exam_records', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('exam_records/exam_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +37,7 @@ export function addExamRecords(params: Record<string, any>) {
* @returns
*/
export function editExamRecords(params: Record<string, any>) {
return request.put(`exam_records/exam_records/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`exam_records/exam_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +46,15 @@ export function editExamRecords(params: Record<string, any>) {
* @returns
*/
export function deleteExamRecords(id: number) {
return request.delete(`exam_records/exam_records/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`exam_records/exam_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('exam_records/campus_all', {params})
}export function getWithPersonnelList(params: Record<string,any>){
return request.get('exam_records/personnel_all', {params})
}export function getWithExamPapersList(params: Record<string,any>){
return request.get('exam_records/exam_papers_all', {params})
}
// USER_CODE_END -- exam_records

30
admin/src/app/api/performance_records.ts

@ -1,5 +1,7 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- performance_records
/**
*
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns
*/
export function getPerformanceRecordsList(params: Record<string, any>) {
return request.get(`performance_records/performance_records`, { params })
return request.get(`performance_records/performance_records`, {params})
}
/**
@ -16,7 +18,7 @@ export function getPerformanceRecordsList(params: Record<string, any>) {
* @returns
*/
export function getPerformanceRecordsInfo(id: number) {
return request.get(`performance_records/performance_records/${id}`)
return request.get(`performance_records/performance_records/${id}`);
}
/**
@ -25,10 +27,7 @@ export function getPerformanceRecordsInfo(id: number) {
* @returns
*/
export function addPerformanceRecords(params: Record<string, any>) {
return request.post('performance_records/performance_records', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('performance_records/performance_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,11 +37,7 @@ export function addPerformanceRecords(params: Record<string, any>) {
* @returns
*/
export function editPerformanceRecords(params: Record<string, any>) {
return request.put(
`performance_records/performance_records/${params.id}`,
params,
{ showErrorMessage: true, showSuccessMessage: true }
)
return request.put(`performance_records/performance_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -51,10 +46,15 @@ export function editPerformanceRecords(params: Record<string, any>) {
* @returns
*/
export function deletePerformanceRecords(id: number) {
return request.delete(`performance_records/performance_records/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`performance_records/performance_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithPersonnelList(params: Record<string,any>){
return request.get('performance_records/personnel_all', {params})
}export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('performance_records/customer_resources_all', {params})
}export function getWithOrderTableList(params: Record<string,any>){
return request.get('performance_records/order_table_all', {params})
}
// USER_CODE_END -- performance_records

60
admin/src/app/api/student.ts

@ -0,0 +1,60 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- student
/**
*
* @param params
* @returns
*/
export function getStudentList(params: Record<string, any>) {
return request.get(`student/student`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getStudentInfo(id: number) {
return request.get(`student/student/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addStudent(params: Record<string, any>) {
return request.post('student/student', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editStudent(params: Record<string, any>) {
return request.put(`student/student/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteStudent(id: number) {
return request.delete(`student/student/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('student/campus_all', {params})
}export function getWithClassGradeList(params: Record<string,any>){
return request.get('student/class_grade_all', {params})
}export function getWithMemberList(params: Record<string,any>){
return request.get('student/member_all', {params})
}
// USER_CODE_END -- student

46
admin/src/app/lang/zh-cn/attendance.attendance.json

@ -1,29 +1,21 @@
{
"id": "考勤编号",
"idPlaceholder": "请输入考勤编号",
"campusId": "校区ID",
"campusIdPlaceholder": "请输入校区ID",
"staffId": "人员ID",
"staffIdPlaceholder": "请输入人员ID",
"attendanceDate": "考勤日期",
"attendanceDatePlaceholder": "请输入考勤日期",
"checkInTime": "签到时间",
"checkInTimePlaceholder": "请输入签到时间",
"checkOutTime": "签退时间",
"checkOutTimePlaceholder": "请输入签退时间",
"status": "考勤状态",
"statusPlaceholder": "请输入考勤状态",
"remarks": "备注",
"remarksPlaceholder": "请输入备注",
"createdAt": "创建时间",
"createdAtPlaceholder": "请输入创建时间",
"updatedAt": "修改时间",
"updatedAtPlaceholder": "请输入修改时间",
"coordinate": "坐标",
"coordinatePlaceholder": "请输入坐标",
"addAttendance": "添加考勤",
"updateAttendance": "编辑考勤",
"attendanceDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"campusId":"校区",
"campusIdPlaceholder":"全部",
"staffId":"人员",
"staffIdPlaceholder":"全部",
"attendanceDate":"考勤日期",
"attendanceDatePlaceholder":"请输入考勤日期",
"checkInTime":"签到时间",
"checkInTimePlaceholder":"请输入签到时间",
"checkOutTime":"签退时间",
"checkOutTimePlaceholder":"请输入签退时间",
"remarks":"备注",
"remarksPlaceholder":"请输入备注",
"status":"考勤状态",
"statusPlaceholder":"请输入考勤状态",
"addAttendance":"添加考勤",
"updateAttendance":"编辑考勤",
"attendanceDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

40
admin/src/app/lang/zh-cn/contract.contract.json

@ -1,25 +1,19 @@
{
"id": "合同编号",
"idPlaceholder": "请输入合同编号",
"contractName": "合同名称",
"contractNamePlaceholder": "请输入合同名称",
"contractTemplate": "合同模板",
"contractTemplatePlaceholder": "请输入合同模板",
"contractStatus": "合同状态",
"contractStatusPlaceholder": "请输入合同状态",
"contractType": "合同类型",
"contractTypePlaceholder": "请输入合同类型",
"remarks": "合同备注",
"remarksPlaceholder": "请输入合同备注",
"createdAt": "创建时间",
"createdAtPlaceholder": "请输入创建时间",
"updatedAt": "修改时间",
"updatedAtPlaceholder": "请输入修改时间",
"deletedAt": "逻辑删除时间",
"deletedAtPlaceholder": "请输入逻辑删除时间",
"addContract": "添加合同",
"updateContract": "编辑合同",
"contractDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"contractName":"合同名称",
"contractNamePlaceholder":"请输入合同名称",
"contractTemplate":"合同模板",
"contractTemplatePlaceholder":"请输入合同模板",
"contractStatus":"合同状态",
"contractStatusPlaceholder":"请输入合同状态",
"contractType":"合同类型",
"contractTypePlaceholder":"请输入合同类型",
"remarks":"合同备注",
"remarksPlaceholder":"请输入合同备注",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"addContract":"添加合同",
"updateContract":"编辑合同",
"contractDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

33
admin/src/app/lang/zh-cn/exam_answers.exam_answers.json

@ -1,19 +1,18 @@
{
"id": "答题记录编号",
"idPlaceholder": "请输入答题记录编号",
"campusId": "校区ID",
"campusIdPlaceholder": "请输入校区ID",
"userId": "人员ID",
"userIdPlaceholder": "请输入人员ID",
"questionId": "试题ID",
"questionIdPlaceholder": "请输入试题ID",
"answer": "用户答案",
"answerPlaceholder": "请输入用户答案",
"isCorrect": "是否正确",
"isCorrectPlaceholder": "请输入是否正确",
"addExamAnswers": "添加答题记录",
"updateExamAnswers": "编辑答题记录",
"examAnswersDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"campusId":"校区",
"campusIdPlaceholder":"全部",
"userId":"人员",
"userIdPlaceholder":"请输入人员",
"questionId":"试题",
"questionIdPlaceholder":"请输入试题",
"answer":"用户答案",
"answerPlaceholder":"请输入用户答案",
"isCorrect":"是否正确",
"isCorrectPlaceholder":"请输入是否正确",
"createdAt":"创建时间",
"addExamAnswers":"添加答题记录",
"updateExamAnswers":"编辑答题记录",
"examAnswersDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

28
admin/src/app/lang/zh-cn/exam_papers.exam_papers.json

@ -1,15 +1,17 @@
{
"id": "试卷编号",
"idPlaceholder": "请输入试卷编号",
"selectionMode": "题目选择模式: random-随机主题, manual-自选题目",
"selectionModePlaceholder": "请输入题目选择模式: random-随机主题, manual-自选题目",
"totalScore": "总分",
"totalScorePlaceholder": "请输入总分",
"passingScore": "合格分数",
"passingScorePlaceholder": "请输入合格分数",
"addExamPapers": "添加试卷",
"updateExamPapers": "编辑试卷",
"examPapersDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"selectionMode":"题目选择模式",
"selectionModePlaceholder":"请输入题目选择模式",
"questionsIds":"自选试题",
"questionsIdsPlaceholder":"请输入自选试题",
"totalScore":"总分",
"totalScorePlaceholder":"请输入总分",
"passingScore":"合格分数",
"passingScorePlaceholder":"请输入合格分数",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"addExamPapers":"添加试卷",
"updateExamPapers":"编辑试卷",
"examPapersDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

51
admin/src/app/lang/zh-cn/exam_questions.exam_questions.json

@ -1,33 +1,22 @@
{
"id": "试题编号",
"idPlaceholder": "请输入试题编号",
"questionType": "题型: single_choice-单选, multiple_choice-多选, true_false-判断",
"questionTypePlaceholder": "请输入题型: single_choice-单选, multiple_choice-多选, true_false-判断",
"questionContentType": "题干类型: text-文本, image-图片",
"questionContentTypePlaceholder": "请输入题干类型: text-文本, image-图片",
"questionContent": "题干内容(如果是图片则存储URL)",
"questionContentPlaceholder": "请输入题干内容(如果是图片则存储URL)",
"optionAContentType": "选项A类型: text-文本, image-图片",
"optionAContentTypePlaceholder": "请输入选项A类型: text-文本, image-图片",
"optionAContent": "选项A内容(如果是图片则存储URL)",
"optionAContentPlaceholder": "请输入选项A内容(如果是图片则存储URL)",
"optionBContentType": "选项B类型: text-文本, image-图片",
"optionBContentTypePlaceholder": "请输入选项B类型: text-文本, image-图片",
"optionBContent": "选项B内容(如果是图片则存储URL)",
"optionBContentPlaceholder": "请输入选项B内容(如果是图片则存储URL)",
"optionCContentType": "选项C类型: text-文本, image-图片",
"optionCContentTypePlaceholder": "请输入选项C类型: text-文本, image-图片",
"optionCContent": "选项C内容(如果是图片则存储URL)",
"optionCContentPlaceholder": "请输入选项C内容(如果是图片则存储URL)",
"optionDContentType": "选项D类型: text-文本, image-图片",
"optionDContentTypePlaceholder": "请输入选项D类型: text-文本, image-图片",
"optionDContent": "选项D内容(如果是图片则存储URL)",
"optionDContentPlaceholder": "请输入选项D内容(如果是图片则存储URL)",
"correctAnswer": "正确答案(如果是多选,答案格式为如A,B,D)",
"correctAnswerPlaceholder": "请输入正确答案(如果是多选,答案格式为如A,B,D)",
"addExamQuestions": "添加试题",
"updateExamQuestions": "编辑试题",
"examQuestionsDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"title":"题目标题",
"titlePlaceholder":"请输入题目标题",
"questionType":"题型",
"questionTypePlaceholder":"请输入题型",
"questionContentType":"题干类型",
"questionContentTypePlaceholder":"请输入题干类型",
"questionContent":"题干内容",
"questionContentPlaceholder":"请输入题干内容",
"optionJson":"选项",
"optionJsonPlaceholder":"请输入选项",
"correctAnswer":"正确答案",
"correctAnswerPlaceholder":"请输入正确答案",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"addExamQuestions":"添加试题",
"updateExamQuestions":"编辑试题",
"examQuestionsDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

40
admin/src/app/lang/zh-cn/exam_records.exam_records.json

@ -1,23 +1,21 @@
{
"id": "记录编号",
"idPlaceholder": "请输入记录编号",
"campusId": "校区ID",
"campusIdPlaceholder": "请输入校区ID",
"userId": "人员ID",
"userIdPlaceholder": "请输入人员ID",
"paperId": "试卷ID",
"paperIdPlaceholder": "请输入试卷ID",
"score": "得分",
"scorePlaceholder": "请输入得分",
"status": "考试状态: in_progress-进行中, completed-已完成",
"statusPlaceholder": "请输入考试状态: in_progress-进行中, completed-已完成",
"startTime": "考试开始时间",
"startTimePlaceholder": "请输入考试开始时间",
"endTime": "考试结束时间",
"endTimePlaceholder": "请输入考试结束时间",
"addExamRecords": "添加考试记录",
"updateExamRecords": "编辑考试记录",
"examRecordsDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"campusId":"校区",
"campusIdPlaceholder":"全部",
"userId":"人员",
"userIdPlaceholder":"请输入人员",
"paperId":"试卷",
"paperIdPlaceholder":"全部",
"score":"得分",
"scorePlaceholder":"请输入得分",
"status":"考试状态",
"statusPlaceholder":"请输入考试状态",
"startTime":"考试开始时间",
"startTimePlaceholder":"请输入考试开始时间",
"endTime":"考试结束时间",
"endTimePlaceholder":"请输入考试结束时间",
"addExamRecords":"添加考试记录",
"updateExamRecords":"编辑考试记录",
"examRecordsDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

40
admin/src/app/lang/zh-cn/performance_records.performance_records.json

@ -1,23 +1,21 @@
{
"id": "绩效编号",
"idPlaceholder": "请输入绩效编号",
"staffId": "员工ID",
"staffIdPlaceholder": "请输入员工ID",
"resourceId": "资源ID",
"resourceIdPlaceholder": "请输入资源ID",
"orderId": "订单ID",
"orderIdPlaceholder": "请输入订单ID",
"orderStatus": "订单状态: pending-待处理, completed-已完成, cancelled-已取消",
"orderStatusPlaceholder": "请输入订单状态: pending-待处理, completed-已完成, cancelled-已取消",
"performanceType": "绩效类型: sales-销售绩效, marketing-市场绩效, other-其他",
"performanceTypePlaceholder": "请输入绩效类型: sales-销售绩效, marketing-市场绩效, other-其他",
"performanceValue": "绩效金额或分值",
"performanceValuePlaceholder": "请输入绩效金额或分值",
"remarks": "备注",
"remarksPlaceholder": "请输入备注",
"addPerformanceRecords": "添加绩效记录",
"updatePerformanceRecords": "编辑绩效记录",
"performanceRecordsDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
"staffId":"员工",
"staffIdPlaceholder":"全部",
"resourceId":"资源",
"resourceIdPlaceholder":"请输入资源",
"orderStatus":"订单状态",
"orderStatusPlaceholder":"请输入订单状态",
"performanceType":"绩效类型",
"performanceTypePlaceholder":"请输入绩效类型",
"performanceValue":"绩效金额或分值",
"performanceValuePlaceholder":"请输入绩效金额或分值",
"remarks":"备注",
"remarksPlaceholder":"请输入备注",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"addPerformanceRecords":"添加绩效记录",
"updatePerformanceRecords":"编辑绩效记录",
"performanceRecordsDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

31
admin/src/app/lang/zh-cn/student.student.json

@ -0,0 +1,31 @@
{
"campusId":"校区",
"campusIdPlaceholder":"全部",
"classId":"班级",
"classIdPlaceholder":"请输入班级",
"userId":"用户",
"userIdPlaceholder":"请输入用户",
"name":"学员姓名",
"namePlaceholder":"请输入学员姓名",
"gender":"性别",
"genderPlaceholder":"请输入性别",
"age":"年龄",
"agePlaceholder":"请输入年龄",
"birthday":"生日",
"birthdayPlaceholder":"请输入生日",
"emergencyContact":"紧急联系人",
"emergencyContactPlaceholder":"请输入紧急联系人",
"contactPhone":"联系人电话",
"contactPhonePlaceholder":"请输入联系人电话",
"note":"备注信息",
"notePlaceholder":"请输入备注信息",
"status":"学员状态",
"statusPlaceholder":"请输入学员状态",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"addStudent":"添加学员",
"updateStudent":"编辑学员",
"studentDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

289
admin/src/app/views/attendance/attendance.vue

@ -1,197 +1,110 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">
<span class="text-lg">{{pageName}}</span>
<!-- <el-button type="primary" @click="addEvent">
{{ t('addAttendance') }}
</el-button>
</el-button> -->
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="attendanceTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="attendanceTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="attendanceTable.searchParam.campus_id"
:placeholder="t('campusIdPlaceholder')"
/>
<el-select class="w-[280px]" v-model="attendanceTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="attendanceTable.searchParam.staff_id"
:placeholder="t('staffIdPlaceholder')"
/>
<el-select class="w-[280px]" v-model="attendanceTable.searchParam.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
<el-option
v-for="(item, index) in staffIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('attendanceDate')" prop="attendance_date">
<el-input
<el-date-picker
class="flex-1 !flex"
v-model="attendanceTable.searchParam.attendance_date"
:placeholder="t('attendanceDatePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('checkInTime')" prop="check_in_time">
<el-input
v-model="attendanceTable.searchParam.check_in_time"
:placeholder="t('checkInTimePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('checkOutTime')" prop="check_out_time">
<el-input
v-model="attendanceTable.searchParam.check_out_time"
:placeholder="t('checkOutTimePlaceholder')"
/>
clearable
type="date"
value-format="YYYY-MM-DD"
:placeholder="t('attendanceDate')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input
v-model="attendanceTable.searchParam.status"
:placeholder="t('statusPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input
v-model="attendanceTable.searchParam.remarks"
:placeholder="t('remarksPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input
v-model="attendanceTable.searchParam.created_at"
:placeholder="t('createdAtPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input
v-model="attendanceTable.searchParam.updated_at"
:placeholder="t('updatedAtPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('coordinate')" prop="coordinate">
<el-input
v-model="attendanceTable.searchParam.coordinate"
:placeholder="t('coordinatePlaceholder')"
/>
<el-select class="w-[280px]" v-model="attendanceTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadAttendanceList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadAttendanceList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="attendanceTable.data"
size="large"
v-loading="attendanceTable.loading"
>
<el-table :data="attendanceTable.data" size="large" v-loading="attendanceTable.loading">
<template #empty>
<span>{{ !attendanceTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="campus_id"
:label="t('campusId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="staff_id_name" :label="t('staffId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="attendance_date"
:label="t('attendanceDate')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="attendance_date" :label="t('attendanceDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="check_in_time"
:label="t('checkInTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="check_in_time" :label="t('checkInTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="check_out_time"
:label="t('checkOutTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="check_out_time" :label="t('checkOutTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="status"
:label="t('status')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="remarks" :label="t('remarks')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="created_at"
:label="t('createdAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="updated_at"
:label="t('updatedAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="coordinate"
:label="t('coordinate')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<!-- <el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column> -->
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="attendanceTable.page"
v-model:page-size="attendanceTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="attendanceTable.total"
@size-change="loadAttendanceList()"
@current-change="loadAttendanceList"
/>
<el-pagination v-model:current-page="attendanceTable.page" v-model:page-size="attendanceTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="attendanceTable.total"
@size-change="loadAttendanceList()" @current-change="loadAttendanceList" />
</div>
</div>
@ -204,13 +117,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getAttendanceList, deleteAttendance } from '@/app/api/attendance'
import { getAttendanceList, deleteAttendance, getWithCampusList, getWithPersonnelList } from '@/app/api/attendance'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/attendance/components/attendance-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let attendanceTable = reactive({
page: 1,
@ -218,18 +131,12 @@ let attendanceTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
campus_id: '',
staff_id: '',
attendance_date: '',
check_in_time: '',
check_out_time: '',
status: '',
remarks: '',
created_at: '',
updated_at: '',
coordinate: '',
},
searchParam:{
"campus_id":"",
"staff_id":"",
"attendance_date":"",
"status":""
}
})
const searchFormRef = ref<FormInstance>()
@ -238,6 +145,11 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('kq_status')).data.dictionary
}
statusDictList();
/**
* 获取考勤列表
@ -249,14 +161,12 @@ const loadAttendanceList = (page: number = 1) => {
getAttendanceList({
page: attendanceTable.page,
limit: attendanceTable.limit,
...attendanceTable.searchParam,
})
.then((res) => {
...attendanceTable.searchParam
}).then(res => {
attendanceTable.loading = false
attendanceTable.data = res.data.data
attendanceTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
attendanceTable.loading = false
})
}
@ -285,19 +195,32 @@ const editEvent = (data: any) => {
* 删除考勤
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('attendanceDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('attendanceDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteAttendance(id)
.then(() => {
}
).then(() => {
deleteAttendance(id).then(() => {
loadAttendanceList()
}).catch(() => {
})
.catch(() => {})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const staffIdList = ref([])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -314,5 +237,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

244
admin/src/app/views/attendance/components/attendance-edit.vue

@ -1,119 +1,84 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateAttendance') : t('addAttendance')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateAttendance') : t('addAttendance')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="formData.campus_id"
clearable
:placeholder="t('campusIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="formData.staff_id"
clearable
:placeholder="t('staffIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in staffIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('attendanceDate')" prop="attendance_date">
<el-input
<el-form-item :label="t('attendanceDate')" prop="attendance_date" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.attendance_date"
clearable
:placeholder="t('attendanceDatePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('attendanceDatePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('checkInTime')">
<el-input
<el-form-item :label="t('checkInTime')" prop="check_in_time" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.check_in_time"
clearable
:placeholder="t('checkInTimePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('checkInTimePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('checkOutTime')">
<el-input
<el-form-item :label="t('checkOutTime')" prop="check_out_time" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.check_out_time"
clearable
:placeholder="t('checkOutTimePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('checkOutTimePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input
v-model="formData.status"
clearable
:placeholder="t('statusPlaceholder')"
class="input-width"
/>
<el-form-item :label="t('remarks')" >
<el-input v-model="formData.remarks" clearable :placeholder="t('remarksPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('remarks')">
<el-input
v-model="formData.remarks"
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('createdAt')">
<el-input
v-model="formData.created_at"
clearable
:placeholder="t('createdAtPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('updatedAt')">
<el-input
v-model="formData.updated_at"
clearable
:placeholder="t('updatedAtPlaceholder')"
class="input-width"
<el-form-item :label="t('status')" prop="status">
<el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('coordinate')">
<el-input
v-model="formData.coordinate"
clearable
:placeholder="t('coordinatePlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -124,11 +89,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addAttendance,
editAttendance,
getAttendanceInfo,
} from '@/app/api/attendance'
import { addAttendance, editAttendance, getAttendanceInfo, getWithCampusList, getWithPersonnelList } from '@/app/api/attendance'
let showDialog = ref(false)
const loading = ref(false)
@ -143,11 +104,8 @@ const initialFormData = {
attendance_date: '',
check_in_time: '',
check_out_time: '',
status: '',
remarks: '',
created_at: '',
updated_at: '',
coordinate: '',
status: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
@ -158,42 +116,39 @@ const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
],
]
,
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
],
]
,
attendance_date: [
{
required: true,
message: t('attendanceDatePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('attendanceDatePlaceholder'), trigger: 'blur' },
]
,
check_in_time: [
{ required: true, message: t('checkInTimePlaceholder'), trigger: 'blur' },
],
]
,
check_out_time: [
{
required: true,
message: t('checkOutTimePlaceholder'),
trigger: 'blur',
},
],
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
],
{ required: true, message: t('checkOutTimePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' },
],
updated_at: [
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
],
coordinate: [
{ required: true, message: t('coordinatePlaceholder'), trigger: 'blur' },
],
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
}
})
@ -213,13 +168,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -227,14 +180,30 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('kq_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const staffIdList = ref([] as any[])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
if(row){
const data = await (await getAttendanceInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
@ -252,12 +221,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -284,13 +248,13 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

5
admin/src/app/views/campus_person_role/campus_person_role.vue

@ -49,7 +49,7 @@
</el-select>
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<!-- <el-form-item :label="t('roleId')" prop="role_id">
<el-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.role_id"
@ -63,7 +63,7 @@
:value="item['role_id']"
/>
</el-select>
</el-form-item>
</el-form-item> -->
<!-- <el-form-item :label="t('deptId')" prop="dept_id">
<el-select
@ -205,6 +205,7 @@ if(pageName == '市场人员列表'){
campusPersonRoleTable.searchParam.dept_id = 1;
}else if(pageName == '销售人员列表'){
campusPersonRoleTable.searchParam.dept_id = 2;
campusPersonRoleTable.searchParam.role_id = 2;
}else if(pageName == '教练管理'){
campusPersonRoleTable.searchParam.role_id = 5;
}

194
admin/src/app/views/contract/components/contract-edit.vue

@ -1,101 +1,50 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateContract') : t('addContract')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateContract') : t('addContract')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('contractName')" prop="contract_name">
<el-input
v-model="formData.contract_name"
clearable
:placeholder="t('contractNamePlaceholder')"
class="input-width"
/>
<el-input v-model="formData.contract_name" clearable :placeholder="t('contractNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('contractTemplate')" prop="contract_template">
<el-input
v-model="formData.contract_template"
clearable
:placeholder="t('contractTemplatePlaceholder')"
class="input-width"
/>
<el-form-item :label="t('contractTemplate')">
<upload-file v-model="formData.contract_template" />
</el-form-item>
<el-form-item :label="t('contractStatus')" prop="contract_status">
<el-input
v-model="formData.contract_status"
clearable
:placeholder="t('contractStatusPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.contract_status" clearable :placeholder="t('contractStatusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in contract_statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('contractType')" prop="contract_type">
<el-input
v-model="formData.contract_type"
clearable
:placeholder="t('contractTypePlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('remarks')">
<el-input
v-model="formData.remarks"
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.contract_type" clearable :placeholder="t('contractTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in contract_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('createdAt')">
<el-input
v-model="formData.created_at"
clearable
:placeholder="t('createdAtPlaceholder')"
class="input-width"
/>
<el-form-item :label="t('remarks')" >
<el-input v-model="formData.remarks" clearable :placeholder="t('remarksPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('updatedAt')">
<el-input
v-model="formData.updated_at"
clearable
:placeholder="t('updatedAtPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('deletedAt')">
<el-input
v-model="formData.deleted_at"
clearable
:placeholder="t('deletedAtPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -121,9 +70,6 @@ const initialFormData = {
contract_status: '',
contract_type: '',
remarks: '',
created_at: '',
updated_at: '',
deleted_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
@ -133,45 +79,30 @@ const formRef = ref<FormInstance>()
const formRules = computed(() => {
return {
contract_name: [
{
required: true,
message: t('contractNamePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('contractNamePlaceholder'), trigger: 'blur' },
]
,
contract_template: [
{
required: true,
message: t('contractTemplatePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('contractTemplatePlaceholder'), trigger: 'blur' },
]
,
contract_status: [
{
required: true,
message: t('contractStatusPlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('contractStatusPlaceholder'), trigger: 'blur' },
]
,
contract_type: [
{
required: true,
message: t('contractTypePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('contractTypePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' },
],
updated_at: [
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
],
deleted_at: [
{ required: true, message: t('deletedAtPlaceholder'), trigger: 'blur' },
],
]
,
}
})
@ -191,13 +122,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -205,14 +134,26 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let contract_statusList = ref([])
const contract_statusDictList = async () => {
contract_statusList.value = await (await useDictionary('ht_status')).data.dictionary
}
contract_statusDictList();
watch(() => contract_statusList.value, () => { formData.contract_status = contract_statusList.value[0].value })
let contract_typeList = ref([])
const contract_typeDictList = async () => {
contract_typeList.value = await (await useDictionary('ht_type')).data.dictionary
}
contract_typeDictList();
watch(() => contract_typeList.value, () => { formData.contract_type = contract_typeList.value[0].value })
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
if(row){
const data = await (await getContractInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
@ -230,12 +171,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -262,13 +198,13 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

240
admin/src/app/views/contract/contract.vue

@ -1,171 +1,91 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addContract') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="contractTable.searchParam"
ref="searchFormRef"
>
<el-form-item :label="t('contractName')" prop="contract_name">
<el-input
v-model="contractTable.searchParam.contract_name"
:placeholder="t('contractNamePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('contractTemplate')" prop="contract_template">
<el-input
v-model="contractTable.searchParam.contract_template"
:placeholder="t('contractTemplatePlaceholder')"
/>
</el-form-item>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="contractTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('contractStatus')" prop="contract_status">
<el-input
v-model="contractTable.searchParam.contract_status"
:placeholder="t('contractStatusPlaceholder')"
/>
<el-select class="w-[280px]" v-model="contractTable.searchParam.contract_status" clearable :placeholder="t('contractStatusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in contract_statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('contractType')" prop="contract_type">
<el-input
v-model="contractTable.searchParam.contract_type"
:placeholder="t('contractTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input
v-model="contractTable.searchParam.remarks"
:placeholder="t('remarksPlaceholder')"
/>
<el-select class="w-[280px]" v-model="contractTable.searchParam.contract_type" clearable :placeholder="t('contractTypePlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in contract_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input
v-model="contractTable.searchParam.created_at"
:placeholder="t('createdAtPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input
v-model="contractTable.searchParam.updated_at"
:placeholder="t('updatedAtPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('deletedAt')" prop="deleted_at">
<el-input
v-model="contractTable.searchParam.deleted_at"
:placeholder="t('deletedAtPlaceholder')"
/>
<el-date-picker v-model="contractTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadContractList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadContractList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="contractTable.data"
size="large"
v-loading="contractTable.loading"
>
<el-table :data="contractTable.data" size="large" v-loading="contractTable.loading">
<template #empty>
<span>{{ !contractTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="contract_name"
:label="t('contractName')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="contract_template"
:label="t('contractTemplate')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="contract_status"
:label="t('contractStatus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="contract_name" :label="t('contractName')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="contract_type"
:label="t('contractType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="created_at"
:label="t('createdAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('contractStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in contract_statusList">
<div v-if="item.value == row.contract_status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="updated_at"
:label="t('updatedAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('contractType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in contract_typeList">
<div v-if="item.value == row.contract_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="deleted_at"
:label="t('deletedAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="contractTable.page"
v-model:page-size="contractTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="contractTable.total"
@size-change="loadContractList()"
@current-change="loadContractList"
/>
<el-pagination v-model:current-page="contractTable.page" v-model:page-size="contractTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="contractTable.total"
@size-change="loadContractList()" @current-change="loadContractList" />
</div>
</div>
@ -180,11 +100,11 @@ import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getContractList, deleteContract } from '@/app/api/contract'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/contract/components/contract-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let contractTable = reactive({
page: 1,
@ -192,16 +112,11 @@ let contractTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
contract_name: '',
contract_template: '',
contract_status: '',
contract_type: '',
remarks: '',
created_at: '',
updated_at: '',
deleted_at: '',
},
searchParam:{
"contract_status":"",
"contract_type":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
@ -210,6 +125,16 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const contract_statusList = ref([] as any[])
const contract_statusDictList = async () => {
contract_statusList.value = await (await useDictionary('ht_status')).data.dictionary
}
contract_statusDictList();
const contract_typeList = ref([] as any[])
const contract_typeDictList = async () => {
contract_typeList.value = await (await useDictionary('ht_type')).data.dictionary
}
contract_typeDictList();
/**
* 获取合同列表
@ -221,14 +146,12 @@ const loadContractList = (page: number = 1) => {
getContractList({
page: contractTable.page,
limit: contractTable.limit,
...contractTable.searchParam,
})
.then((res) => {
...contractTable.searchParam
}).then(res => {
contractTable.loading = false
contractTable.data = res.data.data
contractTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
contractTable.loading = false
})
}
@ -257,19 +180,22 @@ const editEvent = (data: any) => {
* 删除合同
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('contractDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('contractDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteContract(id)
.then(() => {
}
).then(() => {
deleteContract(id).then(() => {
loadContractList()
}).catch(() => {
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -286,5 +212,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

160
admin/src/app/views/exam_answers/components/exam-answers-edit.vue

@ -1,74 +1,64 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateExamAnswers') : t('addExamAnswers')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateExamAnswers') : t('addExamAnswers')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="formData.campus_id"
clearable
:placeholder="t('campusIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-input
v-model="formData.user_id"
clearable
:placeholder="t('userIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in userIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('questionId')" prop="question_id">
<el-input
v-model="formData.question_id"
clearable
:placeholder="t('questionIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.question_id" clearable :placeholder="t('questionIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in questionIdList"
:key="index"
:label="item['title']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('answer')">
<el-input
v-model="formData.answer"
clearable
:placeholder="t('answerPlaceholder')"
class="input-width"
/>
<el-form-item :label="t('answer')" >
<el-input v-model="formData.answer" clearable :placeholder="t('answerPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('isCorrect')">
<el-input
v-model="formData.is_correct"
clearable
:placeholder="t('isCorrectPlaceholder')"
class="input-width"
/>
<el-form-item :label="t('isCorrect')" >
<el-radio-group v-model="formData.is_correct" :placeholder="t('isCorrectPlaceholder')">
<el-radio
v-for="(item, index) in is_correctList"
:key="index" :label="item.value">
{{ item.name }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -79,11 +69,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addExamAnswers,
editExamAnswers,
getExamAnswersInfo,
} from '@/app/api/exam_answers'
import { addExamAnswers, editExamAnswers, getExamAnswersInfo, getWithCampusList, getWithPersonnelList, getWithExamQuestionsList } from '@/app/api/exam_answers'
let showDialog = ref(false)
const loading = ref(false)
@ -108,19 +94,29 @@ const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
],
]
,
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
],
]
,
question_id: [
{ required: true, message: t('questionIdPlaceholder'), trigger: 'blur' },
],
]
,
answer: [
{ required: true, message: t('answerPlaceholder'), trigger: 'blur' },
],
]
,
is_correct: [
{ required: true, message: t('isCorrectPlaceholder'), trigger: 'blur' },
],
]
,
}
})
@ -140,13 +136,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -154,14 +148,35 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let is_correctList = ref([])
const is_correctDictList = async () => {
is_correctList.value = await (await useDictionary('is_correct')).data.dictionary
}
is_correctDictList();
watch(() => is_correctList.value, () => { formData.is_correct = is_correctList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const userIdList = ref([] as any[])
const setUserIdList = async () => {
userIdList.value = await (await getWithPersonnelList({})).data
}
setUserIdList()
const questionIdList = ref([] as any[])
const setQuestionIdList = async () => {
questionIdList.value = await (await getWithExamQuestionsList({})).data
}
setQuestionIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
if(row){
const data = await (await getExamAnswersInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
@ -179,12 +194,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -211,13 +221,13 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

191
admin/src/app/views/exam_answers/exam_answers.vue

@ -1,132 +1,70 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addExamAnswers') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="examAnswersTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="examAnswersTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="examAnswersTable.searchParam.campus_id"
:placeholder="t('campusIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-input
v-model="examAnswersTable.searchParam.user_id"
:placeholder="t('userIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('questionId')" prop="question_id">
<el-input
v-model="examAnswersTable.searchParam.question_id"
:placeholder="t('questionIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('answer')" prop="answer">
<el-input
v-model="examAnswersTable.searchParam.answer"
:placeholder="t('answerPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('isCorrect')" prop="is_correct">
<el-input
v-model="examAnswersTable.searchParam.is_correct"
:placeholder="t('isCorrectPlaceholder')"
<el-select class="w-[280px]" v-model="examAnswersTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadExamAnswersList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadExamAnswersList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="examAnswersTable.data"
size="large"
v-loading="examAnswersTable.loading"
>
<el-table :data="examAnswersTable.data" size="large" v-loading="examAnswersTable.loading">
<template #empty>
<span>{{ !examAnswersTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="campus_id"
:label="t('campusId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="user_id"
:label="t('userId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="question_id"
:label="t('questionId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="question_id_name" :label="t('questionId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="answer"
:label="t('answer')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="answer" :label="t('answer')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="is_correct"
:label="t('isCorrect')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('isCorrect')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in is_correctList">
<div v-if="item.value == row.is_correct">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="examAnswersTable.page"
v-model:page-size="examAnswersTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="examAnswersTable.total"
@size-change="loadExamAnswersList()"
@current-change="loadExamAnswersList"
/>
<el-pagination v-model:current-page="examAnswersTable.page" v-model:page-size="examAnswersTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="examAnswersTable.total"
@size-change="loadExamAnswersList()" @current-change="loadExamAnswersList" />
</div>
</div>
@ -139,13 +77,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getExamAnswersList, deleteExamAnswers } from '@/app/api/exam_answers'
import { getExamAnswersList, deleteExamAnswers, getWithCampusList, getWithPersonnelList, getWithExamQuestionsList } from '@/app/api/exam_answers'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/exam_answers/components/exam-answers-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let examAnswersTable = reactive({
page: 1,
@ -153,13 +91,9 @@ let examAnswersTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
campus_id: '',
user_id: '',
question_id: '',
answer: '',
is_correct: '',
},
searchParam:{
"campus_id":""
}
})
const searchFormRef = ref<FormInstance>()
@ -168,6 +102,11 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const is_correctList = ref([] as any[])
const is_correctDictList = async () => {
is_correctList.value = await (await useDictionary('is_correct')).data.dictionary
}
is_correctDictList();
/**
* 获取答题记录列表
@ -179,14 +118,12 @@ const loadExamAnswersList = (page: number = 1) => {
getExamAnswersList({
page: examAnswersTable.page,
limit: examAnswersTable.limit,
...examAnswersTable.searchParam,
})
.then((res) => {
...examAnswersTable.searchParam
}).then(res => {
examAnswersTable.loading = false
examAnswersTable.data = res.data.data
examAnswersTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
examAnswersTable.loading = false
})
}
@ -215,19 +152,37 @@ const editEvent = (data: any) => {
* 删除答题记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examAnswersDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('examAnswersDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteExamAnswers(id)
.then(() => {
}
).then(() => {
deleteExamAnswers(id).then(() => {
loadExamAnswersList()
}).catch(() => {
})
.catch(() => {})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const userIdList = ref([])
const setUserIdList = async () => {
userIdList.value = await (await getWithPersonnelList({})).data
}
setUserIdList()
const questionIdList = ref([])
const setQuestionIdList = async () => {
questionIdList.value = await (await getWithExamQuestionsList({})).data
}
setQuestionIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -244,5 +199,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

323
admin/src/app/views/exam_papers/components/exam-papers-edit.vue

@ -1,118 +1,194 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateExamPapers') : t('addExamPapers')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateExamPapers') : t('addExamPapers')" width="50%"
class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form-item label="试卷标题">
<el-input v-model="formData.title" class="input-width" />
</el-form-item>
<el-form-item :label="t('selectionMode')" prop="selection_mode">
<el-input
v-model="formData.selection_mode"
clearable
:placeholder="t('selectionModePlaceholder')"
class="input-width"
/>
<el-select class="input-width" v-model="formData.selection_mode" clearable
:placeholder="t('selectionModePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in selection_modeList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<!-- <el-form-item :label="t('questionsIds')" >
<el-input v-model="formData.questions_ids" clearable :placeholder="t('questionsIdsPlaceholder')" class="input-width" />
</el-form-item> -->
<el-form-item :label="t('questionsIds')" v-if="formData.selection_mode == 'manual'">
<div class="mt-[10px]">
<el-table ref="tableRef" :data="questionsList" style="width: 100%"
@selection-change="handleSelectionChange" :loading="loadinga">
<el-table-column type="selection" width="55" />
<el-table-column prop="title" label="题目标题" />
<el-table-column label="题型" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in question_typeList">
<div v-if="item.value == row.question_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="题干类型" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in question_content_typeList">
<div v-if="item.value == row.question_content_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="题干内容" width="100" align="left">
<template #default="{ row }">
<el-avatar v-if="row.question_content_type == 'image'"
:src="img(row.question_content)" />
<div v-if="row.question_content_type == 'text'">{{ row.question_content }}</div>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="fetchQuestions()" @current-change="fetchQuestions" />
</div>
</div>
</el-form-item>
<el-form-item :label="t('totalScore')" prop="total_score">
<el-input
v-model="formData.total_score"
clearable
:placeholder="t('totalScorePlaceholder')"
class="input-width"
/>
<el-input-number v-model="formData.total_score" clearable :placeholder="t('totalScorePlaceholder')"
class="input-width" :min="0" max="100" />
</el-form-item>
<el-form-item :label="t('passingScore')" prop="passing_score">
<el-input
v-model="formData.passing_score"
clearable
:placeholder="t('passingScorePlaceholder')"
class="input-width"
/>
<el-input-number v-model="formData.passing_score" clearable :placeholder="t('passingScorePlaceholder')"
class="input-width" :min="0" max="100" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addExamPapers,
editExamPapers,
getExamPapersInfo,
} from '@/app/api/exam_papers'
let showDialog = ref(false)
const loading = ref(false)
/**
import { ref, reactive, computed, watch ,nextTick } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addExamPapers, editExamPapers, getExamPapersInfo } from '@/app/api/exam_papers'
import { getExamQuestionsList } from '@/app/api/exam_questions'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
const initialFormData = {
id: '',
title: '',
selection_mode: '',
questions_ids: '',
total_score: '',
passing_score: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
}
//
const question_typeList = ref([] as any[])
const question_typeDictList = async () => {
question_typeList.value = await (await useDictionary('question_type')).data.dictionary
}
question_typeDictList();
const question_content_typeList = ref([] as any[])
const question_content_typeDictList = async () => {
question_content_typeList.value = await (await useDictionary('question_content_type')).data.dictionary
}
question_content_typeDictList();
const dialogVisible = ref(false)
//
const questionsList = ref([])
const loadinga = ref(false)
const total = ref(0)
const pageSize = 10
const currentPage = ref(1)
const selectedQuestions = ref([])
const tableRef = ref()
const fetchQuestions = async (page = 1) => {
loadinga.value = true
currentPage.value = page
getExamQuestionsList({
page: page,
limit: pageSize
}).then(res => {
questionsList.value = res.data.data
total.value = res.data.total
loadinga.value = false
//
const formRules = computed(() => {
}).catch(() => {
loadinga.value = false
})
}
fetchQuestions()
const handleSelectionChange = (val) => {
selectedQuestions.value = val
}
const formData : Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
selection_mode: [
{
required: true,
message: t('selectionModePlaceholder'),
trigger: 'blur',
},
],
total_score: [
{ required: true, message: t('totalScorePlaceholder'), trigger: 'blur' },
],
passing_score: [
{
required: true,
message: t('passingScorePlaceholder'),
trigger: 'blur',
},
],
}
})
const emit = defineEmits(['complete'])
/**
{ required: true, message: t('selectionModePlaceholder'), trigger: 'blur' },
]
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
const confirm = async (formEl : FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editExamPapers : addExamPapers
@ -120,86 +196,103 @@ const confirm = async (formEl: FormInstance | undefined) => {
if (valid) {
loading.value = true
if (formData.selection_mode == 'manual') {
const ids = selectedQuestions.value.map(item => item.id).join(',')
formData.questions_ids = ids
}
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
})
}
}
//
let selection_modeList = ref([])
const selection_modeDictList = async () => {
selection_modeList.value = await (await useDictionary('selection_mode')).data.dictionary
}
selection_modeDictList();
watch(() => selection_modeList.value, () => { formData.selection_mode = selection_modeList.value[0].value })
//
const setFormData = async (row: any = null) => {
const setFormData = async (row : any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getExamPapersInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key : string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
nextTick(() => {
const ids = formData.questions_ids?.split(',') || []
console.log(ids);
questionsList.value.forEach(row => {
if (ids.includes(String(row.id))) {
tableRef.value.toggleRowSelection(row)
}
})
})
loading.value = false
}
}
//
const mobileVerify = (rule: any, value: any, callback: any) => {
//
const mobileVerify = (rule : any, value : any, callback : any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
}
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
//
const idCardVerify = (rule : any, value : any, callback : any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
}
//
const emailVerify = (rule: any, value: any, callback: any) => {
//
const emailVerify = (rule : any, value : any, callback : any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
//
const numberVerify = (rule : any, value : any, callback : any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
}
defineExpose({
defineExpose({
showDialog,
setFormData,
})
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
}
</style>

155
admin/src/app/views/exam_papers/exam_papers.vue

@ -1,106 +1,76 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addExamPapers') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="examPapersTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="examPapersTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('selectionMode')" prop="selection_mode">
<el-input
v-model="examPapersTable.searchParam.selection_mode"
:placeholder="t('selectionModePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('totalScore')" prop="total_score">
<el-input
v-model="examPapersTable.searchParam.total_score"
:placeholder="t('totalScorePlaceholder')"
<el-select class="w-[280px]" v-model="examPapersTable.searchParam.selection_mode" clearable :placeholder="t('selectionModePlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in selection_modeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('passingScore')" prop="passing_score">
<el-input
v-model="examPapersTable.searchParam.passing_score"
:placeholder="t('passingScorePlaceholder')"
/>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-date-picker v-model="examPapersTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadExamPapersList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadExamPapersList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="examPapersTable.data"
size="large"
v-loading="examPapersTable.loading"
>
<el-table :data="examPapersTable.data" size="large" v-loading="examPapersTable.loading">
<template #empty>
<span>{{ !examPapersTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="selection_mode"
:label="t('selectionMode')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="total_score"
:label="t('totalScore')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="title" label="试卷标题" />
<el-table-column
prop="passing_score"
:label="t('passingScore')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('selectionMode')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in selection_modeList">
<div v-if="item.value == row.selection_mode">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="total_score" :label="t('totalScore')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="passing_score" :label="t('passingScore')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="examPapersTable.page"
v-model:page-size="examPapersTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="examPapersTable.total"
@size-change="loadExamPapersList()"
@current-change="loadExamPapersList"
/>
<el-pagination v-model:current-page="examPapersTable.page" v-model:page-size="examPapersTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="examPapersTable.total"
@size-change="loadExamPapersList()" @current-change="loadExamPapersList" />
</div>
</div>
@ -115,11 +85,11 @@ import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getExamPapersList, deleteExamPapers } from '@/app/api/exam_papers'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/exam_papers/components/exam-papers-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let examPapersTable = reactive({
page: 1,
@ -127,11 +97,10 @@ let examPapersTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
selection_mode: '',
total_score: '',
passing_score: '',
},
searchParam:{
"selection_mode":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
@ -140,6 +109,11 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const selection_modeList = ref([] as any[])
const selection_modeDictList = async () => {
selection_modeList.value = await (await useDictionary('selection_mode')).data.dictionary
}
selection_modeDictList();
/**
* 获取试卷列表
@ -151,14 +125,12 @@ const loadExamPapersList = (page: number = 1) => {
getExamPapersList({
page: examPapersTable.page,
limit: examPapersTable.limit,
...examPapersTable.searchParam,
})
.then((res) => {
...examPapersTable.searchParam
}).then(res => {
examPapersTable.loading = false
examPapersTable.data = res.data.data
examPapersTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
examPapersTable.loading = false
})
}
@ -187,19 +159,22 @@ const editEvent = (data: any) => {
* 删除试卷
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examPapersDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('examPapersDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteExamPapers(id)
.then(() => {
}
).then(() => {
deleteExamPapers(id).then(() => {
loadExamPapersList()
}).catch(() => {
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -216,5 +191,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

287
admin/src/app/views/exam_questions/components/exam-questions-edit.vue

@ -0,0 +1,287 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateExamQuestions') : t('addExamQuestions')" width="50%"
class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form-item :label="t('title')" prop="title">
<el-input v-model="formData.title" clearable :placeholder="t('titlePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('questionType')" prop="question_type">
<el-select class="input-width" v-model="formData.question_type" clearable
:placeholder="t('questionTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in question_typeList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('questionContentType')" prop="question_content_type">
<el-select class="input-width" v-model="formData.question_content_type" clearable
:placeholder="t('questionContentTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in question_content_typeList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('questionContent')" v-if="formData.question_content_type == 'text'">
<el-input v-model="formData.question_content" clearable class="input-width" />
</el-form-item>
<el-form-item :label="t('questionContent')" v-if="formData.question_content_type == 'image'">
<upload-image v-model="formData.question_content" />
</el-form-item>
<!-- <el-form-item :label="t('optionJson')" prop="option_json">
<el-input v-model="formData.option_json" clearable :placeholder="t('optionJsonPlaceholder')" class="input-width" />
</el-form-item> -->
<el-form-item :label="t('optionJson')">
<div v-for="(option, index) in formData.option_json" :key="index" class="option-item">
<el-card class="box-card" shadow="never">
<el-form-item label="类型" label-width="60">
<el-select v-model="option.option_content_type" placeholder="请选择类型">
<el-option label="文本" value="text" />
<el-option label="图片" value="image" />
</el-select>
</el-form-item>
<el-form-item label="内容" label-width="60" style="margin-top:5px;">
<template v-if="option.option_content_type === 'text'">
<el-input v-model="option.option_content" placeholder="请输入选项文本" />
</template>
<template v-else>
<upload-file v-model="option.option_content" />
</template>
</el-form-item>
<el-form-item label="答案" label-width="60">
<el-switch v-model="option.correct_answer"
:disabled="formData.question_type === 'single_choice' && option.correct_answer"
@change="handleCorrectAnswerChange(index)" />
</el-form-item>
<el-form-item label="操作" label-width="60">
<el-button @click="removeOption(index)" type="danger" size="small" plain>删除</el-button>
</el-form-item>
</el-card>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addOption">添加选项</el-button>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addExamQuestions, editExamQuestions, getExamQuestionsInfo } from '@/app/api/exam_questions'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
title: '',
question_type: '',
question_content_type: '',
question_content: '',
option_json: []
}
const addOption = () => {
formData.option_json.push({
option_content_type: 'text',
option_content: '',
correct_answer: false
})
}
const removeOption = (index) => {
formData.option_json.splice(index, 1)
}
const handleCorrectAnswerChange = (changedIndex) => {
if (formData.question_type === 'single_choice') {
formData.options.forEach((opt, i) => {
if (i !== changedIndex) opt.correct_answer = false
})
}
}
const formData : Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
title: [
{ required: true, message: t('titlePlaceholder'), trigger: 'blur' },
]
,
question_type: [
{ required: true, message: t('questionTypePlaceholder'), trigger: 'blur' },
]
,
question_content_type: [
{ required: true, message: t('questionContentTypePlaceholder'), trigger: 'blur' },
]
,
question_content: [
{ required: true, message: t('questionContentPlaceholder'), trigger: 'blur' },
]
,
option_json: [
{ required: true, message: t('optionJsonPlaceholder'), trigger: 'blur' },
]
,
correct_answer: [
{ required: true, message: t('correctAnswerPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl : FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editExamQuestions : addExamQuestions
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(err => {
loading.value = false
})
}
})
}
//
let question_typeList = ref([])
const question_typeDictList = async () => {
question_typeList.value = await (await useDictionary('question_type')).data.dictionary
}
question_typeDictList();
watch(() => question_typeList.value, () => { formData.question_type = question_typeList.value[0].value })
let question_content_typeList = ref([])
const question_content_typeDictList = async () => {
question_content_typeList.value = await (await useDictionary('question_content_type')).data.dictionary
}
question_content_typeDictList();
watch(() => question_content_typeList.value, () => { formData.question_content_type = question_content_typeList.value[0].value })
const setFormData = async (row : any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getExamQuestionsInfo(row.id)).data
if (data) Object.keys(formData).forEach((key : string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
loading.value = false
}
//
const mobileVerify = (rule : any, value : any, callback : any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
//
const idCardVerify = (rule : any, value : any, callback : any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
//
const emailVerify = (rule : any, value : any, callback : any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
//
const numberVerify = (rule : any, value : any, callback : any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
.option-item {
margin-bottom: 20px;
margin-right: 10px;
}
</style>

328
admin/src/app/views/exam_questions/exam_questions.vue

@ -1,240 +1,95 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addExamQuestions') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="examQuestionsTable.searchParam"
ref="searchFormRef"
>
<el-form-item :label="t('questionType')" prop="question_type">
<el-input
v-model="examQuestionsTable.searchParam.question_type"
:placeholder="t('questionTypePlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('questionContentType')"
prop="question_content_type"
>
<el-input
v-model="examQuestionsTable.searchParam.question_content_type"
:placeholder="t('questionContentTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('questionContent')" prop="question_content">
<el-input
v-model="examQuestionsTable.searchParam.question_content"
:placeholder="t('questionContentPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('optionAContentType')"
prop="option_a_content_type"
>
<el-input
v-model="examQuestionsTable.searchParam.option_a_content_type"
:placeholder="t('optionAContentTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('optionAContent')" prop="option_a_content">
<el-input
v-model="examQuestionsTable.searchParam.option_a_content"
:placeholder="t('optionAContentPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('optionBContentType')"
prop="option_b_content_type"
>
<el-input
v-model="examQuestionsTable.searchParam.option_b_content_type"
:placeholder="t('optionBContentTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('optionBContent')" prop="option_b_content">
<el-input
v-model="examQuestionsTable.searchParam.option_b_content"
:placeholder="t('optionBContentPlaceholder')"
/>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="examQuestionsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('title')" prop="title">
<el-input v-model="examQuestionsTable.searchParam.title" :placeholder="t('titlePlaceholder')" />
</el-form-item>
<el-form-item
:label="t('optionCContentType')"
prop="option_c_content_type"
>
<el-input
v-model="examQuestionsTable.searchParam.option_c_content_type"
:placeholder="t('optionCContentTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('optionCContent')" prop="option_c_content">
<el-input
v-model="examQuestionsTable.searchParam.option_c_content"
:placeholder="t('optionCContentPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('optionDContentType')"
prop="option_d_content_type"
>
<el-input
v-model="examQuestionsTable.searchParam.option_d_content_type"
:placeholder="t('optionDContentTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('optionDContent')" prop="option_d_content">
<el-input
v-model="examQuestionsTable.searchParam.option_d_content"
:placeholder="t('optionDContentPlaceholder')"
/>
<el-form-item :label="t('questionType')" prop="question_type">
<el-select class="w-[280px]" v-model="examQuestionsTable.searchParam.question_type" clearable :placeholder="t('questionTypePlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in question_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('correctAnswer')" prop="correct_answer">
<el-input
v-model="examQuestionsTable.searchParam.correct_answer"
:placeholder="t('correctAnswerPlaceholder')"
/>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-date-picker v-model="examQuestionsTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadExamQuestionsList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadExamQuestionsList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="examQuestionsTable.data"
size="large"
v-loading="examQuestionsTable.loading"
>
<el-table :data="examQuestionsTable.data" size="large" v-loading="examQuestionsTable.loading">
<template #empty>
<span>{{ !examQuestionsTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="question_type"
:label="t('questionType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="question_content_type"
:label="t('questionContentType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="question_content"
:label="t('questionContent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="title" :label="t('title')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="option_a_content_type"
:label="t('optionAContentType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="option_a_content"
:label="t('optionAContent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="option_b_content_type"
:label="t('optionBContentType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="option_b_content"
:label="t('optionBContent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('questionType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in question_typeList">
<div v-if="item.value == row.question_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="option_c_content_type"
:label="t('optionCContentType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('questionContentType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in question_content_typeList">
<div v-if="item.value == row.question_content_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="option_c_content"
:label="t('optionCContent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('questionContent')" width="100" align="left">
<template #default="{ row }">
<el-avatar v-if="row.question_content_type == 'image'" :src="img(row.question_content)" />
<div v-if="row.question_content_type == 'text'">{{ row.question_content }}</div>
</template>
</el-table-column>
<el-table-column
prop="option_d_content_type"
:label="t('optionDContentType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="option_d_content"
:label="t('optionDContent')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="correct_answer"
:label="t('correctAnswer')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="examQuestionsTable.page"
v-model:page-size="examQuestionsTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="examQuestionsTable.total"
@size-change="loadExamQuestionsList()"
@current-change="loadExamQuestionsList"
/>
<el-pagination v-model:current-page="examQuestionsTable.page" v-model:page-size="examQuestionsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="examQuestionsTable.total"
@size-change="loadExamQuestionsList()" @current-change="loadExamQuestionsList" />
</div>
</div>
<edit ref="editExamQuestionsDialog" @complete="loadExamQuestionsList" />
</el-card>
</div>
</template>
@ -243,16 +98,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import {
getExamQuestionsList,
deleteExamQuestions,
} from '@/app/api/exam_questions'
import { getExamQuestionsList, deleteExamQuestions } from '@/app/api/exam_questions'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRouter } from 'vue-router'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/exam_questions/components/exam-questions-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let examQuestionsTable = reactive({
page: 1,
@ -260,20 +112,11 @@ let examQuestionsTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
question_type: '',
question_content_type: '',
question_content: '',
option_a_content_type: '',
option_a_content: '',
option_b_content_type: '',
option_b_content: '',
option_c_content_type: '',
option_c_content: '',
option_d_content_type: '',
option_d_content: '',
correct_answer: '',
},
searchParam:{
"title":"",
"question_type":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
@ -282,6 +125,16 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const question_typeList = ref([] as any[])
const question_typeDictList = async () => {
question_typeList.value = await (await useDictionary('question_type')).data.dictionary
}
question_typeDictList();
const question_content_typeList = ref([] as any[])
const question_content_typeDictList = async () => {
question_content_typeList.value = await (await useDictionary('question_content_type')).data.dictionary
}
question_content_typeDictList();
/**
* 获取试题列表
@ -293,26 +146,25 @@ const loadExamQuestionsList = (page: number = 1) => {
getExamQuestionsList({
page: examQuestionsTable.page,
limit: examQuestionsTable.limit,
...examQuestionsTable.searchParam,
})
.then((res) => {
...examQuestionsTable.searchParam
}).then(res => {
examQuestionsTable.loading = false
examQuestionsTable.data = res.data.data
examQuestionsTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
examQuestionsTable.loading = false
})
}
loadExamQuestionsList()
const router = useRouter()
const editExamQuestionsDialog: Record<string, any> | null = ref(null)
/**
* 添加试题
*/
const addEvent = () => {
router.push('/exam_questions/exam_questions_edit')
editExamQuestionsDialog.value.setFormData()
editExamQuestionsDialog.value.showDialog = true
}
/**
@ -320,26 +172,30 @@ const addEvent = () => {
* @param data
*/
const editEvent = (data: any) => {
router.push('/exam_questions/exam_questions_edit?id=' + data.id)
editExamQuestionsDialog.value.setFormData(data)
editExamQuestionsDialog.value.showDialog = true
}
/**
* 删除试题
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examQuestionsDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('examQuestionsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteExamQuestions(id)
.then(() => {
}
).then(() => {
deleteExamQuestions(id).then(() => {
loadExamQuestionsList()
}).catch(() => {
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -356,5 +212,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

192
admin/src/app/views/exam_records/components/exam-records-edit.vue

@ -1,92 +1,86 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateExamRecords') : t('addExamRecords')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateExamRecords') : t('addExamRecords')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="formData.campus_id"
clearable
:placeholder="t('campusIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-input
v-model="formData.user_id"
clearable
:placeholder="t('userIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in userIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('paperId')" prop="paper_id">
<el-input
v-model="formData.paper_id"
clearable
:placeholder="t('paperIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.paper_id" clearable :placeholder="t('paperIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in paperIdList"
:key="index"
:label="item['title']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('score')">
<el-input
v-model="formData.score"
clearable
:placeholder="t('scorePlaceholder')"
class="input-width"
/>
<el-form-item :label="t('score')" >
<el-input-number v-model="formData.score" clearable :placeholder="t('scorePlaceholder')" class="input-width" :min = "0" max = "100" />
</el-form-item>
<el-form-item :label="t('status')">
<el-input
v-model="formData.status"
clearable
:placeholder="t('statusPlaceholder')"
class="input-width"
<el-form-item :label="t('status')" >
<el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('startTime')">
<el-input
<el-form-item :label="t('startTime')" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.start_time"
clearable
:placeholder="t('startTimePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('startTimePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('endTime')">
<el-input
<el-form-item :label="t('endTime')" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.end_time"
clearable
:placeholder="t('endTimePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('endTimePlaceholder')">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -97,11 +91,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addExamRecords,
editExamRecords,
getExamRecordsInfo,
} from '@/app/api/exam_records'
import { addExamRecords, editExamRecords, getExamRecordsInfo, getWithCampusList, getWithPersonnelList, getWithExamPapersList } from '@/app/api/exam_records'
let showDialog = ref(false)
const loading = ref(false)
@ -128,25 +118,39 @@ const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
],
]
,
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
],
]
,
paper_id: [
{ required: true, message: t('paperIdPlaceholder'), trigger: 'blur' },
],
]
,
score: [
{ required: true, message: t('scorePlaceholder'), trigger: 'blur' },
],
{ validator: (rule: any, value: string, callback: any) => { if (value && !/^\d{0,100}$/.test(value)) { callback(new Error(t('generateBetween')))} else { callback() }}},
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
],
]
,
start_time: [
{ required: true, message: t('startTimePlaceholder'), trigger: 'blur' },
],
]
,
end_time: [
{ required: true, message: t('endTimePlaceholder'), trigger: 'blur' },
],
]
,
}
})
@ -166,13 +170,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -180,14 +182,35 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('ks_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const userIdList = ref([] as any[])
const setUserIdList = async () => {
userIdList.value = await (await getWithPersonnelList({})).data
}
setUserIdList()
const paperIdList = ref([] as any[])
const setPaperIdList = async () => {
paperIdList.value = await (await getWithExamPapersList({})).data
}
setPaperIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
if(row){
const data = await (await getExamRecordsInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
@ -205,12 +228,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -237,13 +255,13 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

232
admin/src/app/views/exam_records/exam_records.vue

@ -1,158 +1,97 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addExamRecords') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="examRecordsTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="examRecordsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input
v-model="examRecordsTable.searchParam.campus_id"
:placeholder="t('campusIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-input
v-model="examRecordsTable.searchParam.user_id"
:placeholder="t('userIdPlaceholder')"
<el-select class="w-[280px]" v-model="examRecordsTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('paperId')" prop="paper_id">
<el-input
v-model="examRecordsTable.searchParam.paper_id"
:placeholder="t('paperIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('score')" prop="score">
<el-input
v-model="examRecordsTable.searchParam.score"
:placeholder="t('scorePlaceholder')"
<el-select class="w-[280px]" v-model="examRecordsTable.searchParam.paper_id" clearable :placeholder="t('paperIdPlaceholder')">
<el-option
v-for="(item, index) in paperIdList"
:key="index"
:label="item['title']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input
v-model="examRecordsTable.searchParam.status"
:placeholder="t('statusPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('startTime')" prop="start_time">
<el-input
v-model="examRecordsTable.searchParam.start_time"
:placeholder="t('startTimePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('endTime')" prop="end_time">
<el-input
v-model="examRecordsTable.searchParam.end_time"
:placeholder="t('endTimePlaceholder')"
<el-select class="w-[280px]" v-model="examRecordsTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadExamRecordsList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadExamRecordsList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="examRecordsTable.data"
size="large"
v-loading="examRecordsTable.loading"
>
<el-table :data="examRecordsTable.data" size="large" v-loading="examRecordsTable.loading">
<template #empty>
<span>{{ !examRecordsTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="campus_id"
:label="t('campusId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="user_id"
:label="t('userId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="paper_id"
:label="t('paperId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="paper_id_name" :label="t('paperId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="score"
:label="t('score')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="score" :label="t('score')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="status"
:label="t('status')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="start_time"
:label="t('startTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="start_time" :label="t('startTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="end_time"
:label="t('endTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="end_time" :label="t('endTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="examRecordsTable.page"
v-model:page-size="examRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="examRecordsTable.total"
@size-change="loadExamRecordsList()"
@current-change="loadExamRecordsList"
/>
<el-pagination v-model:current-page="examRecordsTable.page" v-model:page-size="examRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="examRecordsTable.total"
@size-change="loadExamRecordsList()" @current-change="loadExamRecordsList" />
</div>
</div>
@ -165,13 +104,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getExamRecordsList, deleteExamRecords } from '@/app/api/exam_records'
import { getExamRecordsList, deleteExamRecords, getWithCampusList, getWithPersonnelList, getWithExamPapersList } from '@/app/api/exam_records'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/exam_records/components/exam-records-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let examRecordsTable = reactive({
page: 1,
@ -179,15 +118,11 @@ let examRecordsTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
campus_id: '',
user_id: '',
paper_id: '',
score: '',
status: '',
start_time: '',
end_time: '',
},
searchParam:{
"campus_id":"",
"paper_id":"",
"status":""
}
})
const searchFormRef = ref<FormInstance>()
@ -196,6 +131,11 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('ks_status')).data.dictionary
}
statusDictList();
/**
* 获取考试记录列表
@ -207,14 +147,12 @@ const loadExamRecordsList = (page: number = 1) => {
getExamRecordsList({
page: examRecordsTable.page,
limit: examRecordsTable.limit,
...examRecordsTable.searchParam,
})
.then((res) => {
...examRecordsTable.searchParam
}).then(res => {
examRecordsTable.loading = false
examRecordsTable.data = res.data.data
examRecordsTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
examRecordsTable.loading = false
})
}
@ -243,19 +181,37 @@ const editEvent = (data: any) => {
* 删除考试记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examRecordsDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('examRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteExamRecords(id)
.then(() => {
}
).then(() => {
deleteExamRecords(id).then(() => {
loadExamRecordsList()
}).catch(() => {
})
.catch(() => {})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const userIdList = ref([])
const setUserIdList = async () => {
userIdList.value = await (await getWithPersonnelList({})).data
}
setUserIdList()
const paperIdList = ref([])
const setPaperIdList = async () => {
paperIdList.value = await (await getWithExamPapersList({})).data
}
setPaperIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -272,5 +228,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

204
admin/src/app/views/performance_records/components/performance-records-edit.vue

@ -1,94 +1,70 @@
<template>
<el-dialog
v-model="showDialog"
:title="
formData.id ? t('updatePerformanceRecords') : t('addPerformanceRecords')
"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updatePerformanceRecords') : t('addPerformanceRecords')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="formData.staff_id"
clearable
:placeholder="t('staffIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in staffIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="formData.resource_id"
clearable
:placeholder="t('resourceIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in resourceIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('orderId')">
<el-input
v-model="formData.order_id"
clearable
:placeholder="t('orderIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('orderStatus')">
<el-input
v-model="formData.order_status"
clearable
:placeholder="t('orderStatusPlaceholder')"
class="input-width"
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-select class="input-width" v-model="formData.order_status" clearable :placeholder="t('orderStatusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in order_statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('performanceType')" prop="performance_type">
<el-input
v-model="formData.performance_type"
clearable
:placeholder="t('performanceTypePlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.performance_type" clearable :placeholder="t('performanceTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in performance_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('performanceValue')" prop="performance_value">
<el-input
v-model="formData.performance_value"
clearable
:placeholder="t('performanceValuePlaceholder')"
class="input-width"
/>
<el-input v-model="formData.performance_value" clearable :placeholder="t('performanceValuePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('remarks')">
<el-input
v-model="formData.remarks"
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
/>
<el-form-item :label="t('remarks')" >
<el-input v-model="formData.remarks" clearable :placeholder="t('remarksPlaceholder')" class="input-width" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -99,11 +75,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addPerformanceRecords,
editPerformanceRecords,
getPerformanceRecordsInfo,
} from '@/app/api/performance_records'
import { addPerformanceRecords, editPerformanceRecords, getPerformanceRecordsInfo, getWithPersonnelList, getWithCustomerResourcesList, getWithOrderTableList } from '@/app/api/performance_records'
let showDialog = ref(false)
const loading = ref(false)
@ -115,7 +87,6 @@ const initialFormData = {
id: '',
staff_id: '',
resource_id: '',
order_id: '',
order_status: '',
performance_type: '',
performance_value: '',
@ -130,33 +101,34 @@ const formRules = computed(() => {
return {
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
],
]
,
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
],
order_id: [
{ required: true, message: t('orderIdPlaceholder'), trigger: 'blur' },
],
]
,
order_status: [
{ required: true, message: t('orderStatusPlaceholder'), trigger: 'blur' },
],
]
,
performance_type: [
{
required: true,
message: t('performanceTypePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('performanceTypePlaceholder'), trigger: 'blur' },
]
,
performance_value: [
{
required: true,
message: t('performanceValuePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('performanceValuePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
]
,
}
})
@ -176,13 +148,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -190,14 +160,41 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let order_statusList = ref([])
const order_statusDictList = async () => {
order_statusList.value = await (await useDictionary('orderstatus')).data.dictionary
}
order_statusDictList();
watch(() => order_statusList.value, () => { formData.order_status = order_statusList.value[0].value })
let performance_typeList = ref([])
const performance_typeDictList = async () => {
performance_typeList.value = await (await useDictionary('performance_type')).data.dictionary
}
performance_typeDictList();
watch(() => performance_typeList.value, () => { formData.performance_type = performance_typeList.value[0].value })
const staffIdList = ref([] as any[])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const orderIdList = ref([] as any[])
const setOrderIdList = async () => {
orderIdList.value = await (await getWithOrderTableList({})).data
}
setOrderIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
if(row){
const data = await (await getPerformanceRecordsInfo(row.id)).data
if (data)
Object.keys(formData).forEach((key: string) => {
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
@ -215,12 +212,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -247,13 +239,13 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

262
admin/src/app/views/performance_records/performance_records.vue

@ -1,167 +1,100 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">
<span class="text-lg">{{pageName}}</span>
<!-- <el-button type="primary" @click="addEvent">
{{ t('addPerformanceRecords') }}
</el-button>
</el-button> -->
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="performanceRecordsTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="performanceRecordsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="performanceRecordsTable.searchParam.staff_id"
:placeholder="t('staffIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="performanceRecordsTable.searchParam.resource_id"
:placeholder="t('resourceIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('orderId')" prop="order_id">
<el-input
v-model="performanceRecordsTable.searchParam.order_id"
:placeholder="t('orderIdPlaceholder')"
/>
<el-select class="w-[280px]" v-model="performanceRecordsTable.searchParam.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
<el-option
v-for="(item, index) in staffIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-input
v-model="performanceRecordsTable.searchParam.order_status"
:placeholder="t('orderStatusPlaceholder')"
/>
<el-select class="w-[280px]" v-model="performanceRecordsTable.searchParam.order_status" clearable :placeholder="t('orderStatusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in order_statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('performanceType')" prop="performance_type">
<el-input
v-model="performanceRecordsTable.searchParam.performance_type"
:placeholder="t('performanceTypePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('performanceValue')" prop="performance_value">
<el-input
v-model="performanceRecordsTable.searchParam.performance_value"
:placeholder="t('performanceValuePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input
v-model="performanceRecordsTable.searchParam.remarks"
:placeholder="t('remarksPlaceholder')"
/>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-date-picker v-model="performanceRecordsTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadPerformanceRecordsList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadPerformanceRecordsList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="performanceRecordsTable.data"
size="large"
v-loading="performanceRecordsTable.loading"
>
<el-table :data="performanceRecordsTable.data" size="large" v-loading="performanceRecordsTable.loading">
<template #empty>
<span>{{
!performanceRecordsTable.loading ? t('emptyData') : ''
}}</span>
<span>{{ !performanceRecordsTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="staff_id_name" :label="t('staffId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="resource_id"
:label="t('resourceId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="resource_id_name" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="order_id"
:label="t('orderId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('orderStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in order_statusList">
<div v-if="item.value == row.order_status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="order_status"
:label="t('orderStatus')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('performanceType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in performance_typeList">
<div v-if="item.value == row.performance_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="performance_type"
:label="t('performanceType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="performance_value" :label="t('performanceValue')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="performance_value"
:label="t('performanceValue')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="remarks" :label="t('remarks')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<!-- <el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table-column> -->
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="performanceRecordsTable.page"
v-model:page-size="performanceRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="performanceRecordsTable.total"
@size-change="loadPerformanceRecordsList()"
@current-change="loadPerformanceRecordsList"
/>
<el-pagination v-model:current-page="performanceRecordsTable.page" v-model:page-size="performanceRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="performanceRecordsTable.total"
@size-change="loadPerformanceRecordsList()" @current-change="loadPerformanceRecordsList" />
</div>
</div>
<edit
ref="editPerformanceRecordsDialog"
@complete="loadPerformanceRecordsList"
/>
<edit ref="editPerformanceRecordsDialog" @complete="loadPerformanceRecordsList" />
</el-card>
</div>
</template>
@ -170,16 +103,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import {
getPerformanceRecordsList,
deletePerformanceRecords,
} from '@/app/api/performance_records'
import { getPerformanceRecordsList, deletePerformanceRecords, getWithPersonnelList, getWithCustomerResourcesList, getWithOrderTableList } from '@/app/api/performance_records'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/performance_records/components/performance-records-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let performanceRecordsTable = reactive({
page: 1,
@ -187,15 +117,11 @@ let performanceRecordsTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
staff_id: '',
resource_id: '',
order_id: '',
order_status: '',
performance_type: '',
performance_value: '',
remarks: '',
},
searchParam:{
"staff_id":"",
"order_status":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
@ -204,6 +130,16 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const order_statusList = ref([] as any[])
const order_statusDictList = async () => {
order_statusList.value = await (await useDictionary('orderstatus')).data.dictionary
}
order_statusDictList();
const performance_typeList = ref([] as any[])
const performance_typeDictList = async () => {
performance_typeList.value = await (await useDictionary('performance_type')).data.dictionary
}
performance_typeDictList();
/**
* 获取绩效记录列表
@ -215,14 +151,12 @@ const loadPerformanceRecordsList = (page: number = 1) => {
getPerformanceRecordsList({
page: performanceRecordsTable.page,
limit: performanceRecordsTable.limit,
...performanceRecordsTable.searchParam,
})
.then((res) => {
...performanceRecordsTable.searchParam
}).then(res => {
performanceRecordsTable.loading = false
performanceRecordsTable.data = res.data.data
performanceRecordsTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
performanceRecordsTable.loading = false
})
}
@ -251,19 +185,37 @@ const editEvent = (data: any) => {
* 删除绩效记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('performanceRecordsDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('performanceRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deletePerformanceRecords(id)
.then(() => {
}
).then(() => {
deletePerformanceRecords(id).then(() => {
loadPerformanceRecordsList()
}).catch(() => {
})
.catch(() => {})
})
}
const staffIdList = ref([])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resourceIdList = ref([])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const orderIdList = ref([])
const setOrderIdList = async () => {
orderIdList.value = await (await getWithOrderTableList({})).data
}
setOrderIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
@ -280,5 +232,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
</style>

315
admin/src/app/views/student/components/student-edit.vue

@ -0,0 +1,315 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateStudent') : t('addStudent')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('campusId')" >
<el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id">
<el-select class="input-width" v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in classIdList"
:key="index"
:label="item['class_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-select class="input-width" v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in userIdList"
:key="index"
:label="item['nickname']"
:value="item['member_id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('name')" prop="name">
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('gender')" prop="gender">
<el-select class="input-width" v-model="formData.gender" clearable :placeholder="t('genderPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in genderList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('age')" >
<el-input v-model="formData.age" clearable :placeholder="t('agePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('birthday')" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.birthday"
clearable
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('birthdayPlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('emergencyContact')" >
<el-input v-model="formData.emergency_contact" clearable :placeholder="t('emergencyContactPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('contactPhone')" >
<el-input v-model="formData.contact_phone" clearable :placeholder="t('contactPhonePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('note')" >
<el-input v-model="formData.note" clearable :placeholder="t('notePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addStudent, editStudent, getStudentInfo, getWithCampusList, getWithClassGradeList, getWithMemberList } from '@/app/api/student'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
class_id: '',
user_id: '',
name: '',
gender: '',
age: '',
birthday: '',
emergency_contact: '',
contact_phone: '',
note: '',
status: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
]
,
class_id: [
{ required: true, message: t('classIdPlaceholder'), trigger: 'blur' },
]
,
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
]
,
name: [
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
]
,
gender: [
{ required: true, message: t('genderPlaceholder'), trigger: 'blur' },
]
,
age: [
{ required: true, message: t('agePlaceholder'), trigger: 'blur' },
]
,
birthday: [
{ required: true, message: t('birthdayPlaceholder'), trigger: 'blur' },
]
,
emergency_contact: [
{ required: true, message: t('emergencyContactPlaceholder'), trigger: 'blur' },
]
,
contact_phone: [
{ required: true, message: t('contactPhonePlaceholder'), trigger: 'blur' },
]
,
note: [
{ required: true, message: t('notePlaceholder'), trigger: 'blur' },
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editStudent : addStudent
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(err => {
loading.value = false
})
}
})
}
//
let genderList = ref([])
const genderDictList = async () => {
genderList.value = await (await useDictionary('gender')).data.dictionary
}
genderDictList();
watch(() => genderList.value, () => { formData.gender = genderList.value[0].value })
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('xy_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const classIdList = ref([] as any[])
const setClassIdList = async () => {
classIdList.value = await (await getWithClassGradeList({})).data
}
setClassIdList()
const userIdList = ref([] as any[])
const setUserIdList = async () => {
userIdList.value = await (await getWithMemberList({})).data
}
setUserIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getStudentInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
loading.value = false
}
//
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
//
const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

240
admin/src/app/views/student/student.vue

@ -0,0 +1,240 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addStudent') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="studentTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-select class="w-[280px]" v-model="studentTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('name')" prop="name">
<el-input v-model="studentTable.searchParam.name" :placeholder="t('namePlaceholder')" />
</el-form-item>
<el-form-item :label="t('emergencyContact')" prop="emergency_contact">
<el-input v-model="studentTable.searchParam.emergency_contact" :placeholder="t('emergencyContactPlaceholder')" />
</el-form-item>
<el-form-item :label="t('contactPhone')" prop="contact_phone">
<el-input v-model="studentTable.searchParam.contact_phone" :placeholder="t('contactPhonePlaceholder')" />
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-date-picker v-model="studentTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadStudentList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="studentTable.data" size="large" v-loading="studentTable.loading">
<template #empty>
<span>{{ !studentTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_id_name" :label="t('classId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="name" :label="t('name')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('gender')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in genderList">
<div v-if="item.value == row.gender">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="age" :label="t('age')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="emergency_contact" :label="t('emergencyContact')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="contact_phone" :label="t('contactPhone')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="note" :label="t('note')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="studentTable.page" v-model:page-size="studentTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="studentTable.total"
@size-change="loadStudentList()" @current-change="loadStudentList" />
</div>
</div>
<edit ref="editStudentDialog" @complete="loadStudentList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getStudentList, deleteStudent, getWithCampusList, getWithClassGradeList, getWithMemberList } from '@/app/api/student'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/student/components/student-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let studentTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"name":"",
"emergency_contact":"",
"contact_phone":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const genderList = ref([] as any[])
const genderDictList = async () => {
genderList.value = await (await useDictionary('gender')).data.dictionary
}
genderDictList();
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('xy_status')).data.dictionary
}
statusDictList();
/**
* 获取学员列表
*/
const loadStudentList = (page: number = 1) => {
studentTable.loading = true
studentTable.page = page
getStudentList({
page: studentTable.page,
limit: studentTable.limit,
...studentTable.searchParam
}).then(res => {
studentTable.loading = false
studentTable.data = res.data.data
studentTable.total = res.data.total
}).catch(() => {
studentTable.loading = false
})
}
loadStudentList()
const editStudentDialog: Record<string, any> | null = ref(null)
/**
* 添加学员
*/
const addEvent = () => {
editStudentDialog.value.setFormData()
editStudentDialog.value.showDialog = true
}
/**
* 编辑学员
* @param data
*/
const editEvent = (data: any) => {
editStudentDialog.value.setFormData(data)
editStudentDialog.value.showDialog = true
}
/**
* 删除学员
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('studentDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteStudent(id).then(() => {
loadStudentList()
}).catch(() => {
})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const classIdList = ref([])
const setClassIdList = async () => {
classIdList.value = await (await getWithClassGradeList({})).data
}
setClassIdList()
const userIdList = ref([])
const setUserIdList = async () => {
userIdList.value = await (await getWithMemberList({})).data
}
setUserIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadStudentList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

32
niucloud/app/adminapi/controller/attendance/Attendance.php

@ -31,13 +31,7 @@ class Attendance extends BaseAdminController
["campus_id",""],
["staff_id",""],
["attendance_date",""],
["check_in_time",""],
["check_out_time",""],
["status",""],
["remarks",""],
["created_at",""],
["updated_at",""],
["coordinate",""]
["status",""]
]);
return success((new AttendanceService())->getPage($data));
}
@ -59,14 +53,12 @@ class Attendance extends BaseAdminController
$data = $this->request->params([
["campus_id",0],
["staff_id",0],
["attendance_date","2025-05-16 17:06:01"],
["attendance_date","2025-05-23 12:44:09"],
["check_in_time",""],
["check_out_time",""],
["status",""],
["remarks",""],
["created_at",1747386361],
["updated_at",1747386361],
["coordinate",""]
["status",""],
]);
$this->validate($data, 'app\validate\attendance\Attendance.add');
$id = (new AttendanceService())->add($data);
@ -82,14 +74,12 @@ class Attendance extends BaseAdminController
$data = $this->request->params([
["campus_id",0],
["staff_id",0],
["attendance_date","2025-05-16 17:06:01"],
["attendance_date","2025-05-23 12:44:09"],
["check_in_time",""],
["check_out_time",""],
["status",""],
["remarks",""],
["created_at",1747386361],
["updated_at",1747386361],
["coordinate",""]
["status",""],
]);
$this->validate($data, 'app\validate\attendance\Attendance.edit');
(new AttendanceService())->edit($id, $data);
@ -107,4 +97,12 @@ class Attendance extends BaseAdminController
}
public function getCampusAll(){
return success(( new AttendanceService())->getCampusAll());
}
public function getPersonnelAll(){
return success(( new AttendanceService())->getPersonnelAll());
}
}

15
niucloud/app/adminapi/controller/contract/Contract.php

@ -28,14 +28,9 @@ class Contract extends BaseAdminController
*/
public function lists(){
$data = $this->request->params([
["contract_name",""],
["contract_template",""],
["contract_status",""],
["contract_type",""],
["remarks",""],
["created_at",""],
["updated_at",""],
["deleted_at",""]
["created_at",["",""]]
]);
return success((new ContractService())->getPage($data));
}
@ -60,9 +55,7 @@ class Contract extends BaseAdminController
["contract_status",""],
["contract_type",""],
["remarks",""],
["created_at",1747387361],
["updated_at",1747387361],
["deleted_at",1747387361]
]);
$this->validate($data, 'app\validate\contract\Contract.add');
$id = (new ContractService())->add($data);
@ -81,9 +74,7 @@ class Contract extends BaseAdminController
["contract_status",""],
["contract_type",""],
["remarks",""],
["created_at",1747387361],
["updated_at",1747387361],
["deleted_at",1747387361]
]);
$this->validate($data, 'app\validate\contract\Contract.edit');
(new ContractService())->edit($id, $data);

4
niucloud/app/adminapi/controller/customer_resources/CustomerResources.php

@ -81,7 +81,7 @@ class CustomerResources extends BaseAdminController
["communication",""],
["promised_visit_time",""],
["actual_visit_time",""],
["call_intent",""],
["call_intent","low"],
["first_visit_status",""],
["second_visit_status",""],
["is_closed",""]
@ -124,7 +124,7 @@ class CustomerResources extends BaseAdminController
["communication",""],
["promised_visit_time",""],
["actual_visit_time",""],
["call_intent",""],
["call_intent","low"],
["first_visit_status",""],
["second_visit_status",""],
["is_closed",""]

18
niucloud/app/adminapi/controller/exam_answers/ExamAnswers.php

@ -28,11 +28,7 @@ class ExamAnswers extends BaseAdminController
*/
public function lists(){
$data = $this->request->params([
["campus_id",""],
["user_id",""],
["question_id",""],
["answer",""],
["is_correct",""]
["campus_id",""]
]);
return success((new ExamAnswersService())->getPage($data));
}
@ -94,4 +90,16 @@ class ExamAnswers extends BaseAdminController
}
public function getCampusAll(){
return success(( new ExamAnswersService())->getCampusAll());
}
public function getPersonnelAll(){
return success(( new ExamAnswersService())->getPersonnelAll());
}
public function getExamQuestionsAll(){
return success(( new ExamAnswersService())->getExamQuestionsAll());
}
}

7
niucloud/app/adminapi/controller/exam_papers/ExamPapers.php

@ -29,8 +29,7 @@ class ExamPapers extends BaseAdminController
public function lists(){
$data = $this->request->params([
["selection_mode",""],
["total_score",""],
["passing_score",""]
["created_at",["",""]]
]);
return success((new ExamPapersService())->getPage($data));
}
@ -50,7 +49,9 @@ class ExamPapers extends BaseAdminController
*/
public function add(){
$data = $this->request->params([
["title",""],
["selection_mode",""],
["questions_ids",""],
["total_score",0.00],
["passing_score",0.00],
@ -67,7 +68,9 @@ class ExamPapers extends BaseAdminController
*/
public function edit(int $id){
$data = $this->request->params([
["title",""],
["selection_mode",""],
["questions_ids",""],
["total_score",0.00],
["passing_score",0.00],

35
niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php

@ -28,18 +28,9 @@ class ExamQuestions extends BaseAdminController
*/
public function lists(){
$data = $this->request->params([
["title",""],
["question_type",""],
["question_content_type",""],
["question_content",""],
["option_a_content_type",""],
["option_a_content",""],
["option_b_content_type",""],
["option_b_content",""],
["option_c_content_type",""],
["option_c_content",""],
["option_d_content_type",""],
["option_d_content",""],
["correct_answer",""]
["created_at",["",""]]
]);
return success((new ExamQuestionsService())->getPage($data));
}
@ -59,18 +50,11 @@ class ExamQuestions extends BaseAdminController
*/
public function add(){
$data = $this->request->params([
["title",""],
["question_type",""],
["question_content_type",""],
["question_content",""],
["option_a_content_type",""],
["option_a_content",""],
["option_b_content_type",""],
["option_b_content",""],
["option_c_content_type",""],
["option_c_content",""],
["option_d_content_type",""],
["option_d_content",""],
["correct_answer",""],
["option_json",[]]
]);
$this->validate($data, 'app\validate\exam_questions\ExamQuestions.add');
@ -85,18 +69,11 @@ class ExamQuestions extends BaseAdminController
*/
public function edit(int $id){
$data = $this->request->params([
["title",""],
["question_type",""],
["question_content_type",""],
["question_content",""],
["option_a_content_type",""],
["option_a_content",""],
["option_b_content_type",""],
["option_b_content",""],
["option_c_content_type",""],
["option_c_content",""],
["option_d_content_type",""],
["option_d_content",""],
["correct_answer",""],
["option_json",[]]
]);
$this->validate($data, 'app\validate\exam_questions\ExamQuestions.edit');

26
niucloud/app/adminapi/controller/exam_records/ExamRecords.php

@ -29,12 +29,8 @@ class ExamRecords extends BaseAdminController
public function lists(){
$data = $this->request->params([
["campus_id",""],
["user_id",""],
["paper_id",""],
["score",""],
["status",""],
["start_time",""],
["end_time",""]
["status",""]
]);
return success((new ExamRecordsService())->getPage($data));
}
@ -59,8 +55,8 @@ class ExamRecords extends BaseAdminController
["paper_id",0],
["score",0.00],
["status",""],
["start_time","2025-05-16 17:43:09"],
["end_time","2025-05-16 17:43:09"],
["start_time","2025-05-23 17:15:15"],
["end_time","2025-05-23 17:15:15"],
]);
$this->validate($data, 'app\validate\exam_records\ExamRecords.add');
@ -80,8 +76,8 @@ class ExamRecords extends BaseAdminController
["paper_id",0],
["score",0.00],
["status",""],
["start_time","2025-05-16 17:43:09"],
["end_time","2025-05-16 17:43:09"],
["start_time","2025-05-23 17:15:15"],
["end_time","2025-05-23 17:15:15"],
]);
$this->validate($data, 'app\validate\exam_records\ExamRecords.edit');
@ -100,4 +96,16 @@ class ExamRecords extends BaseAdminController
}
public function getCampusAll(){
return success(( new ExamRecordsService())->getCampusAll());
}
public function getPersonnelAll(){
return success(( new ExamRecordsService())->getPersonnelAll());
}
public function getExamPapersAll(){
return success(( new ExamRecordsService())->getExamPapersAll());
}
}

20
niucloud/app/adminapi/controller/performance_records/PerformanceRecords.php

@ -29,12 +29,8 @@ class PerformanceRecords extends BaseAdminController
public function lists(){
$data = $this->request->params([
["staff_id",""],
["resource_id",""],
["order_id",""],
["order_status",""],
["performance_type",""],
["performance_value",""],
["remarks",""]
["created_at",["",""]]
]);
return success((new PerformanceRecordsService())->getPage($data));
}
@ -56,7 +52,6 @@ class PerformanceRecords extends BaseAdminController
$data = $this->request->params([
["staff_id",0],
["resource_id",0],
["order_id",0],
["order_status",""],
["performance_type",""],
["performance_value",0.00],
@ -77,7 +72,6 @@ class PerformanceRecords extends BaseAdminController
$data = $this->request->params([
["staff_id",0],
["resource_id",0],
["order_id",0],
["order_status",""],
["performance_type",""],
["performance_value",0.00],
@ -100,4 +94,16 @@ class PerformanceRecords extends BaseAdminController
}
public function getPersonnelAll(){
return success(( new PerformanceRecordsService())->getPersonnelAll());
}
public function getCustomerResourcesAll(){
return success(( new PerformanceRecordsService())->getCustomerResourcesAll());
}
public function getOrderTableAll(){
return success(( new PerformanceRecordsService())->getOrderTableAll());
}
}

121
niucloud/app/adminapi/controller/student/Student.php

@ -0,0 +1,121 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\adminapi\controller\student;
use core\base\BaseAdminController;
use app\service\admin\student\StudentService;
/**
* 学员控制器
* Class Student
* @package app\adminapi\controller\student
*/
class Student extends BaseAdminController
{
/**
* 获取学员列表
* @return \think\Response
*/
public function lists(){
$data = $this->request->params([
["campus_id",""],
["name",""],
["emergency_contact",""],
["contact_phone",""],
["created_at",["",""]]
]);
return success((new StudentService())->getPage($data));
}
/**
* 学员详情
* @param int $id
* @return \think\Response
*/
public function info(int $id){
return success((new StudentService())->getInfo($id));
}
/**
* 添加学员
* @return \think\Response
*/
public function add(){
$data = $this->request->params([
["campus_id",0],
["class_id",0],
["user_id",0],
["name",""],
["gender",0],
["age",0.00],
["birthday","2025-05-23 17:31:39"],
["emergency_contact",""],
["contact_phone",""],
["note",""],
["status",0],
]);
$this->validate($data, 'app\validate\student\Student.add');
$id = (new StudentService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
}
/**
* 学员编辑
* @param $id 学员id
* @return \think\Response
*/
public function edit(int $id){
$data = $this->request->params([
["campus_id",0],
["class_id",0],
["user_id",0],
["name",""],
["gender",0],
["age",0.00],
["birthday","2025-05-23 17:31:39"],
["emergency_contact",""],
["contact_phone",""],
["note",""],
["status",0],
]);
$this->validate($data, 'app\validate\student\Student.edit');
(new StudentService())->edit($id, $data);
return success('EDIT_SUCCESS');
}
/**
* 学员删除
* @param $id 学员id
* @return \think\Response
*/
public function del(int $id){
(new StudentService())->del($id);
return success('DELETE_SUCCESS');
}
public function getCampusAll(){
return success(( new StudentService())->getCampusAll());
}
public function getClassGradeAll(){
return success(( new StudentService())->getClassGradeAll());
}
public function getMemberAll(){
return success(( new StudentService())->getMemberAll());
}
}

9
niucloud/app/adminapi/route/attendance.php

@ -16,6 +16,11 @@ use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- attendance
Route::group('attendance', function () {
@ -31,6 +36,10 @@ Route::group('attendance', function () {
//删除考勤
Route::delete('attendance/:id', 'attendance.Attendance/del');
Route::get('campus_all','attendance.Attendance/getCampusAll');
Route::get('personnel_all','attendance.Attendance/getPersonnelAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

2
niucloud/app/adminapi/route/contract.php

@ -14,6 +14,8 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- contract
Route::group('contract', function () {

9
niucloud/app/adminapi/route/exam_answers.php

@ -14,6 +14,9 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- exam_answers
Route::group('exam_answers', function () {
@ -29,6 +32,12 @@ Route::group('exam_answers', function () {
//删除答题记录
Route::delete('exam_answers/:id', 'exam_answers.ExamAnswers/del');
Route::get('campus_all','exam_answers.ExamAnswers/getCampusAll');
Route::get('personnel_all','exam_answers.ExamAnswers/getPersonnelAll');
Route::get('exam_questions_all','exam_answers.ExamAnswers/getExamQuestionsAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

1
niucloud/app/adminapi/route/exam_papers.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- exam_papers
Route::group('exam_papers', function () {

1
niucloud/app/adminapi/route/exam_questions.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- exam_questions
Route::group('exam_questions', function () {

7
niucloud/app/adminapi/route/exam_records.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- exam_records
Route::group('exam_records', function () {
@ -29,6 +30,12 @@ Route::group('exam_records', function () {
//删除考试记录
Route::delete('exam_records/:id', 'exam_records.ExamRecords/del');
Route::get('campus_all','exam_records.ExamRecords/getCampusAll');
Route::get('personnel_all','exam_records.ExamRecords/getPersonnelAll');
Route::get('exam_papers_all','exam_records.ExamRecords/getExamPapersAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

7
niucloud/app/adminapi/route/performance_records.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- performance_records
Route::group('performance_records', function () {
@ -29,6 +30,12 @@ Route::group('performance_records', function () {
//删除绩效记录
Route::delete('performance_records/:id', 'performance_records.PerformanceRecords/del');
Route::get('personnel_all','performance_records.PerformanceRecords/getPersonnelAll');
Route::get('customer_resources_all','performance_records.PerformanceRecords/getCustomerResourcesAll');
Route::get('order_table_all','performance_records.PerformanceRecords/getOrderTableAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

44
niucloud/app/adminapi/route/student.php

@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- student
Route::group('student', function () {
//学员列表
Route::get('student', 'student.Student/lists');
//学员详情
Route::get('student/:id', 'student.Student/info');
//添加学员
Route::post('student', 'student.Student/add');
//编辑学员
Route::put('student/:id', 'student.Student/edit');
//删除学员
Route::delete('student/:id', 'student.Student/del');
Route::get('campus_all','student.Student/getCampusAll');
Route::get('class_grade_all','student.Student/getClassGradeAll');
Route::get('member_all','student.Student/getMemberAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,
AdminLog::class
]);
// USER_CODE_END -- student

64
niucloud/app/model/attendance/Attendance.php

@ -9,22 +9,26 @@
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\campus;
namespace app\model\attendance;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
/**
* 校区模型
* Class Campus
* @package app\model\campus
* 考勤模型
* Class Attendance
* @package app\model\attendance
*/
class Campus extends BaseModel
class Attendance extends BaseModel
{
use SoftDelete;
/**
* 数据表主键
@ -36,53 +40,57 @@ class Campus extends BaseModel
* 模型名称
* @var string
*/
protected $name = 'campus';
protected $name = 'attendance';
/**
* 定义软删除标记字段.
* @var string
*/
protected $deleteTime = 'delete_time';
/**
* 定义软删除字段的默认值.
* @var int
* 搜索器:考勤校区
* @param $value
* @param $data
*/
protected $defaultSoftDelete = 0;
public function searchCampusIdAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_id", $value);
}
}
/**
* 搜索器:校区校区名称
* 搜索器:考勤人员
* @param $value
* @param $data
*/
public function searchCampusNameAttr($query, $value, $data)
public function searchStaffIdAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_name", "like", "%".$value."%");
$query->where("staff_id", $value);
}
}
/**
* 搜索器:校区校区地址
* 搜索器:考勤考勤日期
* @param $value
* @param $data
*/
public function searchCampusAddressAttr($query, $value, $data)
public function searchAttendanceDateAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_address", $value);
$query->where("attendance_date", $value);
}
}
/**
* 搜索器:校区校区状态
* 搜索器:考勤考勤状态
* @param $value
* @param $data
*/
public function searchCampusStatusAttr($query, $value, $data)
public function searchStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_status", $value);
$query->where("status", $value);
}
}
@ -91,4 +99,12 @@ class Campus extends BaseModel
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'staff_id')->joinType('left')->withField('name,id')->bind(['staff_id_name'=>'name']);
}
}

128
niucloud/app/model/contract/Contract.php

@ -9,7 +9,7 @@
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\campus;
namespace app\model\contract;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
@ -17,14 +17,14 @@ use think\model\relation\HasMany;
use think\model\relation\HasOne;
/**
* 校区模型
* Class Campus
* @package app\model\campus
* 合同模型
* Class Contract
* @package app\model\contract
*/
class Campus extends BaseModel
class Contract extends BaseModel
{
use SoftDelete;
/**
* 数据表主键
@ -36,129 +36,59 @@ class Campus extends BaseModel
* 模型名称
* @var string
*/
protected $name = 'campus';
/**
* 搜索器:校区主键ID
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:校区校区名称
* @param $value
* @param $data
*/
public function searchCampusNameAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_name", $value);
}
}
/**
* 搜索器:校区校区地址
* @param $value
* @param $data
*/
public function searchCampusAddressAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_address", $value);
}
}
/**
* 搜索器:校区校区预览图,存储图片路径
* @param $value
* @param $data
*/
public function searchCampusPreviewImageAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_preview_image", $value);
}
}
/**
* 搜索器:校区校区坐标,格式为经度,纬度
* @param $value
* @param $data
*/
public function searchCampusCoordinatesAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_coordinates", $value);
}
}
protected $name = 'contract';
/**
* 搜索器:校区校区介绍
* @param $value
* @param $data
* 定义软删除标记字段.
* @var string
*/
public function searchCampusIntroductionAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_introduction", $value);
}
}
protected $deleteTime = 'deleted_at';
/**
* 搜索器:校区校区状态:0-禁用,1-启用
* @param $value
* @param $data
* 定义软删除字段的默认值.
* @var int
*/
public function searchCampusStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_status", $value);
}
}
protected $defaultSoftDelete = 0;
/**
* 搜索器:校区校区创建时间
* 搜索器:合同合同状态
* @param $value
* @param $data
*/
public function searchCreateTimeAttr($query, $value, $data)
public function searchContractStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("create_time", $value);
$query->where("contract_status", $value);
}
}
/**
* 搜索器:校区校区更新时间
* 搜索器:合同合同类型
* @param $value
* @param $data
*/
public function searchUpdateTimeAttr($query, $value, $data)
public function searchContractTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("update_time", $value);
$query->where("contract_type", $value);
}
}
/**
* 搜索器:校区逻辑删除字段,NULL表示未删除,非空表示已删除
* 搜索器:合同创建时间
* @param $value
* @param $data
*/
public function searchDeleteTimeAttr($query, $value, $data)
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("delete_time", $value);
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}

74
niucloud/app/model/exam_answers/ExamAnswers.php

@ -16,6 +16,12 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
use app\model\exam_questions\ExamQuestions;
/**
* 答题记录模型
* Class ExamAnswers
@ -43,19 +49,7 @@ class ExamAnswers extends BaseModel
/**
* 搜索器:答题记录答题记录编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:答题记录校区ID
* 搜索器:答题记录校区
* @param $value
* @param $data
*/
@ -66,57 +60,21 @@ class ExamAnswers extends BaseModel
}
}
/**
* 搜索器:答题记录人员ID
* @param $value
* @param $data
*/
public function searchUserIdAttr($query, $value, $data)
{
if ($value) {
$query->where("user_id", $value);
}
}
/**
* 搜索器:答题记录试题ID
* @param $value
* @param $data
*/
public function searchQuestionIdAttr($query, $value, $data)
{
if ($value) {
$query->where("question_id", $value);
}
}
/**
* 搜索器:答题记录用户答案
* @param $value
* @param $data
*/
public function searchAnswerAttr($query, $value, $data)
{
if ($value) {
$query->where("answer", $value);
}
}
/**
* 搜索器:答题记录是否正确
* @param $value
* @param $data
*/
public function searchIsCorrectAttr($query, $value, $data)
{
if ($value) {
$query->where("is_correct", $value);
}
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'user_id')->joinType('left')->withField('name,id')->bind(['user_id_name'=>'name']);
}
public function examQuestions(){
return $this->hasOne(ExamQuestions::class, 'id', 'question_id')->joinType('left')->withField('title,id')->bind(['question_id_name'=>'title']);
}
}

40
niucloud/app/model/exam_papers/ExamPapers.php

@ -43,19 +43,7 @@ class ExamPapers extends BaseModel
/**
* 搜索器:试卷试卷编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:试卷题目选择模式: random-随机主题, manual-自选题目
* 搜索器:试卷题目选择模式
* @param $value
* @param $data
*/
@ -67,26 +55,20 @@ class ExamPapers extends BaseModel
}
/**
* 搜索器:试卷总分
* 搜索器:试卷创建时间
* @param $value
* @param $data
*/
public function searchTotalScoreAttr($query, $value, $data)
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("total_score", $value);
}
}
/**
* 搜索器:试卷合格分数
* @param $value
* @param $data
*/
public function searchPassingScoreAttr($query, $value, $data)
{
if ($value) {
$query->where("passing_score", $value);
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}

147
niucloud/app/model/exam_questions/ExamQuestions.php

@ -40,22 +40,27 @@ class ExamQuestions extends BaseModel
// 设置json类型字段
protected $json = [ 'option_json' ];
// 设置JSON数据返回数组
protected $jsonAssoc = true;
/**
* 搜索器:试题试题编号
* 搜索器:试题题目标题
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
public function searchTitleAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
$query->where("title", $value);
}
}
/**
* 搜索器:试题题型: single_choice-单选, multiple_choice-多选, true_false-判断
* 搜索器:试题题型
* @param $value
* @param $data
*/
@ -67,134 +72,20 @@ class ExamQuestions extends BaseModel
}
/**
* 搜索器:试题题干类型: text-文本, image-图片
* @param $value
* @param $data
*/
public function searchQuestionContentTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("question_content_type", $value);
}
}
/**
* 搜索器:试题题干内容(如果是图片则存储URL)
* @param $value
* @param $data
*/
public function searchQuestionContentAttr($query, $value, $data)
{
if ($value) {
$query->where("question_content", $value);
}
}
/**
* 搜索器:试题选项A类型: text-文本, image-图片
* @param $value
* @param $data
*/
public function searchOptionAContentTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("option_a_content_type", $value);
}
}
/**
* 搜索器:试题选项A内容(如果是图片则存储URL)
* @param $value
* @param $data
*/
public function searchOptionAContentAttr($query, $value, $data)
{
if ($value) {
$query->where("option_a_content", $value);
}
}
/**
* 搜索器:试题选项B类型: text-文本, image-图片
* @param $value
* @param $data
*/
public function searchOptionBContentTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("option_b_content_type", $value);
}
}
/**
* 搜索器:试题选项B内容(如果是图片则存储URL)
* 搜索器:试题创建时间
* @param $value
* @param $data
*/
public function searchOptionBContentAttr($query, $value, $data)
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("option_b_content", $value);
}
}
/**
* 搜索器:试题选项C类型: text-文本, image-图片
* @param $value
* @param $data
*/
public function searchOptionCContentTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("option_c_content_type", $value);
}
}
/**
* 搜索器:试题选项C内容(如果是图片则存储URL)
* @param $value
* @param $data
*/
public function searchOptionCContentAttr($query, $value, $data)
{
if ($value) {
$query->where("option_c_content", $value);
}
}
/**
* 搜索器:试题选项D类型: text-文本, image-图片
* @param $value
* @param $data
*/
public function searchOptionDContentTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("option_d_content_type", $value);
}
}
/**
* 搜索器:试题选项D内容(如果是图片则存储URL)
* @param $value
* @param $data
*/
public function searchOptionDContentAttr($query, $value, $data)
{
if ($value) {
$query->where("option_d_content", $value);
}
}
/**
* 搜索器:试题正确答案(如果是多选,答案格式为如"A,B,D")
* @param $value
* @param $data
*/
public function searchCorrectAnswerAttr($query, $value, $data)
{
if ($value) {
$query->where("correct_answer", $value);
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}

80
niucloud/app/model/exam_records/ExamRecords.php

@ -16,6 +16,12 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
use app\model\exam_papers\ExamPapers;
/**
* 考试记录模型
* Class ExamRecords
@ -43,19 +49,7 @@ class ExamRecords extends BaseModel
/**
* 搜索器:考试记录记录编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:考试记录校区ID
* 搜索器:考试记录校区
* @param $value
* @param $data
*/
@ -67,19 +61,7 @@ class ExamRecords extends BaseModel
}
/**
* 搜索器:考试记录人员ID
* @param $value
* @param $data
*/
public function searchUserIdAttr($query, $value, $data)
{
if ($value) {
$query->where("user_id", $value);
}
}
/**
* 搜索器:考试记录试卷ID
* 搜索器:考试记录试卷
* @param $value
* @param $data
*/
@ -91,19 +73,7 @@ class ExamRecords extends BaseModel
}
/**
* 搜索器:考试记录得分
* @param $value
* @param $data
*/
public function searchScoreAttr($query, $value, $data)
{
if ($value) {
$query->where("score", $value);
}
}
/**
* 搜索器:考试记录考试状态: in_progress-进行中, completed-已完成
* 搜索器:考试记录考试状态
* @param $value
* @param $data
*/
@ -114,33 +84,21 @@ class ExamRecords extends BaseModel
}
}
/**
* 搜索器:考试记录考试开始时间
* @param $value
* @param $data
*/
public function searchStartTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("start_time", $value);
}
}
/**
* 搜索器:考试记录考试结束时间
* @param $value
* @param $data
*/
public function searchEndTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("end_time", $value);
}
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'user_id')->joinType('left')->withField('name,id')->bind(['user_id_name'=>'name']);
}
public function examPapers(){
return $this->hasOne(ExamPapers::class, 'id', 'paper_id')->joinType('left')->withField('title,id')->bind(['paper_id_name'=>'title']);
}
}

92
niucloud/app/model/performance_records/PerformanceRecords.php

@ -16,6 +16,12 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\personnel\Personnel;
use app\model\customer_resources\CustomerResources;
use app\model\order_table\OrderTable;
/**
* 绩效记录模型
* Class PerformanceRecords
@ -43,19 +49,7 @@ class PerformanceRecords extends BaseModel
/**
* 搜索器:绩效记录绩效编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:绩效记录员工ID
* 搜索器:绩效记录员工
* @param $value
* @param $data
*/
@ -67,31 +61,7 @@ class PerformanceRecords extends BaseModel
}
/**
* 搜索器:绩效记录资源ID
* @param $value
* @param $data
*/
public function searchResourceIdAttr($query, $value, $data)
{
if ($value) {
$query->where("resource_id", $value);
}
}
/**
* 搜索器:绩效记录订单ID
* @param $value
* @param $data
*/
public function searchOrderIdAttr($query, $value, $data)
{
if ($value) {
$query->where("order_id", $value);
}
}
/**
* 搜索器:绩效记录订单状态: pending-待处理, completed-已完成, cancelled-已取消
* 搜索器:绩效记录订单状态
* @param $value
* @param $data
*/
@ -103,44 +73,38 @@ class PerformanceRecords extends BaseModel
}
/**
* 搜索器:绩效记录绩效类型: sales-销售绩效, marketing-市场绩效, other-其他
* 搜索器:绩效记录创建时间
* @param $value
* @param $data
*/
public function searchPerformanceTypeAttr($query, $value, $data)
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("performance_type", $value);
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}
/**
* 搜索器:绩效记录绩效金额或分值
* @param $value
* @param $data
*/
public function searchPerformanceValueAttr($query, $value, $data)
{
if ($value) {
$query->where("performance_value", $value);
}
}
/**
* 搜索器:绩效记录备注
* @param $value
* @param $data
*/
public function searchRemarksAttr($query, $value, $data)
{
if ($value) {
$query->where("remarks", $value);
}
}
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'staff_id')->joinType('left')->withField('name,id')->bind(['staff_id_name'=>'name']);
}
public function customerResources(){
return $this->hasOne(CustomerResources::class, 'id', 'resource_id')->joinType('left')->withField('name,id')->bind(['resource_id_name'=>'name']);
}
public function orderTable(){
return $this->hasOne(OrderTable::class, 'id', 'order_id')->joinType('left')->withField('payment_id,id')->bind(['order_id_name'=>'payment_id']);
}
}

97
niucloud/app/model/student/Student.php

@ -16,11 +16,21 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\campus\Campus;
use app\model\class_grade\ClassGrade;
use app\model\member\Member;
/**
* 学员模型
* Class Student
* @package app\model\student
*/
class Student extends BaseModel
{
use SoftDelete;
use SoftDelete;
/**
* 数据表主键
@ -34,22 +44,99 @@ class Student extends BaseModel
*/
protected $name = 'student';
/**
* 定义软删除标记字段
* 定义软删除标记字段.
* @var string
*/
protected $deleteTime = 'deleted_at';
/**
* 定义软删除字段的默认值
* 定义软删除字段的默认值.
* @var int
*/
protected $defaultSoftDelete = 0;
/**
* 搜索器:学员校区
* @param $value
* @param $data
*/
public function searchCampusIdAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_id", $value);
}
}
/**
* 搜索器:学员学员姓名
* @param $value
* @param $data
*/
public function searchNameAttr($query, $value, $data)
{
if ($value) {
$query->where("name", $value);
}
}
/**
* 搜索器:学员紧急联系人
* @param $value
* @param $data
*/
public function searchEmergencyContactAttr($query, $value, $data)
{
if ($value) {
$query->where("emergency_contact", $value);
}
}
/**
* 搜索器:学员联系人电话
* @param $value
* @param $data
*/
public function searchContactPhoneAttr($query, $value, $data)
{
if ($value) {
$query->where("contact_phone", $value);
}
}
/**
* 搜索器:学员创建时间
* @param $value
* @param $data
*/
public function searchCreatedAtAttr($query, $value, $data)
{
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
public function classGrade(){
return $this->hasOne(ClassGrade::class, 'id', 'class_id')->joinType('left')->withField('class_name,id')->bind(['class_id_name'=>'class_name']);
}
public function member(){
return $this->hasOne(Member::class, 'member_id', 'user_id')->joinType('left')->withField('nickname,member_id')->bind(['user_id_name'=>'nickname']);
}
}

20
niucloud/app/service/admin/attendance/AttendanceService.php

@ -12,6 +12,8 @@
namespace app\service\admin\attendance;
use app\model\attendance\Attendance;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
use core\base\BaseAdminService;
@ -36,10 +38,10 @@ class AttendanceService extends BaseAdminService
*/
public function getPage(array $where = [])
{
$field = 'id,campus_id,staff_id,attendance_date,check_in_time,check_out_time,status,remarks,created_at,updated_at,coordinate';
$field = 'id,campus_id,staff_id,attendance_date,check_in_time,check_out_time,remarks,status,created_at,updated_at,coordinate';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","campus_id","staff_id","attendance_date","check_in_time","check_out_time","status","remarks","created_at","updated_at","coordinate"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["campus_id","staff_id","attendance_date","status"], $where)->with(['campus','personnel'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -51,9 +53,9 @@ class AttendanceService extends BaseAdminService
*/
public function getInfo(int $id)
{
$field = 'id,campus_id,staff_id,attendance_date,check_in_time,check_out_time,status,remarks,created_at,updated_at,coordinate';
$field = 'id,campus_id,staff_id,attendance_date,check_in_time,check_out_time,remarks,status,created_at,updated_at,coordinate';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','personnel'])->findOrEmpty()->toArray();
return $info;
}
@ -95,5 +97,15 @@ class AttendanceService extends BaseAdminService
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
}

2
niucloud/app/service/admin/contract/ContractService.php

@ -39,7 +39,7 @@ class ContractService extends BaseAdminService
$field = 'id,contract_name,contract_template,contract_status,contract_type,remarks,created_at,updated_at,deleted_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","contract_name","contract_template","contract_status","contract_type","remarks","created_at","updated_at","deleted_at"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["contract_status","contract_type","created_at"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}

6
niucloud/app/service/admin/customer_resources/CustomerResourcesService.php

@ -191,7 +191,7 @@ class CustomerResourcesService extends BaseAdminService
// return fail("操作失败");
// }
$data['consultant'] = 1;
// $data['consultant'] = 1;
$res = $this->model->where([['id', '=', $id]])->findOrEmpty()->toArray();
@ -222,7 +222,7 @@ class CustomerResourcesService extends BaseAdminService
if($resources_save['is_save']){
$customerResourceChanges->insert([
'customer_resource_id' => $id,
'operator_id' => $data['consultant'],
'operator_id' => $res['consultant'],
'campus_id' => $data['campus'],
'modified_fields' => $resources_save['modified_fields'],
'old_values' => $resources_save['old_values'],
@ -262,7 +262,7 @@ class CustomerResourcesService extends BaseAdminService
$sixSpeedModificationLog->insert([
'customer_resource_id' => $id,
'operator_id' => $data['consultant'],
'operator_id' => $res['consultant'],
'campus_id' => $data['campus'],
'modified_field' => $six_save['modified_fields'],
'old_value' => $six_save['old_values'],

23
niucloud/app/service/admin/exam_answers/ExamAnswersService.php

@ -12,6 +12,9 @@
namespace app\service\admin\exam_answers;
use app\model\exam_answers\ExamAnswers;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
use app\model\exam_questions\ExamQuestions;
use core\base\BaseAdminService;
@ -39,7 +42,7 @@ class ExamAnswersService extends BaseAdminService
$field = 'id,campus_id,user_id,question_id,answer,is_correct,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","campus_id","user_id","question_id","answer","is_correct"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["campus_id"], $where)->with(['campus','personnel','examQuestions'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -53,7 +56,8 @@ class ExamAnswersService extends BaseAdminService
{
$field = 'id,campus_id,user_id,question_id,answer,is_correct,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','personnel','examQuestions'])->findOrEmpty()->toArray();
$info['is_correct'] = strval($info['is_correct']);
return $info;
}
@ -95,5 +99,20 @@ class ExamAnswersService extends BaseAdminService
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getExamQuestionsAll(){
$examQuestionsModel = new ExamQuestions();
return $examQuestionsModel->select()->toArray();
}
}

6
niucloud/app/service/admin/exam_papers/ExamPapersService.php

@ -36,10 +36,10 @@ class ExamPapersService extends BaseAdminService
*/
public function getPage(array $where = [])
{
$field = 'id,selection_mode,total_score,passing_score,created_at,updated_at';
$field = 'id,title,selection_mode,questions_ids,total_score,passing_score,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","selection_mode","total_score","passing_score"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["selection_mode","created_at"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -51,7 +51,7 @@ class ExamPapersService extends BaseAdminService
*/
public function getInfo(int $id)
{
$field = 'id,selection_mode,total_score,passing_score,created_at,updated_at';
$field = 'id,title,selection_mode,questions_ids,total_score,passing_score,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
return $info;

6
niucloud/app/service/admin/exam_questions/ExamQuestionsService.php

@ -36,10 +36,10 @@ class ExamQuestionsService extends BaseAdminService
*/
public function getPage(array $where = [])
{
$field = 'id,question_type,question_content_type,question_content,option_a_content_type,option_a_content,option_b_content_type,option_b_content,option_c_content_type,option_c_content,option_d_content_type,option_d_content,correct_answer,created_at,updated_at';
$field = 'id,title,question_type,question_content_type,question_content,option_json,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","question_type","question_content_type","question_content","option_a_content_type","option_a_content","option_b_content_type","option_b_content","option_c_content_type","option_c_content","option_d_content_type","option_d_content","correct_answer"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["title","question_type","created_at"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -51,7 +51,7 @@ class ExamQuestionsService extends BaseAdminService
*/
public function getInfo(int $id)
{
$field = 'id,question_type,question_content_type,question_content,option_a_content_type,option_a_content,option_b_content_type,option_b_content,option_c_content_type,option_c_content,option_d_content_type,option_d_content,correct_answer,created_at,updated_at';
$field = 'id,title,question_type,question_content_type,question_content,option_json,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
return $info;

22
niucloud/app/service/admin/exam_records/ExamRecordsService.php

@ -12,6 +12,9 @@
namespace app\service\admin\exam_records;
use app\model\exam_records\ExamRecords;
use app\model\campus\Campus;
use app\model\personnel\Personnel;
use app\model\exam_papers\ExamPapers;
use core\base\BaseAdminService;
@ -39,7 +42,7 @@ class ExamRecordsService extends BaseAdminService
$field = 'id,campus_id,user_id,paper_id,score,status,start_time,end_time,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","campus_id","user_id","paper_id","score","status","start_time","end_time"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["campus_id","paper_id","status"], $where)->with(['campus','personnel','examPapers'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -53,7 +56,7 @@ class ExamRecordsService extends BaseAdminService
{
$field = 'id,campus_id,user_id,paper_id,score,status,start_time,end_time,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','personnel','examPapers'])->findOrEmpty()->toArray();
return $info;
}
@ -95,5 +98,20 @@ class ExamRecordsService extends BaseAdminService
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getExamPapersAll(){
$examPapersModel = new ExamPapers();
return $examPapersModel->select()->toArray();
}
}

22
niucloud/app/service/admin/performance_records/PerformanceRecordsService.php

@ -12,6 +12,9 @@
namespace app\service\admin\performance_records;
use app\model\performance_records\PerformanceRecords;
use app\model\personnel\Personnel;
use app\model\customer_resources\CustomerResources;
use app\model\order_table\OrderTable;
use core\base\BaseAdminService;
@ -39,7 +42,7 @@ class PerformanceRecordsService extends BaseAdminService
$field = 'id,staff_id,resource_id,order_id,order_status,performance_type,performance_value,remarks,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","staff_id","resource_id","order_id","order_status","performance_type","performance_value","remarks"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["staff_id","order_status","created_at"], $where)->with(['personnel','customerResources','orderTable'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -53,7 +56,7 @@ class PerformanceRecordsService extends BaseAdminService
{
$field = 'id,staff_id,resource_id,order_id,order_status,performance_type,performance_value,remarks,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel','customerResources','orderTable'])->findOrEmpty()->toArray();
return $info;
}
@ -95,5 +98,20 @@ class PerformanceRecordsService extends BaseAdminService
}
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
public function getOrderTableAll(){
$orderTableModel = new OrderTable();
return $orderTableModel->select()->toArray();
}
}

117
niucloud/app/service/admin/student/StudentService.php

@ -0,0 +1,117 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\student;
use app\model\student\Student;
use app\model\campus\Campus;
use app\model\class_grade\ClassGrade;
use app\model\member\Member;
use core\base\BaseAdminService;
/**
* 学员服务层
* Class StudentService
* @package app\service\admin\student
*/
class StudentService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new Student();
}
/**
* 获取学员列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,campus_id,class_id,user_id,name,gender,age,birthday,emergency_contact,contact_phone,note,status,created_at,updated_at,deleted_at';
$order = 'id asc';
$search_model = $this->model->withSearch(["campus_id","name","emergency_contact","contact_phone","created_at"], $where)->with(['campus','classGrade','member'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取学员信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,campus_id,class_id,user_id,name,gender,age,birthday,emergency_contact,contact_phone,note,status,created_at,updated_at,deleted_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus','classGrade','member'])->findOrEmpty()->toArray();
return $info;
}
/**
* 添加学员
* @param array $data
* @return mixed
*/
public function add(array $data)
{
$res = $this->model->create($data);
return $res->id;
}
/**
* 学员编辑
* @param int $id
* @param array $data
* @return bool
*/
public function edit(int $id, array $data)
{
$this->model->where([['id', '=', $id]])->update($data);
return true;
}
/**
* 删除学员
* @param int $id
* @return bool
*/
public function del(int $id)
{
$model = $this->model->where([['id', '=', $id]])->find();
$res = $model->delete();
return $res;
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
public function getClassGradeAll(){
$classGradeModel = new ClassGrade();
return $classGradeModel->select()->toArray();
}
public function getMemberAll(){
$memberModel = new Member();
return $memberModel->select()->toArray();
}
}

8
niucloud/app/validate/attendance/Attendance.php

@ -23,6 +23,8 @@ class Attendance extends BaseValidate
'campus_id' => 'require',
'staff_id' => 'require',
'attendance_date' => 'require',
'check_in_time' => 'require',
'check_out_time' => 'require',
'status' => 'require',
];
@ -30,12 +32,14 @@ class Attendance extends BaseValidate
'campus_id.require' => ['common_validate.require', ['campus_id']],
'staff_id.require' => ['common_validate.require', ['staff_id']],
'attendance_date.require' => ['common_validate.require', ['attendance_date']],
'check_in_time.require' => ['common_validate.require', ['check_in_time']],
'check_out_time.require' => ['common_validate.require', ['check_out_time']],
'status.require' => ['common_validate.require', ['status']],
];
protected $scene = [
"add" => ['campus_id', 'staff_id', 'attendance_date', 'check_in_time', 'check_out_time', 'status', 'remarks', 'created_at', 'updated_at', 'coordinate'],
"edit" => ['campus_id', 'staff_id', 'attendance_date', 'check_in_time', 'check_out_time', 'status', 'remarks', 'created_at', 'updated_at', 'coordinate']
"add" => ['campus_id', 'staff_id', 'attendance_date', 'check_in_time', 'check_out_time', 'remarks', 'status'],
"edit" => ['campus_id', 'staff_id', 'attendance_date', 'check_in_time', 'check_out_time', 'remarks', 'status']
];
}

4
niucloud/app/validate/contract/Contract.php

@ -34,8 +34,8 @@ class Contract extends BaseValidate
];
protected $scene = [
"add" => ['contract_name', 'contract_template', 'contract_status', 'contract_type', 'remarks', 'created_at', 'updated_at', 'deleted_at'],
"edit" => ['contract_name', 'contract_template', 'contract_status', 'contract_type', 'remarks', 'created_at', 'updated_at', 'deleted_at']
"add" => ['contract_name', 'contract_template', 'contract_status', 'contract_type', 'remarks'],
"edit" => ['contract_name', 'contract_template', 'contract_status', 'contract_type', 'remarks']
];
}

10
niucloud/app/validate/exam_papers/ExamPapers.php

@ -21,19 +21,21 @@ class ExamPapers extends BaseValidate
protected $rule = [
'selection_mode' => 'require',
'total_score' => 'require',
'passing_score' => 'require',
'total_score' => 'require|between:0,100',
'passing_score' => 'require|between:0,100',
];
protected $message = [
'selection_mode.require' => ['common_validate.require', ['selection_mode']],
'total_score.require' => ['common_validate.require', ['total_score']],
'total_score.between' => ['common_validate.between', ['total_score','0','100']],
'passing_score.require' => ['common_validate.require', ['passing_score']],
'passing_score.between' => ['common_validate.between', ['passing_score','0','100']],
];
protected $scene = [
"add" => ['selection_mode', 'total_score', 'passing_score'],
"edit" => ['selection_mode', 'total_score', 'passing_score']
"add" => ['selection_mode', 'questions_ids', 'total_score', 'passing_score'],
"edit" => ['selection_mode', 'questions_ids', 'total_score', 'passing_score']
];
}

10
niucloud/app/validate/exam_questions/ExamQuestions.php

@ -20,22 +20,24 @@ class ExamQuestions extends BaseValidate
{
protected $rule = [
'title' => 'require',
'question_type' => 'require',
'question_content_type' => 'require',
'question_content' => 'require',
'correct_answer' => 'require',
'option_json' => 'require',
];
protected $message = [
'title.require' => ['common_validate.require', ['title']],
'question_type.require' => ['common_validate.require', ['question_type']],
'question_content_type.require' => ['common_validate.require', ['question_content_type']],
'question_content.require' => ['common_validate.require', ['question_content']],
'correct_answer.require' => ['common_validate.require', ['correct_answer']],
'option_json.require' => ['common_validate.require', ['option_json']],
];
protected $scene = [
"add" => ['question_type', 'question_content_type', 'question_content', 'option_a_content_type', 'option_a_content', 'option_b_content_type', 'option_b_content', 'option_c_content_type', 'option_c_content', 'option_d_content_type', 'option_d_content', 'correct_answer'],
"edit" => ['question_type', 'question_content_type', 'question_content', 'option_a_content_type', 'option_a_content', 'option_b_content_type', 'option_b_content', 'option_c_content_type', 'option_c_content', 'option_d_content_type', 'option_d_content', 'correct_answer']
"add" => ['title', 'question_type', 'question_content_type', 'question_content', 'option_json'],
"edit" => ['title', 'question_type', 'question_content_type', 'question_content', 'option_json']
];
}

2
niucloud/app/validate/exam_records/ExamRecords.php

@ -23,12 +23,14 @@ class ExamRecords extends BaseValidate
'campus_id' => 'require',
'user_id' => 'require',
'paper_id' => 'require',
'score' => 'between:0,100',
];
protected $message = [
'campus_id.require' => ['common_validate.require', ['campus_id']],
'user_id.require' => ['common_validate.require', ['user_id']],
'paper_id.require' => ['common_validate.require', ['paper_id']],
'score.between' => ['common_validate.between', ['score','0','100']],
];
protected $scene = [

6
niucloud/app/validate/performance_records/PerformanceRecords.php

@ -22,6 +22,7 @@ class PerformanceRecords extends BaseValidate
protected $rule = [
'staff_id' => 'require',
'resource_id' => 'require',
'order_status' => 'require',
'performance_type' => 'require',
'performance_value' => 'require',
];
@ -29,13 +30,14 @@ class PerformanceRecords extends BaseValidate
protected $message = [
'staff_id.require' => ['common_validate.require', ['staff_id']],
'resource_id.require' => ['common_validate.require', ['resource_id']],
'order_status.require' => ['common_validate.require', ['order_status']],
'performance_type.require' => ['common_validate.require', ['performance_type']],
'performance_value.require' => ['common_validate.require', ['performance_value']],
];
protected $scene = [
"add" => ['staff_id', 'resource_id', 'order_id', 'order_status', 'performance_type', 'performance_value', 'remarks'],
"edit" => ['staff_id', 'resource_id', 'order_id', 'order_status', 'performance_type', 'performance_value', 'remarks']
"add" => ['staff_id', 'resource_id', 'order_status', 'performance_type', 'performance_value', 'remarks'],
"edit" => ['staff_id', 'resource_id', 'order_status', 'performance_type', 'performance_value', 'remarks']
];
}

43
niucloud/app/validate/student/Student.php

@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\validate\student;
use core\base\BaseValidate;
/**
* 学员验证器
* Class Student
* @package addon\app\validate\student
*/
class Student extends BaseValidate
{
protected $rule = [
'class_id' => 'require',
'user_id' => 'require',
'name' => 'require',
'gender' => 'require',
'status' => 'require',
];
protected $message = [
'class_id.require' => ['common_validate.require', ['class_id']],
'user_id.require' => ['common_validate.require', ['user_id']],
'name.require' => ['common_validate.require', ['name']],
'gender.require' => ['common_validate.require', ['gender']],
'status.require' => ['common_validate.require', ['status']],
];
protected $scene = [
"add" => ['campus_id', 'class_id', 'user_id', 'name', 'gender', 'age', 'birthday', 'emergency_contact', 'contact_phone', 'note', 'status'],
"edit" => ['campus_id', 'class_id', 'user_id', 'name', 'gender', 'age', 'birthday', 'emergency_contact', 'contact_phone', 'note', 'status']
];
}
Loading…
Cancel
Save