Browse Source

1

yuhongzhe
于宏哲PHP 11 months ago
parent
commit
036d89ff60
  1. 14
      admin/components.d.ts
  2. 56
      admin/src/app/api/attendance.ts
  3. 54
      admin/src/app/api/campus_person_role.ts
  4. 52
      admin/src/app/api/class.ts
  5. 52
      admin/src/app/api/communication_records.ts
  6. 52
      admin/src/app/api/contract.ts
  7. 52
      admin/src/app/api/course.ts
  8. 54
      admin/src/app/api/course_schedule.ts
  9. 52
      admin/src/app/api/customer_resource_changes.ts
  10. 52
      admin/src/app/api/customer_resources.ts
  11. 52
      admin/src/app/api/departments.ts
  12. 52
      admin/src/app/api/exam_answers.ts
  13. 52
      admin/src/app/api/exam_papers.ts
  14. 52
      admin/src/app/api/exam_questions.ts
  15. 52
      admin/src/app/api/exam_records.ts
  16. 52
      admin/src/app/api/order_table.ts
  17. 52
      admin/src/app/api/performance_records.ts
  18. 52
      admin/src/app/api/person_course_schedule.ts
  19. 54
      admin/src/app/api/physical_test.ts
  20. 52
      admin/src/app/api/reimbursement.ts
  21. 52
      admin/src/app/api/resource_sharing.ts
  22. 52
      admin/src/app/api/salary.ts
  23. 54
      admin/src/app/api/service.ts
  24. 52
      admin/src/app/api/six_speed.ts
  25. 52
      admin/src/app/api/six_speed_modification_log.ts
  26. 52
      admin/src/app/api/stat_hour.ts
  27. 52
      admin/src/app/api/student_course_usage.ts
  28. 52
      admin/src/app/api/student_courses.ts
  29. 52
      admin/src/app/api/user_feedback.ts
  30. 52
      admin/src/app/api/venue.ts
  31. 29
      admin/src/app/lang/zh-cn/attendance.attendance.json
  32. 23
      admin/src/app/lang/zh-cn/campus_person_role.campus_person_role.json
  33. 35
      admin/src/app/lang/zh-cn/class.class.json
  34. 31
      admin/src/app/lang/zh-cn/communication_records.communication_records.json
  35. 25
      admin/src/app/lang/zh-cn/contract.contract.json
  36. 27
      admin/src/app/lang/zh-cn/course.course.json
  37. 29
      admin/src/app/lang/zh-cn/course_schedule.course_schedule.json
  38. 21
      admin/src/app/lang/zh-cn/customer_resource_changes.customer_resource_changes.json
  39. 43
      admin/src/app/lang/zh-cn/customer_resources.customer_resources.json
  40. 13
      admin/src/app/lang/zh-cn/departments.departments.json
  41. 19
      admin/src/app/lang/zh-cn/exam_answers.exam_answers.json
  42. 15
      admin/src/app/lang/zh-cn/exam_papers.exam_papers.json
  43. 33
      admin/src/app/lang/zh-cn/exam_questions.exam_questions.json
  44. 29
      admin/src/app/lang/zh-cn/exam_questions.exam_questions_edit.json
  45. 23
      admin/src/app/lang/zh-cn/exam_records.exam_records.json
  46. 35
      admin/src/app/lang/zh-cn/order_table.order_table.json
  47. 23
      admin/src/app/lang/zh-cn/performance_records.performance_records.json
  48. 19
      admin/src/app/lang/zh-cn/person_course_schedule.person_course_schedule.json
  49. 43
      admin/src/app/lang/zh-cn/physical_test.physical_test.json
  50. 21
      admin/src/app/lang/zh-cn/reimbursement.reimbursement.json
  51. 19
      admin/src/app/lang/zh-cn/resource_sharing.resource_sharing.json
  52. 33
      admin/src/app/lang/zh-cn/salary.salary.json
  53. 29
      admin/src/app/lang/zh-cn/service.service.json
  54. 35
      admin/src/app/lang/zh-cn/six_speed.six_speed.json
  55. 19
      admin/src/app/lang/zh-cn/six_speed_modification_log.six_speed_modification_log.json
  56. 73
      admin/src/app/lang/zh-cn/stat_hour.stat_hour.json
  57. 15
      admin/src/app/lang/zh-cn/student_course_usage.student_course_usage.json
  58. 21
      admin/src/app/lang/zh-cn/student_courses.student_courses.json
  59. 15
      admin/src/app/lang/zh-cn/user_feedback.user_feedback.json
  60. 25
      admin/src/app/lang/zh-cn/venue.venue.json
  61. 213
      admin/src/app/views/attendance/attendance.vue
  62. 233
      admin/src/app/views/attendance/components/attendance-edit.vue
  63. 195
      admin/src/app/views/campus_person_role/campus_person_role.vue
  64. 203
      admin/src/app/views/campus_person_role/components/campus-person-role-edit.vue
  65. 231
      admin/src/app/views/class/class.vue
  66. 263
      admin/src/app/views/class/components/class-edit.vue
  67. 219
      admin/src/app/views/communication_records/communication_records.vue
  68. 243
      admin/src/app/views/communication_records/components/communication-records-edit.vue
  69. 213
      admin/src/app/views/contract/components/contract-edit.vue
  70. 201
      admin/src/app/views/contract/contract.vue
  71. 223
      admin/src/app/views/course/components/course-edit.vue
  72. 207
      admin/src/app/views/course/course.vue
  73. 233
      admin/src/app/views/course_schedule/components/course-schedule-edit.vue
  74. 213
      admin/src/app/views/course_schedule/course_schedule.vue
  75. 193
      admin/src/app/views/customer_resource_changes/components/customer-resource-changes-edit.vue
  76. 189
      admin/src/app/views/customer_resource_changes/customer_resource_changes.vue
  77. 303
      admin/src/app/views/customer_resources/components/customer-resources-edit.vue
  78. 255
      admin/src/app/views/customer_resources/customer_resources.vue
  79. 153
      admin/src/app/views/departments/components/departments-edit.vue
  80. 165
      admin/src/app/views/departments/departments.vue
  81. 183
      admin/src/app/views/exam_answers/components/exam-answers-edit.vue
  82. 183
      admin/src/app/views/exam_answers/exam_answers.vue
  83. 163
      admin/src/app/views/exam_papers/components/exam-papers-edit.vue
  84. 171
      admin/src/app/views/exam_papers/exam_papers.vue
  85. 223
      admin/src/app/views/exam_questions/exam_questions.vue
  86. 250
      admin/src/app/views/exam_questions/exam_questions_edit.vue
  87. 203
      admin/src/app/views/exam_records/components/exam-records-edit.vue
  88. 195
      admin/src/app/views/exam_records/exam_records.vue
  89. 263
      admin/src/app/views/order_table/components/order-table-edit.vue
  90. 231
      admin/src/app/views/order_table/order_table.vue
  91. 203
      admin/src/app/views/performance_records/components/performance-records-edit.vue
  92. 195
      admin/src/app/views/performance_records/performance_records.vue
  93. 183
      admin/src/app/views/person_course_schedule/components/person-course-schedule-edit.vue
  94. 183
      admin/src/app/views/person_course_schedule/person_course_schedule.vue
  95. 303
      admin/src/app/views/physical_test/components/physical-test-edit.vue
  96. 255
      admin/src/app/views/physical_test/physical_test.vue
  97. 193
      admin/src/app/views/reimbursement/components/reimbursement-edit.vue
  98. 189
      admin/src/app/views/reimbursement/reimbursement.vue
  99. 183
      admin/src/app/views/resource_sharing/components/resource-sharing-edit.vue
  100. 183
      admin/src/app/views/resource_sharing/resource_sharing.vue

14
admin/components.d.ts

@ -15,6 +15,7 @@ declare module '@vue/runtime-core' {
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
@ -32,18 +33,31 @@ declare module '@vue/runtime-core' {
ElImage: typeof import('element-plus/es')['ElImage'] ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMain: typeof import('element-plus/es')['ElMain'] ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default'] ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default'] HeatMap: typeof import('./src/components/heat-map/index.vue')['default']

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

@ -0,0 +1,56 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- attendance
/**
*
* @param params
* @returns
*/
export function getAttendanceList(params: Record<string, any>) {
return request.get(`attendance/attendance`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getAttendanceInfo(id: number) {
return request.get(`attendance/attendance/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addAttendance(params: Record<string, any>) {
return request.post('attendance/attendance', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editAttendance(params: Record<string, any>) {
return request.put(`attendance/attendance/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteAttendance(id: number) {
return request.delete(`attendance/attendance/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- attendance

54
admin/src/app/api/campus_person_role.ts

@ -0,0 +1,54 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- campus_person_role
/**
*
* @param params
* @returns
*/
export function getCampusPersonRoleList(params: Record<string, any>) {
return request.get(`campus_person_role/campus_person_role`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCampusPersonRoleInfo(id: number) {
return request.get(`campus_person_role/campus_person_role/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCampusPersonRole(params: Record<string, any>) {
return request.post('campus_person_role/campus_person_role', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCampusPersonRole(params: Record<string, any>) {
return request.put(`campus_person_role/campus_person_role/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCampusPersonRole(id: number) {
return request.delete(`campus_person_role/campus_person_role/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- campus_person_role

52
admin/src/app/api/class.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- class
/**
*
* @param params
* @returns
*/
export function getClassList(params: Record<string, any>) {
return request.get(`class/class`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getClassInfo(id: number) {
return request.get(`class/class/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addClass(params: Record<string, any>) {
return request.post('class/class', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editClass(params: Record<string, any>) {
return request.put(`class/class/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteClass(id: number) {
return request.delete(`class/class/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- class

52
admin/src/app/api/communication_records.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- communication_records
/**
*
* @param params
* @returns
*/
export function getCommunicationRecordsList(params: Record<string, any>) {
return request.get(`communication_records/communication_records`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCommunicationRecordsInfo(id: number) {
return request.get(`communication_records/communication_records/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCommunicationRecords(params: Record<string, any>) {
return request.post('communication_records/communication_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCommunicationRecords(params: Record<string, any>) {
return request.put(`communication_records/communication_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCommunicationRecords(id: number) {
return request.delete(`communication_records/communication_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- communication_records

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- contract
/**
*
* @param params
* @returns
*/
export function getContractList(params: Record<string, any>) {
return request.get(`contract/contract`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getContractInfo(id: number) {
return request.get(`contract/contract/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addContract(params: Record<string, any>) {
return request.post('contract/contract', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editContract(params: Record<string, any>) {
return request.put(`contract/contract/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteContract(id: number) {
return request.delete(`contract/contract/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- contract

52
admin/src/app/api/course.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- course
/**
*
* @param params
* @returns
*/
export function getCourseList(params: Record<string, any>) {
return request.get(`course/course`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCourseInfo(id: number) {
return request.get(`course/course/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCourse(params: Record<string, any>) {
return request.post('course/course', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCourse(params: Record<string, any>) {
return request.put(`course/course/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCourse(id: number) {
return request.delete(`course/course/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- course

54
admin/src/app/api/course_schedule.ts

@ -0,0 +1,54 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- course_schedule
/**
*
* @param params
* @returns
*/
export function getCourseScheduleList(params: Record<string, any>) {
return request.get(`course_schedule/course_schedule`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCourseScheduleInfo(id: number) {
return request.get(`course_schedule/course_schedule/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCourseSchedule(params: Record<string, any>) {
return request.post('course_schedule/course_schedule', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCourseSchedule(params: Record<string, any>) {
return request.put(`course_schedule/course_schedule/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCourseSchedule(id: number) {
return request.delete(`course_schedule/course_schedule/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- course_schedule

52
admin/src/app/api/customer_resource_changes.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- customer_resource_changes
/**
*
* @param params
* @returns
*/
export function getCustomerResourceChangesList(params: Record<string, any>) {
return request.get(`customer_resource_changes/customer_resource_changes`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCustomerResourceChangesInfo(id: number) {
return request.get(`customer_resource_changes/customer_resource_changes/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCustomerResourceChanges(params: Record<string, any>) {
return request.post('customer_resource_changes/customer_resource_changes', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCustomerResourceChanges(params: Record<string, any>) {
return request.put(`customer_resource_changes/customer_resource_changes/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCustomerResourceChanges(id: number) {
return request.delete(`customer_resource_changes/customer_resource_changes/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- customer_resource_changes

52
admin/src/app/api/customer_resources.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- customer_resources
/**
*
* @param params
* @returns
*/
export function getCustomerResourcesList(params: Record<string, any>) {
return request.get(`customer_resources/customer_resources`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCustomerResourcesInfo(id: number) {
return request.get(`customer_resources/customer_resources/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCustomerResources(params: Record<string, any>) {
return request.post('customer_resources/customer_resources', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCustomerResources(params: Record<string, any>) {
return request.put(`customer_resources/customer_resources/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCustomerResources(id: number) {
return request.delete(`customer_resources/customer_resources/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- customer_resources

52
admin/src/app/api/departments.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- departments
/**
*
* @param params
* @returns
*/
export function getDepartmentsList(params: Record<string, any>) {
return request.get(`departments/departments`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getDepartmentsInfo(id: number) {
return request.get(`departments/departments/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addDepartments(params: Record<string, any>) {
return request.post('departments/departments', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editDepartments(params: Record<string, any>) {
return request.put(`departments/departments/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteDepartments(id: number) {
return request.delete(`departments/departments/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- departments

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_answers
/**
*
* @param params
* @returns
*/
export function getExamAnswersList(params: Record<string, any>) {
return request.get(`exam_answers/exam_answers`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getExamAnswersInfo(id: number) {
return request.get(`exam_answers/exam_answers/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addExamAnswers(params: Record<string, any>) {
return request.post('exam_answers/exam_answers', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editExamAnswers(params: Record<string, any>) {
return request.put(`exam_answers/exam_answers/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteExamAnswers(id: number) {
return request.delete(`exam_answers/exam_answers/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_answers

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_papers
/**
*
* @param params
* @returns
*/
export function getExamPapersList(params: Record<string, any>) {
return request.get(`exam_papers/exam_papers`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getExamPapersInfo(id: number) {
return request.get(`exam_papers/exam_papers/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addExamPapers(params: Record<string, any>) {
return request.post('exam_papers/exam_papers', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editExamPapers(params: Record<string, any>) {
return request.put(`exam_papers/exam_papers/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteExamPapers(id: number) {
return request.delete(`exam_papers/exam_papers/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_papers

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_questions
/**
*
* @param params
* @returns
*/
export function getExamQuestionsList(params: Record<string, any>) {
return request.get(`exam_questions/exam_questions`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getExamQuestionsInfo(id: number) {
return request.get(`exam_questions/exam_questions/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addExamQuestions(params: Record<string, any>) {
return request.post('exam_questions/exam_questions', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editExamQuestions(params: Record<string, any>) {
return request.put(`exam_questions/exam_questions/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteExamQuestions(id: number) {
return request.delete(`exam_questions/exam_questions/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_questions

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- exam_records
/**
*
* @param params
* @returns
*/
export function getExamRecordsList(params: Record<string, any>) {
return request.get(`exam_records/exam_records`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getExamRecordsInfo(id: number) {
return request.get(`exam_records/exam_records/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addExamRecords(params: Record<string, any>) {
return request.post('exam_records/exam_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editExamRecords(params: Record<string, any>) {
return request.put(`exam_records/exam_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteExamRecords(id: number) {
return request.delete(`exam_records/exam_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- exam_records

52
admin/src/app/api/order_table.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- order_table
/**
*
* @param params
* @returns
*/
export function getOrderTableList(params: Record<string, any>) {
return request.get(`order_table/order_table`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getOrderTableInfo(id: number) {
return request.get(`order_table/order_table/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addOrderTable(params: Record<string, any>) {
return request.post('order_table/order_table', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editOrderTable(params: Record<string, any>) {
return request.put(`order_table/order_table/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteOrderTable(id: number) {
return request.delete(`order_table/order_table/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- order_table

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- performance_records
/**
*
* @param params
* @returns
*/
export function getPerformanceRecordsList(params: Record<string, any>) {
return request.get(`performance_records/performance_records`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getPerformanceRecordsInfo(id: number) {
return request.get(`performance_records/performance_records/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addPerformanceRecords(params: Record<string, any>) {
return request.post('performance_records/performance_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editPerformanceRecords(params: Record<string, any>) {
return request.put(`performance_records/performance_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deletePerformanceRecords(id: number) {
return request.delete(`performance_records/performance_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- performance_records

52
admin/src/app/api/person_course_schedule.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- person_course_schedule
/**
*
* @param params
* @returns
*/
export function getPersonCourseScheduleList(params: Record<string, any>) {
return request.get(`person_course_schedule/person_course_schedule`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getPersonCourseScheduleInfo(id: number) {
return request.get(`person_course_schedule/person_course_schedule/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addPersonCourseSchedule(params: Record<string, any>) {
return request.post('person_course_schedule/person_course_schedule', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editPersonCourseSchedule(params: Record<string, any>) {
return request.put(`person_course_schedule/person_course_schedule/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deletePersonCourseSchedule(id: number) {
return request.delete(`person_course_schedule/person_course_schedule/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- person_course_schedule

54
admin/src/app/api/physical_test.ts

@ -0,0 +1,54 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- physical_test
/**
*
* @param params
* @returns
*/
export function getPhysicalTestList(params: Record<string, any>) {
return request.get(`physical_test/physical_test`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getPhysicalTestInfo(id: number) {
return request.get(`physical_test/physical_test/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addPhysicalTest(params: Record<string, any>) {
return request.post('physical_test/physical_test', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editPhysicalTest(params: Record<string, any>) {
return request.put(`physical_test/physical_test/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deletePhysicalTest(id: number) {
return request.delete(`physical_test/physical_test/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- physical_test

52
admin/src/app/api/reimbursement.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- reimbursement
/**
*
* @param params
* @returns
*/
export function getReimbursementList(params: Record<string, any>) {
return request.get(`reimbursement/reimbursement`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getReimbursementInfo(id: number) {
return request.get(`reimbursement/reimbursement/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addReimbursement(params: Record<string, any>) {
return request.post('reimbursement/reimbursement', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editReimbursement(params: Record<string, any>) {
return request.put(`reimbursement/reimbursement/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteReimbursement(id: number) {
return request.delete(`reimbursement/reimbursement/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- reimbursement

52
admin/src/app/api/resource_sharing.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- resource_sharing
/**
*
* @param params
* @returns
*/
export function getResourceSharingList(params: Record<string, any>) {
return request.get(`resource_sharing/resource_sharing`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getResourceSharingInfo(id: number) {
return request.get(`resource_sharing/resource_sharing/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addResourceSharing(params: Record<string, any>) {
return request.post('resource_sharing/resource_sharing', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editResourceSharing(params: Record<string, any>) {
return request.put(`resource_sharing/resource_sharing/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteResourceSharing(id: number) {
return request.delete(`resource_sharing/resource_sharing/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- resource_sharing

52
admin/src/app/api/salary.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- salary
/**
*
* @param params
* @returns
*/
export function getSalaryList(params: Record<string, any>) {
return request.get(`salary/salary`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getSalaryInfo(id: number) {
return request.get(`salary/salary/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addSalary(params: Record<string, any>) {
return request.post('salary/salary', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editSalary(params: Record<string, any>) {
return request.put(`salary/salary/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteSalary(id: number) {
return request.delete(`salary/salary/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- salary

54
admin/src/app/api/service.ts

@ -0,0 +1,54 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- service
/**
*
* @param params
* @returns
*/
export function getServiceList(params: Record<string, any>) {
return request.get(`service/service`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getServiceInfo(id: number) {
return request.get(`service/service/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addService(params: Record<string, any>) {
return request.post('service/service', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editService(params: Record<string, any>) {
return request.put(`service/service/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteService(id: number) {
return request.delete(`service/service/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- service

52
admin/src/app/api/six_speed.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- six_speed
/**
*
* @param params
* @returns
*/
export function getSixSpeedList(params: Record<string, any>) {
return request.get(`six_speed/six_speed`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getSixSpeedInfo(id: number) {
return request.get(`six_speed/six_speed/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addSixSpeed(params: Record<string, any>) {
return request.post('six_speed/six_speed', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editSixSpeed(params: Record<string, any>) {
return request.put(`six_speed/six_speed/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteSixSpeed(id: number) {
return request.delete(`six_speed/six_speed/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- six_speed

52
admin/src/app/api/six_speed_modification_log.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- six_speed_modification_log
/**
*
* @param params
* @returns
*/
export function getSixSpeedModificationLogList(params: Record<string, any>) {
return request.get(`six_speed_modification_log/six_speed_modification_log`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getSixSpeedModificationLogInfo(id: number) {
return request.get(`six_speed_modification_log/six_speed_modification_log/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addSixSpeedModificationLog(params: Record<string, any>) {
return request.post('six_speed_modification_log/six_speed_modification_log', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editSixSpeedModificationLog(params: Record<string, any>) {
return request.put(`six_speed_modification_log/six_speed_modification_log/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteSixSpeedModificationLog(id: number) {
return request.delete(`six_speed_modification_log/six_speed_modification_log/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- six_speed_modification_log

52
admin/src/app/api/stat_hour.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- stat_hour
/**
*
* @param params
* @returns
*/
export function getStatHourList(params: Record<string, any>) {
return request.get(`stat_hour/stat_hour`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getStatHourInfo(id: number) {
return request.get(`stat_hour/stat_hour/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addStatHour(params: Record<string, any>) {
return request.post('stat_hour/stat_hour', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editStatHour(params: Record<string, any>) {
return request.put(`stat_hour/stat_hour/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteStatHour(id: number) {
return request.delete(`stat_hour/stat_hour/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- stat_hour

52
admin/src/app/api/student_course_usage.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- student_course_usage
/**
*
* @param params
* @returns
*/
export function getStudentCourseUsageList(params: Record<string, any>) {
return request.get(`student_course_usage/student_course_usage`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getStudentCourseUsageInfo(id: number) {
return request.get(`student_course_usage/student_course_usage/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addStudentCourseUsage(params: Record<string, any>) {
return request.post('student_course_usage/student_course_usage', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editStudentCourseUsage(params: Record<string, any>) {
return request.put(`student_course_usage/student_course_usage/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteStudentCourseUsage(id: number) {
return request.delete(`student_course_usage/student_course_usage/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- student_course_usage

52
admin/src/app/api/student_courses.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- student_courses
/**
*
* @param params
* @returns
*/
export function getStudentCoursesList(params: Record<string, any>) {
return request.get(`student_courses/student_courses`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getStudentCoursesInfo(id: number) {
return request.get(`student_courses/student_courses/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addStudentCourses(params: Record<string, any>) {
return request.post('student_courses/student_courses', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editStudentCourses(params: Record<string, any>) {
return request.put(`student_courses/student_courses/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteStudentCourses(id: number) {
return request.delete(`student_courses/student_courses/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- student_courses

52
admin/src/app/api/user_feedback.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- user_feedback
/**
*
* @param params
* @returns
*/
export function getUserFeedbackList(params: Record<string, any>) {
return request.get(`user_feedback/user_feedback`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getUserFeedbackInfo(id: number) {
return request.get(`user_feedback/user_feedback/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addUserFeedback(params: Record<string, any>) {
return request.post('user_feedback/user_feedback', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editUserFeedback(params: Record<string, any>) {
return request.put(`user_feedback/user_feedback/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteUserFeedback(id: number) {
return request.delete(`user_feedback/user_feedback/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- user_feedback

52
admin/src/app/api/venue.ts

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- venue
/**
*
* @param params
* @returns
*/
export function getVenueList(params: Record<string, any>) {
return request.get(`venue/venue`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getVenueInfo(id: number) {
return request.get(`venue/venue/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addVenue(params: Record<string, any>) {
return request.post('venue/venue', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editVenue(params: Record<string, any>) {
return request.put(`venue/venue/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteVenue(id: number) {
return request.delete(`venue/venue/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- venue

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

@ -0,0 +1,29 @@
{
"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":"请选择结束时间"
}

23
admin/src/app/lang/zh-cn/campus_person_role.campus_person_role.json

@ -0,0 +1,23 @@
{
"id":"关系编号",
"idPlaceholder":"请输入关系编号",
"campusId":"校区ID",
"campusIdPlaceholder":"请输入校区ID",
"personId":"人员ID",
"personIdPlaceholder":"请输入人员ID",
"roleId":"角色ID",
"roleIdPlaceholder":"请输入角色ID",
"deptId":"部门表",
"deptIdPlaceholder":"请输入部门表",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"更新时间",
"updatedAtPlaceholder":"请输入更新时间",
"deletedAt":"逻辑删除时间",
"deletedAtPlaceholder":"请输入逻辑删除时间",
"addCampusPersonRole":"添加角色关系",
"updateCampusPersonRole":"编辑角色关系",
"campusPersonRoleDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

35
admin/src/app/lang/zh-cn/class.class.json

@ -0,0 +1,35 @@
{
"id":"班级编号",
"idPlaceholder":"请输入班级编号",
"campusId":"校区ID",
"campusIdPlaceholder":"请输入校区ID",
"campusName":"校区名称",
"campusNamePlaceholder":"请输入校区名称",
"className":"班级名称",
"classNamePlaceholder":"请输入班级名称",
"headCoach":"班级主教练",
"headCoachPlaceholder":"请输入班级主教练",
"ageGroup":"班级授课年龄段",
"ageGroupPlaceholder":"请输入班级授课年龄段",
"classType":"班级类型",
"classTypePlaceholder":"请输入班级类型",
"assistantCoach":"班级助教",
"assistantCoachPlaceholder":"请输入班级助教",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"updatedAtPlaceholder":"请输入修改时间",
"deletedAt":"逻辑删除时间",
"deletedAtPlaceholder":"请输入逻辑删除时间",
"status":"班级状态",
"statusPlaceholder":"请输入班级状态",
"sortOrder":"班级排序",
"sortOrderPlaceholder":"请输入班级排序",
"remarks":"班级备注",
"remarksPlaceholder":"请输入班级备注",
"addClass":"添加班级",
"updateClass":"编辑班级",
"classDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

@ -0,0 +1,31 @@
{
"id":"沟通记录编号",
"idPlaceholder":"请输入沟通记录编号",
"staffId":"员工ID",
"staffIdPlaceholder":"请输入员工ID",
"resourceId":"资源ID",
"resourceIdPlaceholder":"请输入资源ID",
"resourceType":"资源类型(如设备、文件、系统等)",
"resourceTypePlaceholder":"请输入资源类型(如设备、文件、系统等)",
"communicationType":"沟通类型: phone-电话, email-邮件, meeting-会议, other-其他",
"communicationTypePlaceholder":"请输入沟通类型: phone-电话, email-邮件, meeting-会议, other-其他",
"communicationResult":"沟通结果: success-成功, failure-失败, pending-待定",
"communicationResultPlaceholder":"请输入沟通结果: success-成功, failure-失败, pending-待定",
"communicationTime":"沟通时间",
"communicationTimePlaceholder":"请输入沟通时间",
"remarks":"备注",
"remarksPlaceholder":"请输入备注",
"tag":"标签: high-高, medium-中, low-低",
"tagPlaceholder":"请输入标签: high-高, medium-中, low-低",
"businessId":"关联的业务ID",
"businessIdPlaceholder":"请输入关联的业务ID",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"updatedAtPlaceholder":"请输入修改时间",
"addCommunicationRecords":"添加沟通记录",
"updateCommunicationRecords":"编辑沟通记录",
"communicationRecordsDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

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

27
admin/src/app/lang/zh-cn/course.course.json

@ -0,0 +1,27 @@
{
"id":"课程编号",
"idPlaceholder":"请输入课程编号",
"courseName":"课程名称",
"courseNamePlaceholder":"请输入课程名称",
"courseType":"课程类型",
"courseTypePlaceholder":"请输入课程类型",
"duration":"课程时长",
"durationPlaceholder":"请输入课程时长",
"sessionCount":"课时数量",
"sessionCountPlaceholder":"请输入课时数量",
"singleSessionCount":"单次逍客数量",
"singleSessionCountPlaceholder":"请输入单次逍客数量",
"price":"课程价格",
"pricePlaceholder":"请输入课程价格",
"internalReminder":"内部提醒课时",
"internalReminderPlaceholder":"请输入内部提醒课时",
"customerReminder":"客户提醒课时",
"customerReminderPlaceholder":"请输入客户提醒课时",
"remarks":"课程备注",
"remarksPlaceholder":"请输入课程备注",
"addCourse":"添加课程",
"updateCourse":"编辑课程",
"courseDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

29
admin/src/app/lang/zh-cn/course_schedule.course_schedule.json

@ -0,0 +1,29 @@
{
"id":"课程安排编号",
"idPlaceholder":"请输入课程安排编号",
"campusId":"校区ID",
"campusIdPlaceholder":"请输入校区ID",
"venueId":"场地ID",
"venueIdPlaceholder":"请输入场地ID",
"courseDate":"上课日期",
"courseDatePlaceholder":"请输入上课日期",
"timeSlot":"上课时段",
"timeSlotPlaceholder":"请输入上课时段",
"courseId":"课程ID",
"courseIdPlaceholder":"请输入课程ID",
"coachId":"上课教练ID",
"coachIdPlaceholder":"请输入上课教练ID",
"participants":"参与人员列表",
"participantsPlaceholder":"请输入参与人员列表",
"studentIds":"上课学生列表",
"studentIdsPlaceholder":"请输入上课学生列表",
"availableCapacity":"根据场地容量判断的可安排学员位置数量",
"availableCapacityPlaceholder":"请输入根据场地容量判断的可安排学员位置数量",
"status":"课程状态:",
"statusPlaceholder":"请输入课程状态:",
"addCourseSchedule":"添加课程安排",
"updateCourseSchedule":"编辑课程安排",
"courseScheduleDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

21
admin/src/app/lang/zh-cn/customer_resource_changes.customer_resource_changes.json

@ -0,0 +1,21 @@
{
"id":"修改编号",
"idPlaceholder":"请输入修改编号",
"customerResourceId":"客户资源的ID",
"customerResourceIdPlaceholder":"请输入客户资源的ID",
"operatorId":"操作人的ID",
"operatorIdPlaceholder":"请输入操作人的ID",
"campusId":"操作校区的ID",
"campusIdPlaceholder":"请输入操作校区的ID",
"modifiedFields":"修改的哪些字段",
"modifiedFieldsPlaceholder":"请输入修改的哪些字段",
"oldValues":"修改前的值",
"oldValuesPlaceholder":"请输入修改前的值",
"newValues":"修改后的值",
"newValuesPlaceholder":"请输入修改后的值",
"addCustomerResourceChanges":"添加客户资源表变更记录",
"updateCustomerResourceChanges":"编辑客户资源表变更记录",
"customerResourceChangesDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

43
admin/src/app/lang/zh-cn/customer_resources.customer_resources.json

@ -0,0 +1,43 @@
{
"id":"编号",
"idPlaceholder":"请输入编号",
"createYearMonth":"创建年月",
"createYearMonthPlaceholder":"请输入创建年月",
"createDate":"创建日期",
"createDatePlaceholder":"请输入创建日期",
"sourceChannel":"来源渠道",
"sourceChannelPlaceholder":"请输入来源渠道",
"source":"来源",
"sourcePlaceholder":"请输入来源",
"consultant":"顾问",
"consultantPlaceholder":"请输入顾问",
"name":"姓名",
"namePlaceholder":"请输入姓名",
"age":"年龄",
"agePlaceholder":"请输入年龄",
"gender":"性别: male-男性, female-女性, other-其他",
"genderPlaceholder":"请输入性别: male-男性, female-女性, other-其他",
"phoneNumber":"联系电话",
"phoneNumberPlaceholder":"请输入联系电话",
"demand":"需求",
"demandPlaceholder":"请输入需求",
"purchasingPower":"购买力",
"purchasingPowerPlaceholder":"请输入购买力",
"cognitiveIdea":"认知理念",
"cognitiveIdeaPlaceholder":"请输入认知理念",
"optionalClassTime":"可选上课时间",
"optionalClassTimePlaceholder":"请输入可选上课时间",
"distance":"距离",
"distancePlaceholder":"请输入距离",
"decisionMaker":"决策人",
"decisionMakerPlaceholder":"请输入决策人",
"initialIntent":"客户初步意向度: high-高, medium-中, low-低",
"initialIntentPlaceholder":"请输入客户初步意向度: high-高, medium-中, low-低",
"campus":"所属校区",
"campusPlaceholder":"请输入所属校区",
"addCustomerResources":"添加客户资源",
"updateCustomerResources":"编辑客户资源",
"customerResourcesDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

13
admin/src/app/lang/zh-cn/departments.departments.json

@ -0,0 +1,13 @@
{
"id":"部门编号",
"idPlaceholder":"请输入部门编号",
"departmentName":"部门名称",
"departmentNamePlaceholder":"请输入部门名称",
"parentDepartmentId":"上级部门",
"parentDepartmentIdPlaceholder":"请输入上级部门",
"addDepartments":"添加部门",
"updateDepartments":"编辑部门",
"departmentsDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

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

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

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

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

@ -0,0 +1,33 @@
{
"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":"请选择结束时间"
}

29
admin/src/app/lang/zh-cn/exam_questions.exam_questions_edit.json

@ -0,0 +1,29 @@
{
"questionType":"题型: single_choice-单选, multiple_choice-多选, true_false-判断",
"questionContentType":"题干类型: text-文本, image-图片",
"questionContent":"题干内容(如果是图片则存储URL)",
"optionAContentType":"选项A类型: text-文本, image-图片",
"optionAContent":"选项A内容(如果是图片则存储URL)",
"optionBContentType":"选项B类型: text-文本, image-图片",
"optionBContent":"选项B内容(如果是图片则存储URL)",
"optionCContentType":"选项C类型: text-文本, image-图片",
"optionCContent":"选项C内容(如果是图片则存储URL)",
"optionDContentType":"选项D类型: text-文本, image-图片",
"optionDContent":"选项D内容(如果是图片则存储URL)",
"correctAnswer":"正确答案(如果是多选,答案格式为如"A,B,D")",
"questionTypePlaceholder":"请输入题型: single_choice-单选, multiple_choice-多选, true_false-判断",
"questionContentTypePlaceholder":"请输入题干类型: text-文本, image-图片",
"questionContentPlaceholder":"请输入题干内容(如果是图片则存储URL)",
"optionAContentTypePlaceholder":"请输入选项A类型: text-文本, image-图片",
"optionAContentPlaceholder":"请输入选项A内容(如果是图片则存储URL)",
"optionBContentTypePlaceholder":"请输入选项B类型: text-文本, image-图片",
"optionBContentPlaceholder":"请输入选项B内容(如果是图片则存储URL)",
"optionCContentTypePlaceholder":"请输入选项C类型: text-文本, image-图片",
"optionCContentPlaceholder":"请输入选项C内容(如果是图片则存储URL)",
"optionDContentTypePlaceholder":"请输入选项D类型: text-文本, image-图片",
"optionDContentPlaceholder":"请输入选项D内容(如果是图片则存储URL)",
"correctAnswerPlaceholder":"请输入正确答案(如果是多选,答案格式为如"A,B,D")",
"addExamQuestions":"添加试题",
"updateExamQuestions":"编辑试题",
"examQuestionsDeleteTips":"确定要删除该试题吗?"
}

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

@ -0,0 +1,23 @@
{
"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":"请选择结束时间"
}

35
admin/src/app/lang/zh-cn/order_table.order_table.json

@ -0,0 +1,35 @@
{
"id":"订单编号",
"idPlaceholder":"请输入订单编号",
"paymentId":"支付编号",
"paymentIdPlaceholder":"请输入支付编号",
"orderStatus":"订单状态: pending-待支付, paid-已支付",
"orderStatusPlaceholder":"请输入订单状态: pending-待支付, paid-已支付",
"paymentType":"付款类型: cash-现金支付, scan_code-扫码支付, subscription-订阅支付",
"paymentTypePlaceholder":"请输入付款类型: cash-现金支付, scan_code-扫码支付, subscription-订阅支付",
"orderAmount":"订单金额",
"orderAmountPlaceholder":"请输入订单金额",
"courseId":"课程ID",
"courseIdPlaceholder":"请输入课程ID",
"classId":"班级ID",
"classIdPlaceholder":"请输入班级ID",
"staffId":"人员ID",
"staffIdPlaceholder":"请输入人员ID",
"resourceId":"资源ID",
"resourceIdPlaceholder":"请输入资源ID",
"afterSalesStatus":"售后状态",
"afterSalesStatusPlaceholder":"请输入售后状态",
"afterSalesReason":"售后原因",
"afterSalesReasonPlaceholder":"请输入售后原因",
"afterSalesTime":"售后时间",
"afterSalesTimePlaceholder":"请输入售后时间",
"paymentTime":"支付时间",
"paymentTimePlaceholder":"请输入支付时间",
"subscriptionPaymentTime":"订阅支付生成时间",
"subscriptionPaymentTimePlaceholder":"请输入订阅支付生成时间",
"addOrderTable":"添加订单",
"updateOrderTable":"编辑订单",
"orderTableDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

@ -0,0 +1,23 @@
{
"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":"请选择结束时间"
}

19
admin/src/app/lang/zh-cn/person_course_schedule.person_course_schedule.json

@ -0,0 +1,19 @@
{
"id":"关系编号",
"idPlaceholder":"请输入关系编号",
"personId":"人员或资源ID",
"personIdPlaceholder":"请输入人员或资源ID",
"personType":"人员类型: student-正式学员, customer_resource-客户资源",
"personTypePlaceholder":"请输入人员类型: student-正式学员, customer_resource-客户资源",
"scheduleId":"课程安排ID",
"scheduleIdPlaceholder":"请输入课程安排ID",
"courseDate":"上课日期",
"courseDatePlaceholder":"请输入上课日期",
"timeSlot":"上课时段",
"timeSlotPlaceholder":"请输入上课时段",
"addPersonCourseSchedule":"添加人员与课程安排关系",
"updatePersonCourseSchedule":"编辑人员与课程安排关系",
"personCourseScheduleDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

43
admin/src/app/lang/zh-cn/physical_test.physical_test.json

@ -0,0 +1,43 @@
{
"id":"体测编号",
"idPlaceholder":"请输入体测编号",
"resourceId":"资源ID",
"resourceIdPlaceholder":"请输入资源ID",
"studentId":"学员ID",
"studentIdPlaceholder":"请输入学员ID",
"height":"身高",
"heightPlaceholder":"请输入身高",
"weight":"体重",
"weightPlaceholder":"请输入体重",
"coachId":"教练ID",
"coachIdPlaceholder":"请输入教练ID",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"updatedAtPlaceholder":"请输入修改时间",
"seatedForwardBend":"坐位体前屈",
"seatedForwardBendPlaceholder":"请输入坐位体前屈",
"sitUps":"仰卧卷腹",
"sitUpsPlaceholder":"请输入仰卧卷腹",
"pushUps":"九十度仰卧撑",
"pushUpsPlaceholder":"请输入九十度仰卧撑",
"flamingoBalance":"火烈鸟平衡测试",
"flamingoBalancePlaceholder":"请输入火烈鸟平衡测试",
"thirtySecJump":"三十秒双脚连续跳",
"thirtySecJumpPlaceholder":"请输入三十秒双脚连续跳",
"standingLongJump":"立定跳远",
"standingLongJumpPlaceholder":"请输入立定跳远",
"agilityRun":"4乘10m灵敏折返跑",
"agilityRunPlaceholder":"请输入4乘10m灵敏折返跑",
"balanceBeam":"走平衡木",
"balanceBeamPlaceholder":"请输入走平衡木",
"tennisThrow":"网球掷远",
"tennisThrowPlaceholder":"请输入网球掷远",
"tenMeterShuttleRun":"十米往返跑",
"tenMeterShuttleRunPlaceholder":"请输入十米往返跑",
"addPhysicalTest":"添加体测",
"updatePhysicalTest":"编辑体测",
"physicalTestDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

21
admin/src/app/lang/zh-cn/reimbursement.reimbursement.json

@ -0,0 +1,21 @@
{
"id":"报销编号",
"idPlaceholder":"请输入报销编号",
"applicantId":"申请人ID",
"applicantIdPlaceholder":"请输入申请人ID",
"amount":"报销金额",
"amountPlaceholder":"请输入报销金额",
"description":"报销描述",
"descriptionPlaceholder":"请输入报销描述",
"receiptUrl":"发票或收据URL",
"receiptUrlPlaceholder":"请输入发票或收据URL",
"status":"状态",
"statusPlaceholder":"请输入状态",
"processId":"关联的审批流程ID",
"processIdPlaceholder":"请输入关联的审批流程ID",
"addReimbursement":"添加报销记录",
"updateReimbursement":"编辑报销记录",
"reimbursementDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

19
admin/src/app/lang/zh-cn/resource_sharing.resource_sharing.json

@ -0,0 +1,19 @@
{
"id":"共享记录编号",
"idPlaceholder":"请输入共享记录编号",
"resourceId":"资源ID",
"resourceIdPlaceholder":"请输入资源ID",
"userId":"用户ID(可为空)",
"userIdPlaceholder":"请输入用户ID(可为空)",
"roleId":"角色ID(可为空)",
"roleIdPlaceholder":"请输入角色ID(可为空)",
"sharedBy":"共享人ID",
"sharedByPlaceholder":"请输入共享人ID",
"sharedAt":"共享时间",
"sharedAtPlaceholder":"请输入共享时间",
"addResourceSharing":"添加资源共享",
"updateResourceSharing":"编辑资源共享",
"resourceSharingDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

@ -0,0 +1,33 @@
{
"id":"工资编号",
"idPlaceholder":"请输入工资编号",
"staffId":"员工ID",
"staffIdPlaceholder":"请输入员工ID",
"baseSalary":"底薪",
"baseSalaryPlaceholder":"请输入底薪",
"performanceBonus":"绩效",
"performanceBonusPlaceholder":"请输入绩效",
"deductions":"扣款",
"deductionsPlaceholder":"请输入扣款",
"otherSubsidies":"其他补贴",
"otherSubsidiesPlaceholder":"请输入其他补贴",
"netSalary":"实发工资",
"netSalaryPlaceholder":"请输入实发工资",
"paymentStatus":"发放状态",
"paymentStatusPlaceholder":"请输入发放状态",
"paymentMethod":"发放方式",
"paymentMethodPlaceholder":"请输入发放方式",
"remarks":"备注",
"remarksPlaceholder":"请输入备注",
"salaryMonth":"工资月份",
"salaryMonthPlaceholder":"请输入工资月份",
"departmentId":"部门ID",
"departmentIdPlaceholder":"请输入部门ID",
"processId":"关联的审批流程ID",
"processIdPlaceholder":"请输入关联的审批流程ID",
"addSalary":"添加工资",
"updateSalary":"编辑工资",
"salaryDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

29
admin/src/app/lang/zh-cn/service.service.json

@ -0,0 +1,29 @@
{
"id":"服务编号",
"idPlaceholder":"请输入服务编号",
"serviceName":"服务名称",
"serviceNamePlaceholder":"请输入服务名称",
"previewImageUrl":"服务预览图URL",
"previewImageUrlPlaceholder":"请输入服务预览图URL",
"description":"服务描述",
"descriptionPlaceholder":"请输入服务描述",
"serviceType":"服务类型",
"serviceTypePlaceholder":"请输入服务类型",
"executionRules":"服务执行规则",
"executionRulesPlaceholder":"请输入服务执行规则",
"staffReminder":"是否员工提醒: 1-是, 0-否",
"staffReminderPlaceholder":"请输入是否员工提醒: 1-是, 0-否",
"customerReminder":"是否客户提醒: 1-是, 0-否",
"customerReminderPlaceholder":"请输入是否客户提醒: 1-是, 0-否",
"customerConfirmation":"是否客户确认: 1-是, 0-否",
"customerConfirmationPlaceholder":"请输入是否客户确认: 1-是, 0-否",
"customerFeedback":"客户反馈内容",
"customerFeedbackPlaceholder":"请输入客户反馈内容",
"status":"状态",
"statusPlaceholder":"请输入状态",
"addService":"添加服务",
"updateService":"编辑服务",
"serviceDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

35
admin/src/app/lang/zh-cn/six_speed.six_speed.json

@ -0,0 +1,35 @@
{
"id":"编号",
"idPlaceholder":"请输入编号",
"purchasePower":"需求购买力",
"purchasePowerPlaceholder":"请输入需求购买力",
"conceptAwareness":"认知理念",
"conceptAwarenessPlaceholder":"请输入认知理念",
"preferredClassTime":"可选上课时间",
"preferredClassTimePlaceholder":"请输入可选上课时间",
"distance":"距离",
"distancePlaceholder":"请输入距离",
"communication":"沟通备注",
"communicationPlaceholder":"请输入沟通备注",
"promisedVisitTime":"承诺到访时间",
"promisedVisitTimePlaceholder":"请输入承诺到访时间",
"actualVisitTime":"实际到访时间",
"actualVisitTimePlaceholder":"请输入实际到访时间",
"callIntent":"电话后的意向程度: low-低, medium-中, high-高",
"callIntentPlaceholder":"请输入电话后的意向程度: low-低, medium-中, high-高",
"firstVisitStatus":"一访情况",
"firstVisitStatusPlaceholder":"请输入一访情况",
"secondVisitStatus":"二访情况",
"secondVisitStatusPlaceholder":"请输入二访情况",
"isClosed":"是否关单: 1-是, 0-否",
"isClosedPlaceholder":"请输入是否关单: 1-是, 0-否",
"staffId":"人员ID",
"staffIdPlaceholder":"请输入人员ID",
"resourceId":"资源ID",
"resourceIdPlaceholder":"请输入资源ID",
"addSixSpeed":"添加六一速",
"updateSixSpeed":"编辑六一速",
"sixSpeedDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

19
admin/src/app/lang/zh-cn/six_speed_modification_log.six_speed_modification_log.json

@ -0,0 +1,19 @@
{
"id":"编号",
"idPlaceholder":"请输入编号",
"campusId":"校区ID",
"campusIdPlaceholder":"请输入校区ID",
"staffId":"人员ID",
"staffIdPlaceholder":"请输入人员ID",
"modifiedField":"修改的字段",
"modifiedFieldPlaceholder":"请输入修改的字段",
"oldValue":"修改前的值",
"oldValuePlaceholder":"请输入修改前的值",
"newValue":"修改后的值",
"newValuePlaceholder":"请输入修改后的值",
"addSixSpeedModificationLog":"添加六一速修改记录",
"updateSixSpeedModificationLog":"编辑六一速修改记录",
"sixSpeedModificationLogDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

73
admin/src/app/lang/zh-cn/stat_hour.stat_hour.json

@ -0,0 +1,73 @@
{
"id":"",
"idPlaceholder":"请输入",
"addon":"插件",
"addonPlaceholder":"请输入插件",
"field":"统计字段",
"fieldPlaceholder":"请输入统计字段",
"fieldTotal":"总计",
"fieldTotalPlaceholder":"请输入总计",
"year":"年",
"yearPlaceholder":"请输入年",
"month":"月",
"monthPlaceholder":"请输入月",
"day":"天",
"dayPlaceholder":"请输入天",
"startTime":"当日开始时间戳",
"startTimePlaceholder":"请输入当日开始时间戳",
"lastTime":"最后执行时间",
"lastTimePlaceholder":"请输入最后执行时间",
"hour0":"",
"hour0Placeholder":"请输入",
"hour1":"",
"hour1Placeholder":"请输入",
"hour2":"",
"hour2Placeholder":"请输入",
"hour3":"",
"hour3Placeholder":"请输入",
"hour4":"",
"hour4Placeholder":"请输入",
"hour5":"",
"hour5Placeholder":"请输入",
"hour6":"",
"hour6Placeholder":"请输入",
"hour7":"",
"hour7Placeholder":"请输入",
"hour8":"",
"hour8Placeholder":"请输入",
"hour9":"",
"hour9Placeholder":"请输入",
"hour10":"",
"hour10Placeholder":"请输入",
"hour11":"",
"hour11Placeholder":"请输入",
"hour12":"",
"hour12Placeholder":"请输入",
"hour13":"",
"hour13Placeholder":"请输入",
"hour14":"",
"hour14Placeholder":"请输入",
"hour15":"",
"hour15Placeholder":"请输入",
"hour16":"",
"hour16Placeholder":"请输入",
"hour17":"",
"hour17Placeholder":"请输入",
"hour18":"",
"hour18Placeholder":"请输入",
"hour19":"",
"hour19Placeholder":"请输入",
"hour20":"",
"hour20Placeholder":"请输入",
"hour21":"",
"hour21Placeholder":"请输入",
"hour22":"",
"hour22Placeholder":"请输入",
"hour23":"",
"hour23Placeholder":"请输入",
"addStatHour":"添加小时统计",
"updateStatHour":"编辑小时统计",
"statHourDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

15
admin/src/app/lang/zh-cn/student_course_usage.student_course_usage.json

@ -0,0 +1,15 @@
{
"id":"记录编号",
"idPlaceholder":"请输入记录编号",
"studentCourseId":"学员课程ID(关联到student_courses表)",
"studentCourseIdPlaceholder":"请输入学员课程ID(关联到student_courses表)",
"usedHours":"本次使用的课时数",
"usedHoursPlaceholder":"请输入本次使用的课时数",
"usageDate":"课时使用日期",
"usageDatePlaceholder":"请输入课时使用日期",
"addStudentCourseUsage":"添加学员课时消费记录",
"updateStudentCourseUsage":"编辑学员课时消费记录",
"studentCourseUsageDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

21
admin/src/app/lang/zh-cn/student_courses.student_courses.json

@ -0,0 +1,21 @@
{
"id":"记录编号",
"idPlaceholder":"请输入记录编号",
"studentId":"学员ID",
"studentIdPlaceholder":"请输入学员ID",
"courseId":"课程ID",
"courseIdPlaceholder":"请输入课程ID",
"totalHours":"总正式课时数",
"totalHoursPlaceholder":"请输入总正式课时数",
"giftHours":"赠送课时数",
"giftHoursPlaceholder":"请输入赠送课时数",
"startDate":"课程开始日期",
"startDatePlaceholder":"请输入课程开始日期",
"endDate":"课程结束日期",
"endDatePlaceholder":"请输入课程结束日期",
"addStudentCourses":"添加学员课程",
"updateStudentCourses":"编辑学员课程",
"studentCoursesDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

15
admin/src/app/lang/zh-cn/user_feedback.user_feedback.json

@ -0,0 +1,15 @@
{
"id":"反馈编号",
"idPlaceholder":"请输入反馈编号",
"userId":"用户ID",
"userIdPlaceholder":"请输入用户ID",
"feedbackText":"反馈内容",
"feedbackTextPlaceholder":"请输入反馈内容",
"attachmentUrl":"附件URL(OSS对象存储)",
"attachmentUrlPlaceholder":"请输入附件URL(OSS对象存储)",
"addUserFeedback":"添加用户反馈信息",
"updateUserFeedback":"编辑用户反馈信息",
"userFeedbackDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

25
admin/src/app/lang/zh-cn/venue.venue.json

@ -0,0 +1,25 @@
{
"id":"场地编号",
"idPlaceholder":"请输入场地编号",
"campusId":"校区ID",
"campusIdPlaceholder":"请输入校区ID",
"venueName":"场地名称",
"venueNamePlaceholder":"请输入场地名称",
"capacity":"场地可容纳人数上限",
"capacityPlaceholder":"请输入场地可容纳人数上限",
"availabilityStatus":"场地可用状态",
"availabilityStatusPlaceholder":"请输入场地可用状态",
"timeRangeType":"场地可用时间范围类型",
"timeRangeTypePlaceholder":"请输入场地可用时间范围类型",
"timeRangeStart":"范围类型的开始时间",
"timeRangeStartPlaceholder":"请输入范围类型的开始时间",
"timeRangeEnd":"范围类型的结束时间",
"timeRangeEndPlaceholder":"请输入范围类型的结束时间",
"fixedTimeRanges":"固定时间范围类型的可用时间, 存储为JSON数组",
"fixedTimeRangesPlaceholder":"请输入固定时间范围类型的可用时间, 存储为JSON数组",
"addVenue":"添加场地",
"updateVenue":"编辑场地",
"venueDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

@ -0,0 +1,213 @@
<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('addAttendance') }}
</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-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="attendanceTable.searchParam.campus_id" :placeholder="t('campusIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input v-model="attendanceTable.searchParam.staff_id" :placeholder="t('staffIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('attendanceDate')" prop="attendance_date">
<el-input 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')" />
</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-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-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<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="staff_id" :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="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="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="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">
<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" />
</div>
</div>
<edit ref="editAttendanceDialog" @complete="loadAttendanceList" />
</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 { getAttendanceList, deleteAttendance } from '@/app/api/attendance'
import { img } from '@/utils/common'
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;
let attendanceTable = reactive({
page: 1,
limit: 10,
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":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取考勤列表
*/
const loadAttendanceList = (page: number = 1) => {
attendanceTable.loading = true
attendanceTable.page = page
getAttendanceList({
page: attendanceTable.page,
limit: attendanceTable.limit,
...attendanceTable.searchParam
}).then(res => {
attendanceTable.loading = false
attendanceTable.data = res.data.data
attendanceTable.total = res.data.total
}).catch(() => {
attendanceTable.loading = false
})
}
loadAttendanceList()
const editAttendanceDialog: Record<string, any> | null = ref(null)
/**
* 添加考勤
*/
const addEvent = () => {
editAttendanceDialog.value.setFormData()
editAttendanceDialog.value.showDialog = true
}
/**
* 编辑考勤
* @param data
*/
const editEvent = (data: any) => {
editAttendanceDialog.value.setFormData(data)
editAttendanceDialog.value.showDialog = true
}
/**
* 删除考勤
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('attendanceDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteAttendance(id).then(() => {
loadAttendanceList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadAttendanceList()
}
</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>

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

@ -0,0 +1,233 @@
<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-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')" class="input-width" />
</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-form-item>
<el-form-item :label="t('attendanceDate')" prop="attendance_date">
<el-input v-model="formData.attendance_date" clearable :placeholder="t('attendanceDatePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('checkInTime')" >
<el-input v-model="formData.check_in_time" clearable :placeholder="t('checkInTimePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('checkOutTime')" >
<el-input v-model="formData.check_out_time" clearable :placeholder="t('checkOutTimePlaceholder')" class="input-width" />
</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>
<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>
<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>
</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 { addAttendance, editAttendance, getAttendanceInfo } from '@/app/api/attendance'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
staff_id: '',
attendance_date: '',
check_in_time: '',
check_out_time: '',
status: '',
remarks: '',
created_at: '',
updated_at: '',
coordinate: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
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' },
]
,
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' },
]
,
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' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editAttendance : addAttendance
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getAttendanceInfo(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>

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

@ -0,0 +1,195 @@
<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('addCampusPersonRole') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="campusPersonRoleTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="campusPersonRoleTable.searchParam.campus_id" :placeholder="t('campusIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('personId')" prop="person_id">
<el-input v-model="campusPersonRoleTable.searchParam.person_id" :placeholder="t('personIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<el-input v-model="campusPersonRoleTable.searchParam.role_id" :placeholder="t('roleIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('deptId')" prop="dept_id">
<el-input v-model="campusPersonRoleTable.searchParam.dept_id" :placeholder="t('deptIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input v-model="campusPersonRoleTable.searchParam.created_at" :placeholder="t('createdAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input v-model="campusPersonRoleTable.searchParam.updated_at" :placeholder="t('updatedAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('deletedAt')" prop="deleted_at">
<el-input v-model="campusPersonRoleTable.searchParam.deleted_at" :placeholder="t('deletedAtPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCampusPersonRoleList()">{{ 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="campusPersonRoleTable.data" size="large" v-loading="campusPersonRoleTable.loading">
<template #empty>
<span>{{ !campusPersonRoleTable.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="person_id" :label="t('personId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="role_id" :label="t('roleId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="dept_id" :label="t('deptId')" 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="deleted_at" :label="t('deletedAt')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="campusPersonRoleTable.page" v-model:page-size="campusPersonRoleTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="campusPersonRoleTable.total"
@size-change="loadCampusPersonRoleList()" @current-change="loadCampusPersonRoleList" />
</div>
</div>
<edit ref="editCampusPersonRoleDialog" @complete="loadCampusPersonRoleList" />
</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 { getCampusPersonRoleList, deleteCampusPersonRole } from '@/app/api/campus_person_role'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/campus_person_role/components/campus-person-role-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let campusPersonRoleTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"person_id":"",
"role_id":"",
"dept_id":"",
"created_at":"",
"updated_at":"",
"deleted_at":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取角色关系列表
*/
const loadCampusPersonRoleList = (page: number = 1) => {
campusPersonRoleTable.loading = true
campusPersonRoleTable.page = page
getCampusPersonRoleList({
page: campusPersonRoleTable.page,
limit: campusPersonRoleTable.limit,
...campusPersonRoleTable.searchParam
}).then(res => {
campusPersonRoleTable.loading = false
campusPersonRoleTable.data = res.data.data
campusPersonRoleTable.total = res.data.total
}).catch(() => {
campusPersonRoleTable.loading = false
})
}
loadCampusPersonRoleList()
const editCampusPersonRoleDialog: Record<string, any> | null = ref(null)
/**
* 添加角色关系
*/
const addEvent = () => {
editCampusPersonRoleDialog.value.setFormData()
editCampusPersonRoleDialog.value.showDialog = true
}
/**
* 编辑角色关系
* @param data
*/
const editEvent = (data: any) => {
editCampusPersonRoleDialog.value.setFormData(data)
editCampusPersonRoleDialog.value.showDialog = true
}
/**
* 删除角色关系
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('campusPersonRoleDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCampusPersonRole(id).then(() => {
loadCampusPersonRoleList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCampusPersonRoleList()
}
</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>

203
admin/src/app/views/campus_person_role/components/campus-person-role-edit.vue

@ -0,0 +1,203 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCampusPersonRole') : t('addCampusPersonRole')" 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-form-item>
<el-form-item :label="t('personId')" prop="person_id">
<el-input v-model="formData.person_id" clearable :placeholder="t('personIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<el-input v-model="formData.role_id" clearable :placeholder="t('roleIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('deptId')" >
<el-input v-model="formData.dept_id" clearable :placeholder="t('deptIdPlaceholder')" 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>
<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>
</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 { addCampusPersonRole, editCampusPersonRole, getCampusPersonRoleInfo } from '@/app/api/campus_person_role'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
person_id: '',
role_id: '',
dept_id: '',
created_at: '',
updated_at: '',
deleted_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
]
,
person_id: [
{ required: true, message: t('personIdPlaceholder'), trigger: 'blur' },
]
,
role_id: [
{ required: true, message: t('roleIdPlaceholder'), trigger: 'blur' },
]
,
dept_id: [
{ required: true, message: t('deptIdPlaceholder'), 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' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCampusPersonRole : addCampusPersonRole
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCampusPersonRoleInfo(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>

231
admin/src/app/views/class/class.vue

@ -0,0 +1,231 @@
<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('addClass') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="classTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="classTable.searchParam.campus_id" :placeholder="t('campusIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('campusName')" prop="campus_name">
<el-input v-model="classTable.searchParam.campus_name" :placeholder="t('campusNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('className')" prop="class_name">
<el-input v-model="classTable.searchParam.class_name" :placeholder="t('classNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('headCoach')" prop="head_coach">
<el-input v-model="classTable.searchParam.head_coach" :placeholder="t('headCoachPlaceholder')" />
</el-form-item>
<el-form-item :label="t('ageGroup')" prop="age_group">
<el-input v-model="classTable.searchParam.age_group" :placeholder="t('ageGroupPlaceholder')" />
</el-form-item>
<el-form-item :label="t('classType')" prop="class_type">
<el-input v-model="classTable.searchParam.class_type" :placeholder="t('classTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('assistantCoach')" prop="assistant_coach">
<el-input v-model="classTable.searchParam.assistant_coach" :placeholder="t('assistantCoachPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input v-model="classTable.searchParam.created_at" :placeholder="t('createdAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input v-model="classTable.searchParam.updated_at" :placeholder="t('updatedAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('deletedAt')" prop="deleted_at">
<el-input v-model="classTable.searchParam.deleted_at" :placeholder="t('deletedAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input v-model="classTable.searchParam.status" :placeholder="t('statusPlaceholder')" />
</el-form-item>
<el-form-item :label="t('sortOrder')" prop="sort_order">
<el-input v-model="classTable.searchParam.sort_order" :placeholder="t('sortOrderPlaceholder')" />
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input v-model="classTable.searchParam.remarks" :placeholder="t('remarksPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadClassList()">{{ 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="classTable.data" size="large" v-loading="classTable.loading">
<template #empty>
<span>{{ !classTable.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_name" :label="t('campusName')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_name" :label="t('className')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="head_coach" :label="t('headCoach')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="age_group" :label="t('ageGroup')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_type" :label="t('classType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="assistant_coach" :label="t('assistantCoach')" 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="deleted_at" :label="t('deletedAt')" 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="sort_order" :label="t('sortOrder')" 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 :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="classTable.page" v-model:page-size="classTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="classTable.total"
@size-change="loadClassList()" @current-change="loadClassList" />
</div>
</div>
<edit ref="editClassDialog" @complete="loadClassList" />
</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 { getClassList, deleteClass } from '@/app/api/class'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/class/components/class-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let classTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"campus_name":"",
"class_name":"",
"head_coach":"",
"age_group":"",
"class_type":"",
"assistant_coach":"",
"created_at":"",
"updated_at":"",
"deleted_at":"",
"status":"",
"sort_order":"",
"remarks":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取班级列表
*/
const loadClassList = (page: number = 1) => {
classTable.loading = true
classTable.page = page
getClassList({
page: classTable.page,
limit: classTable.limit,
...classTable.searchParam
}).then(res => {
classTable.loading = false
classTable.data = res.data.data
classTable.total = res.data.total
}).catch(() => {
classTable.loading = false
})
}
loadClassList()
const editClassDialog: Record<string, any> | null = ref(null)
/**
* 添加班级
*/
const addEvent = () => {
editClassDialog.value.setFormData()
editClassDialog.value.showDialog = true
}
/**
* 编辑班级
* @param data
*/
const editEvent = (data: any) => {
editClassDialog.value.setFormData(data)
editClassDialog.value.showDialog = true
}
/**
* 删除班级
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('classDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteClass(id).then(() => {
loadClassList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadClassList()
}
</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>

263
admin/src/app/views/class/components/class-edit.vue

@ -0,0 +1,263 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateClass') : t('addClass')" 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-form-item>
<el-form-item :label="t('campusName')" prop="campus_name">
<el-input v-model="formData.campus_name" clearable :placeholder="t('campusNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('className')" prop="class_name">
<el-input v-model="formData.class_name" clearable :placeholder="t('classNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('headCoach')" prop="head_coach">
<el-input v-model="formData.head_coach" clearable :placeholder="t('headCoachPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('ageGroup')" prop="age_group">
<el-input v-model="formData.age_group" clearable :placeholder="t('ageGroupPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('classType')" prop="class_type">
<el-input v-model="formData.class_type" clearable :placeholder="t('classTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('assistantCoach')" prop="assistant_coach">
<el-input v-model="formData.assistant_coach" clearable :placeholder="t('assistantCoachPlaceholder')" 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>
<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-item :label="t('status')" prop="status">
<el-input v-model="formData.status" clearable :placeholder="t('statusPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sortOrder')" prop="sort_order">
<el-input v-model="formData.sort_order" clearable :placeholder="t('sortOrderPlaceholder')" 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>
<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 { addClass, editClass, getClassInfo } from '@/app/api/class'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
campus_name: '',
class_name: '',
head_coach: '',
age_group: '',
class_type: '',
assistant_coach: '',
created_at: '',
updated_at: '',
deleted_at: '',
status: '',
sort_order: '',
remarks: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
]
,
campus_name: [
{ required: true, message: t('campusNamePlaceholder'), trigger: 'blur' },
]
,
class_name: [
{ required: true, message: t('classNamePlaceholder'), trigger: 'blur' },
]
,
head_coach: [
{ required: true, message: t('headCoachPlaceholder'), trigger: 'blur' },
]
,
age_group: [
{ required: true, message: t('ageGroupPlaceholder'), trigger: 'blur' },
]
,
class_type: [
{ required: true, message: t('classTypePlaceholder'), trigger: 'blur' },
]
,
assistant_coach: [
{ required: true, message: t('assistantCoachPlaceholder'), 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' },
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
sort_order: [
{ required: true, message: t('sortOrderPlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editClass : addClass
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getClassInfo(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>

219
admin/src/app/views/communication_records/communication_records.vue

@ -0,0 +1,219 @@
<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('addCommunicationRecords') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="communicationRecordsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input v-model="communicationRecordsTable.searchParam.staff_id" :placeholder="t('staffIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input v-model="communicationRecordsTable.searchParam.resource_id" :placeholder="t('resourceIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('resourceType')" prop="resource_type">
<el-input v-model="communicationRecordsTable.searchParam.resource_type" :placeholder="t('resourceTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('communicationType')" prop="communication_type">
<el-input v-model="communicationRecordsTable.searchParam.communication_type" :placeholder="t('communicationTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('communicationResult')" prop="communication_result">
<el-input v-model="communicationRecordsTable.searchParam.communication_result" :placeholder="t('communicationResultPlaceholder')" />
</el-form-item>
<el-form-item :label="t('communicationTime')" prop="communication_time">
<el-input v-model="communicationRecordsTable.searchParam.communication_time" :placeholder="t('communicationTimePlaceholder')" />
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input v-model="communicationRecordsTable.searchParam.remarks" :placeholder="t('remarksPlaceholder')" />
</el-form-item>
<el-form-item :label="t('tag')" prop="tag">
<el-input v-model="communicationRecordsTable.searchParam.tag" :placeholder="t('tagPlaceholder')" />
</el-form-item>
<el-form-item :label="t('businessId')" prop="business_id">
<el-input v-model="communicationRecordsTable.searchParam.business_id" :placeholder="t('businessIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input v-model="communicationRecordsTable.searchParam.created_at" :placeholder="t('createdAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input v-model="communicationRecordsTable.searchParam.updated_at" :placeholder="t('updatedAtPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCommunicationRecordsList()">{{ 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="communicationRecordsTable.data" size="large" v-loading="communicationRecordsTable.loading">
<template #empty>
<span>{{ !communicationRecordsTable.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="resource_id" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="resource_type" :label="t('resourceType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="communication_type" :label="t('communicationType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="communication_result" :label="t('communicationResult')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="communication_time" :label="t('communicationTime')" 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="tag" :label="t('tag')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="business_id" :label="t('businessId')" 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 :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="communicationRecordsTable.page" v-model:page-size="communicationRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="communicationRecordsTable.total"
@size-change="loadCommunicationRecordsList()" @current-change="loadCommunicationRecordsList" />
</div>
</div>
<edit ref="editCommunicationRecordsDialog" @complete="loadCommunicationRecordsList" />
</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 { getCommunicationRecordsList, deleteCommunicationRecords } from '@/app/api/communication_records'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/communication_records/components/communication-records-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let communicationRecordsTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"staff_id":"",
"resource_id":"",
"resource_type":"",
"communication_type":"",
"communication_result":"",
"communication_time":"",
"remarks":"",
"tag":"",
"business_id":"",
"created_at":"",
"updated_at":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取沟通记录列表
*/
const loadCommunicationRecordsList = (page: number = 1) => {
communicationRecordsTable.loading = true
communicationRecordsTable.page = page
getCommunicationRecordsList({
page: communicationRecordsTable.page,
limit: communicationRecordsTable.limit,
...communicationRecordsTable.searchParam
}).then(res => {
communicationRecordsTable.loading = false
communicationRecordsTable.data = res.data.data
communicationRecordsTable.total = res.data.total
}).catch(() => {
communicationRecordsTable.loading = false
})
}
loadCommunicationRecordsList()
const editCommunicationRecordsDialog: Record<string, any> | null = ref(null)
/**
* 添加沟通记录
*/
const addEvent = () => {
editCommunicationRecordsDialog.value.setFormData()
editCommunicationRecordsDialog.value.showDialog = true
}
/**
* 编辑沟通记录
* @param data
*/
const editEvent = (data: any) => {
editCommunicationRecordsDialog.value.setFormData(data)
editCommunicationRecordsDialog.value.showDialog = true
}
/**
* 删除沟通记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('communicationRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCommunicationRecords(id).then(() => {
loadCommunicationRecordsList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCommunicationRecordsList()
}
</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>

243
admin/src/app/views/communication_records/components/communication-records-edit.vue

@ -0,0 +1,243 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCommunicationRecords') : t('addCommunicationRecords')" 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-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-form-item>
<el-form-item :label="t('resourceType')" prop="resource_type">
<el-input v-model="formData.resource_type" clearable :placeholder="t('resourceTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('communicationType')" prop="communication_type">
<el-input v-model="formData.communication_type" clearable :placeholder="t('communicationTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('communicationResult')" prop="communication_result">
<el-input v-model="formData.communication_result" clearable :placeholder="t('communicationResultPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('communicationTime')" prop="communication_time">
<el-input v-model="formData.communication_time" clearable :placeholder="t('communicationTimePlaceholder')" 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('tag')" >
<el-input v-model="formData.tag" clearable :placeholder="t('tagPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('businessId')" >
<el-input v-model="formData.business_id" clearable :placeholder="t('businessIdPlaceholder')" 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>
</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 { addCommunicationRecords, editCommunicationRecords, getCommunicationRecordsInfo } from '@/app/api/communication_records'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
staff_id: '',
resource_id: '',
resource_type: '',
communication_type: '',
communication_result: '',
communication_time: '',
remarks: '',
tag: '',
business_id: '',
created_at: '',
updated_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
]
,
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
resource_type: [
{ required: true, message: t('resourceTypePlaceholder'), trigger: 'blur' },
]
,
communication_type: [
{ required: true, message: t('communicationTypePlaceholder'), trigger: 'blur' },
]
,
communication_result: [
{ required: true, message: t('communicationResultPlaceholder'), trigger: 'blur' },
]
,
communication_time: [
{ required: true, message: t('communicationTimePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
]
,
tag: [
{ required: true, message: t('tagPlaceholder'), trigger: 'blur' },
]
,
business_id: [
{ required: true, message: t('businessIdPlaceholder'), trigger: 'blur' },
]
,
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' },
]
,
updated_at: [
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCommunicationRecords : addCommunicationRecords
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCommunicationRecordsInfo(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>

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

@ -0,0 +1,213 @@
<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-form-item :label="t('contractName')" prop="contract_name">
<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>
<el-form-item :label="t('contractStatus')" prop="contract_status">
<el-input v-model="formData.contract_status" clearable :placeholder="t('contractStatusPlaceholder')" class="input-width" />
</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-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>
<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>
</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 { addContract, editContract, getContractInfo } from '@/app/api/contract'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
contract_name: '',
contract_template: '',
contract_status: '',
contract_type: '',
remarks: '',
created_at: '',
updated_at: '',
deleted_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
contract_name: [
{ required: true, message: t('contractNamePlaceholder'), trigger: 'blur' },
]
,
contract_template: [
{ required: true, message: t('contractTemplatePlaceholder'), trigger: 'blur' },
]
,
contract_status: [
{ required: true, message: t('contractStatusPlaceholder'), trigger: 'blur' },
]
,
contract_type: [
{ 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' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editContract : addContract
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getContractInfo(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>

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

@ -0,0 +1,201 @@
<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('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-form-item :label="t('contractStatus')" prop="contract_status">
<el-input v-model="contractTable.searchParam.contract_status" :placeholder="t('contractStatusPlaceholder')" />
</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-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-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-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<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_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 prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="deleted_at" :label="t('deletedAt')" 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>
</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" />
</div>
</div>
<edit ref="editContractDialog" @complete="loadContractList" />
</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 { getContractList, deleteContract } from '@/app/api/contract'
import { img } from '@/utils/common'
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;
let contractTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"contract_name":"",
"contract_template":"",
"contract_status":"",
"contract_type":"",
"remarks":"",
"created_at":"",
"updated_at":"",
"deleted_at":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取合同列表
*/
const loadContractList = (page: number = 1) => {
contractTable.loading = true
contractTable.page = page
getContractList({
page: contractTable.page,
limit: contractTable.limit,
...contractTable.searchParam
}).then(res => {
contractTable.loading = false
contractTable.data = res.data.data
contractTable.total = res.data.total
}).catch(() => {
contractTable.loading = false
})
}
loadContractList()
const editContractDialog: Record<string, any> | null = ref(null)
/**
* 添加合同
*/
const addEvent = () => {
editContractDialog.value.setFormData()
editContractDialog.value.showDialog = true
}
/**
* 编辑合同
* @param data
*/
const editEvent = (data: any) => {
editContractDialog.value.setFormData(data)
editContractDialog.value.showDialog = true
}
/**
* 删除合同
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('contractDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteContract(id).then(() => {
loadContractList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadContractList()
}
</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>

223
admin/src/app/views/course/components/course-edit.vue

@ -0,0 +1,223 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCourse') : t('addCourse')" 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('courseName')" prop="course_name">
<el-input v-model="formData.course_name" clearable :placeholder="t('courseNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('courseType')" prop="course_type">
<el-input v-model="formData.course_type" clearable :placeholder="t('courseTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('duration')" prop="duration">
<el-input v-model="formData.duration" clearable :placeholder="t('durationPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sessionCount')" prop="session_count">
<el-input v-model="formData.session_count" clearable :placeholder="t('sessionCountPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('singleSessionCount')" prop="single_session_count">
<el-input v-model="formData.single_session_count" clearable :placeholder="t('singleSessionCountPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('price')" prop="price">
<el-input v-model="formData.price" clearable :placeholder="t('pricePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('internalReminder')" prop="internal_reminder">
<el-input v-model="formData.internal_reminder" clearable :placeholder="t('internalReminderPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('customerReminder')" prop="customer_reminder">
<el-input v-model="formData.customer_reminder" clearable :placeholder="t('customerReminderPlaceholder')" 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>
<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 { addCourse, editCourse, getCourseInfo } from '@/app/api/course'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
course_name: '',
course_type: '',
duration: '',
session_count: '',
single_session_count: '',
price: '',
internal_reminder: '',
customer_reminder: '',
remarks: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
course_name: [
{ required: true, message: t('courseNamePlaceholder'), trigger: 'blur' },
]
,
course_type: [
{ required: true, message: t('courseTypePlaceholder'), trigger: 'blur' },
]
,
duration: [
{ required: true, message: t('durationPlaceholder'), trigger: 'blur' },
]
,
session_count: [
{ required: true, message: t('sessionCountPlaceholder'), trigger: 'blur' },
]
,
single_session_count: [
{ required: true, message: t('singleSessionCountPlaceholder'), trigger: 'blur' },
]
,
price: [
{ required: true, message: t('pricePlaceholder'), trigger: 'blur' },
]
,
internal_reminder: [
{ required: true, message: t('internalReminderPlaceholder'), trigger: 'blur' },
]
,
customer_reminder: [
{ required: true, message: t('customerReminderPlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCourse : addCourse
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCourseInfo(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>

207
admin/src/app/views/course/course.vue

@ -0,0 +1,207 @@
<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('addCourse') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="courseTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('courseName')" prop="course_name">
<el-input v-model="courseTable.searchParam.course_name" :placeholder="t('courseNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('courseType')" prop="course_type">
<el-input v-model="courseTable.searchParam.course_type" :placeholder="t('courseTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('duration')" prop="duration">
<el-input v-model="courseTable.searchParam.duration" :placeholder="t('durationPlaceholder')" />
</el-form-item>
<el-form-item :label="t('sessionCount')" prop="session_count">
<el-input v-model="courseTable.searchParam.session_count" :placeholder="t('sessionCountPlaceholder')" />
</el-form-item>
<el-form-item :label="t('singleSessionCount')" prop="single_session_count">
<el-input v-model="courseTable.searchParam.single_session_count" :placeholder="t('singleSessionCountPlaceholder')" />
</el-form-item>
<el-form-item :label="t('price')" prop="price">
<el-input v-model="courseTable.searchParam.price" :placeholder="t('pricePlaceholder')" />
</el-form-item>
<el-form-item :label="t('internalReminder')" prop="internal_reminder">
<el-input v-model="courseTable.searchParam.internal_reminder" :placeholder="t('internalReminderPlaceholder')" />
</el-form-item>
<el-form-item :label="t('customerReminder')" prop="customer_reminder">
<el-input v-model="courseTable.searchParam.customer_reminder" :placeholder="t('customerReminderPlaceholder')" />
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input v-model="courseTable.searchParam.remarks" :placeholder="t('remarksPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCourseList()">{{ 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="courseTable.data" size="large" v-loading="courseTable.loading">
<template #empty>
<span>{{ !courseTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="course_name" :label="t('courseName')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="course_type" :label="t('courseType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="duration" :label="t('duration')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="session_count" :label="t('sessionCount')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="single_session_count" :label="t('singleSessionCount')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="price" :label="t('price')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="internal_reminder" :label="t('internalReminder')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="customer_reminder" :label="t('customerReminder')" 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 :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="courseTable.page" v-model:page-size="courseTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="courseTable.total"
@size-change="loadCourseList()" @current-change="loadCourseList" />
</div>
</div>
<edit ref="editCourseDialog" @complete="loadCourseList" />
</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 { getCourseList, deleteCourse } from '@/app/api/course'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/course/components/course-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let courseTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"course_name":"",
"course_type":"",
"duration":"",
"session_count":"",
"single_session_count":"",
"price":"",
"internal_reminder":"",
"customer_reminder":"",
"remarks":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取课程列表
*/
const loadCourseList = (page: number = 1) => {
courseTable.loading = true
courseTable.page = page
getCourseList({
page: courseTable.page,
limit: courseTable.limit,
...courseTable.searchParam
}).then(res => {
courseTable.loading = false
courseTable.data = res.data.data
courseTable.total = res.data.total
}).catch(() => {
courseTable.loading = false
})
}
loadCourseList()
const editCourseDialog: Record<string, any> | null = ref(null)
/**
* 添加课程
*/
const addEvent = () => {
editCourseDialog.value.setFormData()
editCourseDialog.value.showDialog = true
}
/**
* 编辑课程
* @param data
*/
const editEvent = (data: any) => {
editCourseDialog.value.setFormData(data)
editCourseDialog.value.showDialog = true
}
/**
* 删除课程
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('courseDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCourse(id).then(() => {
loadCourseList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCourseList()
}
</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>

233
admin/src/app/views/course_schedule/components/course-schedule-edit.vue

@ -0,0 +1,233 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCourseSchedule') : t('addCourseSchedule')" 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-form-item>
<el-form-item :label="t('venueId')" prop="venue_id">
<el-input v-model="formData.venue_id" clearable :placeholder="t('venueIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('courseDate')" prop="course_date">
<el-input v-model="formData.course_date" clearable :placeholder="t('courseDatePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('timeSlot')" prop="time_slot">
<el-input v-model="formData.time_slot" clearable :placeholder="t('timeSlotPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('coachId')" prop="coach_id">
<el-input v-model="formData.coach_id" clearable :placeholder="t('coachIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('participants')" prop="participants">
<el-input v-model="formData.participants" clearable :placeholder="t('participantsPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('studentIds')" prop="student_ids">
<el-input v-model="formData.student_ids" clearable :placeholder="t('studentIdsPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('availableCapacity')" prop="available_capacity">
<el-input v-model="formData.available_capacity" clearable :placeholder="t('availableCapacityPlaceholder')" class="input-width" />
</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>
</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 { addCourseSchedule, editCourseSchedule, getCourseScheduleInfo } from '@/app/api/course_schedule'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
venue_id: '',
course_date: '',
time_slot: '',
course_id: '',
coach_id: '',
participants: '',
student_ids: '',
available_capacity: '',
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' },
]
,
venue_id: [
{ required: true, message: t('venueIdPlaceholder'), trigger: 'blur' },
]
,
course_date: [
{ required: true, message: t('courseDatePlaceholder'), trigger: 'blur' },
]
,
time_slot: [
{ required: true, message: t('timeSlotPlaceholder'), trigger: 'blur' },
]
,
course_id: [
{ required: true, message: t('courseIdPlaceholder'), trigger: 'blur' },
]
,
coach_id: [
{ required: true, message: t('coachIdPlaceholder'), trigger: 'blur' },
]
,
participants: [
{ required: true, message: t('participantsPlaceholder'), trigger: 'blur' },
]
,
student_ids: [
{ required: true, message: t('studentIdsPlaceholder'), trigger: 'blur' },
]
,
available_capacity: [
{ required: true, message: t('availableCapacityPlaceholder'), 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 ? editCourseSchedule : addCourseSchedule
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCourseScheduleInfo(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>

213
admin/src/app/views/course_schedule/course_schedule.vue

@ -0,0 +1,213 @@
<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('addCourseSchedule') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="courseScheduleTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="courseScheduleTable.searchParam.campus_id" :placeholder="t('campusIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('venueId')" prop="venue_id">
<el-input v-model="courseScheduleTable.searchParam.venue_id" :placeholder="t('venueIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('courseDate')" prop="course_date">
<el-input v-model="courseScheduleTable.searchParam.course_date" :placeholder="t('courseDatePlaceholder')" />
</el-form-item>
<el-form-item :label="t('timeSlot')" prop="time_slot">
<el-input v-model="courseScheduleTable.searchParam.time_slot" :placeholder="t('timeSlotPlaceholder')" />
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input v-model="courseScheduleTable.searchParam.course_id" :placeholder="t('courseIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('coachId')" prop="coach_id">
<el-input v-model="courseScheduleTable.searchParam.coach_id" :placeholder="t('coachIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('participants')" prop="participants">
<el-input v-model="courseScheduleTable.searchParam.participants" :placeholder="t('participantsPlaceholder')" />
</el-form-item>
<el-form-item :label="t('studentIds')" prop="student_ids">
<el-input v-model="courseScheduleTable.searchParam.student_ids" :placeholder="t('studentIdsPlaceholder')" />
</el-form-item>
<el-form-item :label="t('availableCapacity')" prop="available_capacity">
<el-input v-model="courseScheduleTable.searchParam.available_capacity" :placeholder="t('availableCapacityPlaceholder')" />
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input v-model="courseScheduleTable.searchParam.status" :placeholder="t('statusPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCourseScheduleList()">{{ 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="courseScheduleTable.data" size="large" v-loading="courseScheduleTable.loading">
<template #empty>
<span>{{ !courseScheduleTable.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="venue_id" :label="t('venueId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="course_date" :label="t('courseDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="time_slot" :label="t('timeSlot')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="course_id" :label="t('courseId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="coach_id" :label="t('coachId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="participants" :label="t('participants')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="student_ids" :label="t('studentIds')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="available_capacity" :label="t('availableCapacity')" 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('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="courseScheduleTable.page" v-model:page-size="courseScheduleTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="courseScheduleTable.total"
@size-change="loadCourseScheduleList()" @current-change="loadCourseScheduleList" />
</div>
</div>
<edit ref="editCourseScheduleDialog" @complete="loadCourseScheduleList" />
</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 { getCourseScheduleList, deleteCourseSchedule } from '@/app/api/course_schedule'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/course_schedule/components/course-schedule-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let courseScheduleTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"venue_id":"",
"course_date":"",
"time_slot":"",
"course_id":"",
"coach_id":"",
"participants":"",
"student_ids":"",
"available_capacity":"",
"status":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取课程安排列表
*/
const loadCourseScheduleList = (page: number = 1) => {
courseScheduleTable.loading = true
courseScheduleTable.page = page
getCourseScheduleList({
page: courseScheduleTable.page,
limit: courseScheduleTable.limit,
...courseScheduleTable.searchParam
}).then(res => {
courseScheduleTable.loading = false
courseScheduleTable.data = res.data.data
courseScheduleTable.total = res.data.total
}).catch(() => {
courseScheduleTable.loading = false
})
}
loadCourseScheduleList()
const editCourseScheduleDialog: Record<string, any> | null = ref(null)
/**
* 添加课程安排
*/
const addEvent = () => {
editCourseScheduleDialog.value.setFormData()
editCourseScheduleDialog.value.showDialog = true
}
/**
* 编辑课程安排
* @param data
*/
const editEvent = (data: any) => {
editCourseScheduleDialog.value.setFormData(data)
editCourseScheduleDialog.value.showDialog = true
}
/**
* 删除课程安排
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('courseScheduleDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCourseSchedule(id).then(() => {
loadCourseScheduleList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCourseScheduleList()
}
</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>

193
admin/src/app/views/customer_resource_changes/components/customer-resource-changes-edit.vue

@ -0,0 +1,193 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCustomerResourceChanges') : t('addCustomerResourceChanges')" 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('customerResourceId')" prop="customer_resource_id">
<el-input v-model="formData.customer_resource_id" clearable :placeholder="t('customerResourceIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('operatorId')" prop="operator_id">
<el-input v-model="formData.operator_id" clearable :placeholder="t('operatorIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('modifiedFields')" prop="modified_fields">
<el-input v-model="formData.modified_fields" clearable :placeholder="t('modifiedFieldsPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('oldValues')" prop="old_values">
<el-input v-model="formData.old_values" clearable :placeholder="t('oldValuesPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('newValues')" prop="new_values">
<el-input v-model="formData.new_values" clearable :placeholder="t('newValuesPlaceholder')" 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>
</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 { addCustomerResourceChanges, editCustomerResourceChanges, getCustomerResourceChangesInfo } from '@/app/api/customer_resource_changes'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
customer_resource_id: '',
operator_id: '',
campus_id: '',
modified_fields: '',
old_values: '',
new_values: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
customer_resource_id: [
{ required: true, message: t('customerResourceIdPlaceholder'), trigger: 'blur' },
]
,
operator_id: [
{ required: true, message: t('operatorIdPlaceholder'), trigger: 'blur' },
]
,
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
]
,
modified_fields: [
{ required: true, message: t('modifiedFieldsPlaceholder'), trigger: 'blur' },
]
,
old_values: [
{ required: true, message: t('oldValuesPlaceholder'), trigger: 'blur' },
]
,
new_values: [
{ required: true, message: t('newValuesPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCustomerResourceChanges : addCustomerResourceChanges
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCustomerResourceChangesInfo(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>

189
admin/src/app/views/customer_resource_changes/customer_resource_changes.vue

@ -0,0 +1,189 @@
<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('addCustomerResourceChanges') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="customerResourceChangesTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('customerResourceId')" prop="customer_resource_id">
<el-input v-model="customerResourceChangesTable.searchParam.customer_resource_id" :placeholder="t('customerResourceIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('operatorId')" prop="operator_id">
<el-input v-model="customerResourceChangesTable.searchParam.operator_id" :placeholder="t('operatorIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="customerResourceChangesTable.searchParam.campus_id" :placeholder="t('campusIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('modifiedFields')" prop="modified_fields">
<el-input v-model="customerResourceChangesTable.searchParam.modified_fields" :placeholder="t('modifiedFieldsPlaceholder')" />
</el-form-item>
<el-form-item :label="t('oldValues')" prop="old_values">
<el-input v-model="customerResourceChangesTable.searchParam.old_values" :placeholder="t('oldValuesPlaceholder')" />
</el-form-item>
<el-form-item :label="t('newValues')" prop="new_values">
<el-input v-model="customerResourceChangesTable.searchParam.new_values" :placeholder="t('newValuesPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCustomerResourceChangesList()">{{ 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="customerResourceChangesTable.data" size="large" v-loading="customerResourceChangesTable.loading">
<template #empty>
<span>{{ !customerResourceChangesTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="customer_resource_id" :label="t('customerResourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="operator_id" :label="t('operatorId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="campus_id" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="modified_fields" :label="t('modifiedFields')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="old_values" :label="t('oldValues')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="new_values" :label="t('newValues')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="customerResourceChangesTable.page" v-model:page-size="customerResourceChangesTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="customerResourceChangesTable.total"
@size-change="loadCustomerResourceChangesList()" @current-change="loadCustomerResourceChangesList" />
</div>
</div>
<edit ref="editCustomerResourceChangesDialog" @complete="loadCustomerResourceChangesList" />
</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 { getCustomerResourceChangesList, deleteCustomerResourceChanges } from '@/app/api/customer_resource_changes'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/customer_resource_changes/components/customer-resource-changes-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let customerResourceChangesTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"customer_resource_id":"",
"operator_id":"",
"campus_id":"",
"modified_fields":"",
"old_values":"",
"new_values":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取客户资源表变更记录列表
*/
const loadCustomerResourceChangesList = (page: number = 1) => {
customerResourceChangesTable.loading = true
customerResourceChangesTable.page = page
getCustomerResourceChangesList({
page: customerResourceChangesTable.page,
limit: customerResourceChangesTable.limit,
...customerResourceChangesTable.searchParam
}).then(res => {
customerResourceChangesTable.loading = false
customerResourceChangesTable.data = res.data.data
customerResourceChangesTable.total = res.data.total
}).catch(() => {
customerResourceChangesTable.loading = false
})
}
loadCustomerResourceChangesList()
const editCustomerResourceChangesDialog: Record<string, any> | null = ref(null)
/**
* 添加客户资源表变更记录
*/
const addEvent = () => {
editCustomerResourceChangesDialog.value.setFormData()
editCustomerResourceChangesDialog.value.showDialog = true
}
/**
* 编辑客户资源表变更记录
* @param data
*/
const editEvent = (data: any) => {
editCustomerResourceChangesDialog.value.setFormData(data)
editCustomerResourceChangesDialog.value.showDialog = true
}
/**
* 删除客户资源表变更记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('customerResourceChangesDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCustomerResourceChanges(id).then(() => {
loadCustomerResourceChangesList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCustomerResourceChangesList()
}
</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>

303
admin/src/app/views/customer_resources/components/customer-resources-edit.vue

@ -0,0 +1,303 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCustomerResources') : t('addCustomerResources')" 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('createYearMonth')" prop="create_year_month">
<el-input v-model="formData.create_year_month" clearable :placeholder="t('createYearMonthPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('createDate')" prop="create_date">
<el-input v-model="formData.create_date" clearable :placeholder="t('createDatePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sourceChannel')" prop="source_channel">
<el-input v-model="formData.source_channel" clearable :placeholder="t('sourceChannelPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('source')" prop="source">
<el-input v-model="formData.source" clearable :placeholder="t('sourcePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('consultant')" prop="consultant">
<el-input v-model="formData.consultant" clearable :placeholder="t('consultantPlaceholder')" class="input-width" />
</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('age')" prop="age">
<el-input v-model="formData.age" clearable :placeholder="t('agePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('gender')" prop="gender">
<el-input v-model="formData.gender" clearable :placeholder="t('genderPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('phoneNumber')" prop="phone_number">
<el-input v-model="formData.phone_number" clearable :placeholder="t('phoneNumberPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('demand')" prop="demand">
<el-input v-model="formData.demand" clearable :placeholder="t('demandPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('purchasingPower')" prop="purchasing_power">
<el-input v-model="formData.purchasing_power" clearable :placeholder="t('purchasingPowerPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('cognitiveIdea')" prop="cognitive_idea">
<el-input v-model="formData.cognitive_idea" clearable :placeholder="t('cognitiveIdeaPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionalClassTime')" prop="optional_class_time">
<el-input v-model="formData.optional_class_time" clearable :placeholder="t('optionalClassTimePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('distance')" prop="distance">
<el-input v-model="formData.distance" clearable :placeholder="t('distancePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('decisionMaker')" prop="decision_maker">
<el-input v-model="formData.decision_maker" clearable :placeholder="t('decisionMakerPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('initialIntent')" prop="initial_intent">
<el-input v-model="formData.initial_intent" clearable :placeholder="t('initialIntentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('campus')" prop="campus">
<el-input v-model="formData.campus" clearable :placeholder="t('campusPlaceholder')" 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>
</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 { addCustomerResources, editCustomerResources, getCustomerResourcesInfo } from '@/app/api/customer_resources'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
create_year_month: '',
create_date: '',
source_channel: '',
source: '',
consultant: '',
name: '',
age: '',
gender: '',
phone_number: '',
demand: '',
purchasing_power: '',
cognitive_idea: '',
optional_class_time: '',
distance: '',
decision_maker: '',
initial_intent: '',
campus: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
create_year_month: [
{ required: true, message: t('createYearMonthPlaceholder'), trigger: 'blur' },
]
,
create_date: [
{ required: true, message: t('createDatePlaceholder'), trigger: 'blur' },
]
,
source_channel: [
{ required: true, message: t('sourceChannelPlaceholder'), trigger: 'blur' },
]
,
source: [
{ required: true, message: t('sourcePlaceholder'), trigger: 'blur' },
]
,
consultant: [
{ required: true, message: t('consultantPlaceholder'), trigger: 'blur' },
]
,
name: [
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
]
,
age: [
{ required: true, message: t('agePlaceholder'), trigger: 'blur' },
]
,
gender: [
{ required: true, message: t('genderPlaceholder'), trigger: 'blur' },
]
,
phone_number: [
{ required: true, message: t('phoneNumberPlaceholder'), trigger: 'blur' },
]
,
demand: [
{ required: true, message: t('demandPlaceholder'), trigger: 'blur' },
]
,
purchasing_power: [
{ required: true, message: t('purchasingPowerPlaceholder'), trigger: 'blur' },
]
,
cognitive_idea: [
{ required: true, message: t('cognitiveIdeaPlaceholder'), trigger: 'blur' },
]
,
optional_class_time: [
{ required: true, message: t('optionalClassTimePlaceholder'), trigger: 'blur' },
]
,
distance: [
{ required: true, message: t('distancePlaceholder'), trigger: 'blur' },
]
,
decision_maker: [
{ required: true, message: t('decisionMakerPlaceholder'), trigger: 'blur' },
]
,
initial_intent: [
{ required: true, message: t('initialIntentPlaceholder'), trigger: 'blur' },
]
,
campus: [
{ required: true, message: t('campusPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCustomerResources : addCustomerResources
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCustomerResourcesInfo(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>

255
admin/src/app/views/customer_resources/customer_resources.vue

@ -0,0 +1,255 @@
<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('addCustomerResources') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="customerResourcesTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('createYearMonth')" prop="create_year_month">
<el-input v-model="customerResourcesTable.searchParam.create_year_month" :placeholder="t('createYearMonthPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createDate')" prop="create_date">
<el-input v-model="customerResourcesTable.searchParam.create_date" :placeholder="t('createDatePlaceholder')" />
</el-form-item>
<el-form-item :label="t('sourceChannel')" prop="source_channel">
<el-input v-model="customerResourcesTable.searchParam.source_channel" :placeholder="t('sourceChannelPlaceholder')" />
</el-form-item>
<el-form-item :label="t('source')" prop="source">
<el-input v-model="customerResourcesTable.searchParam.source" :placeholder="t('sourcePlaceholder')" />
</el-form-item>
<el-form-item :label="t('consultant')" prop="consultant">
<el-input v-model="customerResourcesTable.searchParam.consultant" :placeholder="t('consultantPlaceholder')" />
</el-form-item>
<el-form-item :label="t('name')" prop="name">
<el-input v-model="customerResourcesTable.searchParam.name" :placeholder="t('namePlaceholder')" />
</el-form-item>
<el-form-item :label="t('age')" prop="age">
<el-input v-model="customerResourcesTable.searchParam.age" :placeholder="t('agePlaceholder')" />
</el-form-item>
<el-form-item :label="t('gender')" prop="gender">
<el-input v-model="customerResourcesTable.searchParam.gender" :placeholder="t('genderPlaceholder')" />
</el-form-item>
<el-form-item :label="t('phoneNumber')" prop="phone_number">
<el-input v-model="customerResourcesTable.searchParam.phone_number" :placeholder="t('phoneNumberPlaceholder')" />
</el-form-item>
<el-form-item :label="t('demand')" prop="demand">
<el-input v-model="customerResourcesTable.searchParam.demand" :placeholder="t('demandPlaceholder')" />
</el-form-item>
<el-form-item :label="t('purchasingPower')" prop="purchasing_power">
<el-input v-model="customerResourcesTable.searchParam.purchasing_power" :placeholder="t('purchasingPowerPlaceholder')" />
</el-form-item>
<el-form-item :label="t('cognitiveIdea')" prop="cognitive_idea">
<el-input v-model="customerResourcesTable.searchParam.cognitive_idea" :placeholder="t('cognitiveIdeaPlaceholder')" />
</el-form-item>
<el-form-item :label="t('optionalClassTime')" prop="optional_class_time">
<el-input v-model="customerResourcesTable.searchParam.optional_class_time" :placeholder="t('optionalClassTimePlaceholder')" />
</el-form-item>
<el-form-item :label="t('distance')" prop="distance">
<el-input v-model="customerResourcesTable.searchParam.distance" :placeholder="t('distancePlaceholder')" />
</el-form-item>
<el-form-item :label="t('decisionMaker')" prop="decision_maker">
<el-input v-model="customerResourcesTable.searchParam.decision_maker" :placeholder="t('decisionMakerPlaceholder')" />
</el-form-item>
<el-form-item :label="t('initialIntent')" prop="initial_intent">
<el-input v-model="customerResourcesTable.searchParam.initial_intent" :placeholder="t('initialIntentPlaceholder')" />
</el-form-item>
<el-form-item :label="t('campus')" prop="campus">
<el-input v-model="customerResourcesTable.searchParam.campus" :placeholder="t('campusPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCustomerResourcesList()">{{ 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="customerResourcesTable.data" size="large" v-loading="customerResourcesTable.loading">
<template #empty>
<span>{{ !customerResourcesTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="create_year_month" :label="t('createYearMonth')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="create_date" :label="t('createDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="source_channel" :label="t('sourceChannel')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="source" :label="t('source')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="consultant" :label="t('consultant')" 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 prop="age" :label="t('age')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="gender" :label="t('gender')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="phone_number" :label="t('phoneNumber')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="demand" :label="t('demand')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="purchasing_power" :label="t('purchasingPower')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="cognitive_idea" :label="t('cognitiveIdea')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="optional_class_time" :label="t('optionalClassTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="distance" :label="t('distance')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="decision_maker" :label="t('decisionMaker')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="initial_intent" :label="t('initialIntent')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="campus" :label="t('campus')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="customerResourcesTable.page" v-model:page-size="customerResourcesTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="customerResourcesTable.total"
@size-change="loadCustomerResourcesList()" @current-change="loadCustomerResourcesList" />
</div>
</div>
<edit ref="editCustomerResourcesDialog" @complete="loadCustomerResourcesList" />
</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 { getCustomerResourcesList, deleteCustomerResources } from '@/app/api/customer_resources'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/customer_resources/components/customer-resources-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let customerResourcesTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"create_year_month":"",
"create_date":"",
"source_channel":"",
"source":"",
"consultant":"",
"name":"",
"age":"",
"gender":"",
"phone_number":"",
"demand":"",
"purchasing_power":"",
"cognitive_idea":"",
"optional_class_time":"",
"distance":"",
"decision_maker":"",
"initial_intent":"",
"campus":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取客户资源列表
*/
const loadCustomerResourcesList = (page: number = 1) => {
customerResourcesTable.loading = true
customerResourcesTable.page = page
getCustomerResourcesList({
page: customerResourcesTable.page,
limit: customerResourcesTable.limit,
...customerResourcesTable.searchParam
}).then(res => {
customerResourcesTable.loading = false
customerResourcesTable.data = res.data.data
customerResourcesTable.total = res.data.total
}).catch(() => {
customerResourcesTable.loading = false
})
}
loadCustomerResourcesList()
const editCustomerResourcesDialog: Record<string, any> | null = ref(null)
/**
* 添加客户资源
*/
const addEvent = () => {
editCustomerResourcesDialog.value.setFormData()
editCustomerResourcesDialog.value.showDialog = true
}
/**
* 编辑客户资源
* @param data
*/
const editEvent = (data: any) => {
editCustomerResourcesDialog.value.setFormData(data)
editCustomerResourcesDialog.value.showDialog = true
}
/**
* 删除客户资源
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('customerResourcesDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCustomerResources(id).then(() => {
loadCustomerResourcesList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCustomerResourcesList()
}
</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>

153
admin/src/app/views/departments/components/departments-edit.vue

@ -0,0 +1,153 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateDepartments') : t('addDepartments')" 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('departmentName')" prop="department_name">
<el-input v-model="formData.department_name" clearable :placeholder="t('departmentNamePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('parentDepartmentId')" >
<el-input v-model="formData.parent_department_id" clearable :placeholder="t('parentDepartmentIdPlaceholder')" 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>
</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 { addDepartments, editDepartments, getDepartmentsInfo } from '@/app/api/departments'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
department_name: '',
parent_department_id: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
department_name: [
{ required: true, message: t('departmentNamePlaceholder'), trigger: 'blur' },
]
,
parent_department_id: [
{ required: true, message: t('parentDepartmentIdPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editDepartments : addDepartments
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getDepartmentsInfo(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>

165
admin/src/app/views/departments/departments.vue

@ -0,0 +1,165 @@
<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('addDepartments') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="departmentsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('departmentName')" prop="department_name">
<el-input v-model="departmentsTable.searchParam.department_name" :placeholder="t('departmentNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('parentDepartmentId')" prop="parent_department_id">
<el-input v-model="departmentsTable.searchParam.parent_department_id" :placeholder="t('parentDepartmentIdPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadDepartmentsList()">{{ 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="departmentsTable.data" size="large" v-loading="departmentsTable.loading">
<template #empty>
<span>{{ !departmentsTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="department_name" :label="t('departmentName')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="parent_department_id" :label="t('parentDepartmentId')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="departmentsTable.page" v-model:page-size="departmentsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="departmentsTable.total"
@size-change="loadDepartmentsList()" @current-change="loadDepartmentsList" />
</div>
</div>
<edit ref="editDepartmentsDialog" @complete="loadDepartmentsList" />
</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 { getDepartmentsList, deleteDepartments } from '@/app/api/departments'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/departments/components/departments-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let departmentsTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"department_name":"",
"parent_department_id":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取部门列表
*/
const loadDepartmentsList = (page: number = 1) => {
departmentsTable.loading = true
departmentsTable.page = page
getDepartmentsList({
page: departmentsTable.page,
limit: departmentsTable.limit,
...departmentsTable.searchParam
}).then(res => {
departmentsTable.loading = false
departmentsTable.data = res.data.data
departmentsTable.total = res.data.total
}).catch(() => {
departmentsTable.loading = false
})
}
loadDepartmentsList()
const editDepartmentsDialog: Record<string, any> | null = ref(null)
/**
* 添加部门
*/
const addEvent = () => {
editDepartmentsDialog.value.setFormData()
editDepartmentsDialog.value.showDialog = true
}
/**
* 编辑部门
* @param data
*/
const editEvent = (data: any) => {
editDepartmentsDialog.value.setFormData(data)
editDepartmentsDialog.value.showDialog = true
}
/**
* 删除部门
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('departmentsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteDepartments(id).then(() => {
loadDepartmentsList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadDepartmentsList()
}
</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>

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

@ -0,0 +1,183 @@
<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-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')" class="input-width" />
</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-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-form-item>
<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>
</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 { addExamAnswers, editExamAnswers, getExamAnswersInfo } from '@/app/api/exam_answers'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
user_id: '',
question_id: '',
answer: '',
is_correct: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
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' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editExamAnswers : addExamAnswers
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getExamAnswersInfo(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>

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

@ -0,0 +1,183 @@
<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('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-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-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-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<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="user_id" :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="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('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="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>
<edit ref="editExamAnswersDialog" @complete="loadExamAnswersList" />
</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 { getExamAnswersList, deleteExamAnswers } from '@/app/api/exam_answers'
import { img } from '@/utils/common'
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;
let examAnswersTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"user_id":"",
"question_id":"",
"answer":"",
"is_correct":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取答题记录列表
*/
const loadExamAnswersList = (page: number = 1) => {
examAnswersTable.loading = true
examAnswersTable.page = page
getExamAnswersList({
page: examAnswersTable.page,
limit: examAnswersTable.limit,
...examAnswersTable.searchParam
}).then(res => {
examAnswersTable.loading = false
examAnswersTable.data = res.data.data
examAnswersTable.total = res.data.total
}).catch(() => {
examAnswersTable.loading = false
})
}
loadExamAnswersList()
const editExamAnswersDialog: Record<string, any> | null = ref(null)
/**
* 添加答题记录
*/
const addEvent = () => {
editExamAnswersDialog.value.setFormData()
editExamAnswersDialog.value.showDialog = true
}
/**
* 编辑答题记录
* @param data
*/
const editEvent = (data: any) => {
editExamAnswersDialog.value.setFormData(data)
editExamAnswersDialog.value.showDialog = true
}
/**
* 删除答题记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examAnswersDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteExamAnswers(id).then(() => {
loadExamAnswersList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadExamAnswersList()
}
</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>

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

@ -0,0 +1,163 @@
<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-form-item :label="t('selectionMode')" prop="selection_mode">
<el-input v-model="formData.selection_mode" clearable :placeholder="t('selectionModePlaceholder')" class="input-width" />
</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-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-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 { addExamPapers, editExamPapers, getExamPapersInfo } from '@/app/api/exam_papers'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
selection_mode: '',
total_score: '',
passing_score: '',
}
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'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editExamPapers : addExamPapers
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
})
}
})
}
//
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[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>

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

@ -0,0 +1,171 @@
<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('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-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-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>
<el-form-item>
<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">
<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="passing_score" :label="t('passingScore')" 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>
</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" />
</div>
</div>
<edit ref="editExamPapersDialog" @complete="loadExamPapersList" />
</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 { getExamPapersList, deleteExamPapers } from '@/app/api/exam_papers'
import { img } from '@/utils/common'
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;
let examPapersTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"selection_mode":"",
"total_score":"",
"passing_score":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取试卷列表
*/
const loadExamPapersList = (page: number = 1) => {
examPapersTable.loading = true
examPapersTable.page = page
getExamPapersList({
page: examPapersTable.page,
limit: examPapersTable.limit,
...examPapersTable.searchParam
}).then(res => {
examPapersTable.loading = false
examPapersTable.data = res.data.data
examPapersTable.total = res.data.total
}).catch(() => {
examPapersTable.loading = false
})
}
loadExamPapersList()
const editExamPapersDialog: Record<string, any> | null = ref(null)
/**
* 添加试卷
*/
const addEvent = () => {
editExamPapersDialog.value.setFormData()
editExamPapersDialog.value.showDialog = true
}
/**
* 编辑试卷
* @param data
*/
const editEvent = (data: any) => {
editExamPapersDialog.value.setFormData(data)
editExamPapersDialog.value.showDialog = true
}
/**
* 删除试卷
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examPapersDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteExamPapers(id).then(() => {
loadExamPapersList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadExamPapersList()
}
</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>

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

@ -0,0 +1,223 @@
<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('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-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>
<el-form-item :label="t('correctAnswer')" prop="correct_answer">
<el-input v-model="examQuestionsTable.searchParam.correct_answer" :placeholder="t('correctAnswerPlaceholder')" />
</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-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<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="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 prop="option_c_content_type" :label="t('optionCContentType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="option_c_content" :label="t('optionCContent')" min-width="120" :show-overflow-tooltip="true"/>
<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="correct_answer" :label="t('correctAnswer')" 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>
</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" />
</div>
</div>
</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 { getExamQuestionsList, deleteExamQuestions } from '@/app/api/exam_questions'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import { useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let examQuestionsTable = reactive({
page: 1,
limit: 10,
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":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取试题列表
*/
const loadExamQuestionsList = (page: number = 1) => {
examQuestionsTable.loading = true
examQuestionsTable.page = page
getExamQuestionsList({
page: examQuestionsTable.page,
limit: examQuestionsTable.limit,
...examQuestionsTable.searchParam
}).then(res => {
examQuestionsTable.loading = false
examQuestionsTable.data = res.data.data
examQuestionsTable.total = res.data.total
}).catch(() => {
examQuestionsTable.loading = false
})
}
loadExamQuestionsList()
const router = useRouter()
/**
* 添加试题
*/
const addEvent = () => {
router.push('/exam_questions/exam_questions_edit')
}
/**
* 编辑试题
* @param data
*/
const editEvent = (data: any) => {
router.push('/exam_questions/exam_questions_edit?id='+data.id)
}
/**
* 删除试题
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examQuestionsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteExamQuestions(id).then(() => {
loadExamQuestionsList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadExamQuestionsList()
}
</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>

250
admin/src/app/views/exam_questions/exam_questions_edit.vue

@ -0,0 +1,250 @@
<template>
<div class="main-container">
<div class="detail-head">
<div class="left" @click="back()">
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
<span class="ml-[1px]">{{t('returnToPreviousPage')}}</span>
</div>
<span class="adorn">|</span>
<span class="right">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
<el-form-item :label="t('questionType')" prop="question_type">
<el-input v-model="formData.question_type" clearable :placeholder="t('questionTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('questionContentType')" prop="question_content_type">
<el-input v-model="formData.question_content_type" clearable :placeholder="t('questionContentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('questionContent')" prop="question_content">
<el-input v-model="formData.question_content" clearable :placeholder="t('questionContentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionAContentType')" >
<el-input v-model="formData.option_a_content_type" clearable :placeholder="t('optionAContentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionAContent')" >
<el-input v-model="formData.option_a_content" clearable :placeholder="t('optionAContentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionBContentType')" >
<el-input v-model="formData.option_b_content_type" clearable :placeholder="t('optionBContentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionBContent')" >
<el-input v-model="formData.option_b_content" clearable :placeholder="t('optionBContentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionCContentType')" >
<el-input v-model="formData.option_c_content_type" clearable :placeholder="t('optionCContentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionCContent')" >
<el-input v-model="formData.option_c_content" clearable :placeholder="t('optionCContentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionDContentType')" >
<el-input v-model="formData.option_d_content_type" clearable :placeholder="t('optionDContentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('optionDContent')" >
<el-input v-model="formData.option_d_content" clearable :placeholder="t('optionDContentPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('correctAnswer')" prop="correct_answer">
<el-input v-model="formData.correct_answer" clearable :placeholder="t('correctAnswerPlaceholder')" class="input-width" />
</el-form-item>
</el-form>
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" @click="onSave(formRef)">{{ t('save') }}</el-button>
<el-button @click="back()">{{ t('cancel') }}</el-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import type { FormInstance } from 'element-plus'
import { getExamQuestionsInfo,addExamQuestions,editExamQuestions } from '@/app/api/exam_questions';
import { useRoute } from 'vue-router'
const route = useRoute()
const id:number = parseInt(route.query.id);
const loading = ref(false)
const pageName = route.meta.title
/**
* 表单数据
*/
const initialFormData = {
id: 0,
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: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const setFormData = async (id:number = 0) => {
Object.assign(formData, initialFormData)
const data = await (await getExamQuestionsInfo(id)).data
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
if(id) setFormData(id);
const formRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
//
const formRules = computed(() => {
return {
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_a_content_type: [
{ required: true, message: t('optionAContentTypePlaceholder'), trigger: 'blur' },
]
,
option_a_content: [
{ required: true, message: t('optionAContentPlaceholder'), trigger: 'blur' },
]
,
option_b_content_type: [
{ required: true, message: t('optionBContentTypePlaceholder'), trigger: 'blur' },
]
,
option_b_content: [
{ required: true, message: t('optionBContentPlaceholder'), trigger: 'blur' },
]
,
option_c_content_type: [
{ required: true, message: t('optionCContentTypePlaceholder'), trigger: 'blur' },
]
,
option_c_content: [
{ required: true, message: t('optionCContentPlaceholder'), trigger: 'blur' },
]
,
option_d_content_type: [
{ required: true, message: t('optionDContentTypePlaceholder'), trigger: 'blur' },
]
,
option_d_content: [
{ required: true, message: t('optionDContentPlaceholder'), trigger: 'blur' },
]
,
correct_answer: [
{ required: true, message: t('correctAnswerPlaceholder'), trigger: 'blur' },
]
,
}
})
const onSave = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
const save = id ? editExamQuestions : addExamQuestions
save(data).then(res => {
loading.value = false
history.back()
}).catch(err => {
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()
}
}
const back = () => {
history.back()
}
</script>
<style lang="scss" scoped></style>

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

@ -0,0 +1,203 @@
<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-form-item :label="t('campusId')" prop="campus_id">
<el-input v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')" class="input-width" />
</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-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-form-item>
<el-form-item :label="t('score')" >
<el-input v-model="formData.score" clearable :placeholder="t('scorePlaceholder')" class="input-width" />
</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>
<el-form-item :label="t('startTime')" >
<el-input v-model="formData.start_time" clearable :placeholder="t('startTimePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('endTime')" >
<el-input v-model="formData.end_time" clearable :placeholder="t('endTimePlaceholder')" 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>
</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 { addExamRecords, editExamRecords, getExamRecordsInfo } from '@/app/api/exam_records'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
user_id: '',
paper_id: '',
score: '',
status: '',
start_time: '',
end_time: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
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' },
]
,
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' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editExamRecords : addExamRecords
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getExamRecordsInfo(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>

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

@ -0,0 +1,195 @@
<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('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-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-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-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-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-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<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="user_id" :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="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 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 :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="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>
<edit ref="editExamRecordsDialog" @complete="loadExamRecordsList" />
</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 { getExamRecordsList, deleteExamRecords } from '@/app/api/exam_records'
import { img } from '@/utils/common'
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;
let examRecordsTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"user_id":"",
"paper_id":"",
"score":"",
"status":"",
"start_time":"",
"end_time":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取考试记录列表
*/
const loadExamRecordsList = (page: number = 1) => {
examRecordsTable.loading = true
examRecordsTable.page = page
getExamRecordsList({
page: examRecordsTable.page,
limit: examRecordsTable.limit,
...examRecordsTable.searchParam
}).then(res => {
examRecordsTable.loading = false
examRecordsTable.data = res.data.data
examRecordsTable.total = res.data.total
}).catch(() => {
examRecordsTable.loading = false
})
}
loadExamRecordsList()
const editExamRecordsDialog: Record<string, any> | null = ref(null)
/**
* 添加考试记录
*/
const addEvent = () => {
editExamRecordsDialog.value.setFormData()
editExamRecordsDialog.value.showDialog = true
}
/**
* 编辑考试记录
* @param data
*/
const editEvent = (data: any) => {
editExamRecordsDialog.value.setFormData(data)
editExamRecordsDialog.value.showDialog = true
}
/**
* 删除考试记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('examRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteExamRecords(id).then(() => {
loadExamRecordsList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadExamRecordsList()
}
</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>

263
admin/src/app/views/order_table/components/order-table-edit.vue

@ -0,0 +1,263 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateOrderTable') : t('addOrderTable')" 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('paymentId')" prop="payment_id">
<el-input v-model="formData.payment_id" clearable :placeholder="t('paymentIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-input v-model="formData.order_status" clearable :placeholder="t('orderStatusPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('paymentType')" prop="payment_type">
<el-input v-model="formData.payment_type" clearable :placeholder="t('paymentTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('orderAmount')" prop="order_amount">
<el-input v-model="formData.order_amount" clearable :placeholder="t('orderAmountPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id">
<el-input v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')" class="input-width" />
</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-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-form-item>
<el-form-item :label="t('afterSalesStatus')" >
<el-input v-model="formData.after_sales_status" clearable :placeholder="t('afterSalesStatusPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('afterSalesReason')" >
<el-input v-model="formData.after_sales_reason" clearable :placeholder="t('afterSalesReasonPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('afterSalesTime')" >
<el-input v-model="formData.after_sales_time" clearable :placeholder="t('afterSalesTimePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('paymentTime')" >
<el-input v-model="formData.payment_time" clearable :placeholder="t('paymentTimePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('subscriptionPaymentTime')" >
<el-input v-model="formData.subscription_payment_time" clearable :placeholder="t('subscriptionPaymentTimePlaceholder')" 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>
</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 { addOrderTable, editOrderTable, getOrderTableInfo } from '@/app/api/order_table'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
payment_id: '',
order_status: '',
payment_type: '',
order_amount: '',
course_id: '',
class_id: '',
staff_id: '',
resource_id: '',
after_sales_status: '',
after_sales_reason: '',
after_sales_time: '',
payment_time: '',
subscription_payment_time: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
payment_id: [
{ required: true, message: t('paymentIdPlaceholder'), trigger: 'blur' },
]
,
order_status: [
{ required: true, message: t('orderStatusPlaceholder'), trigger: 'blur' },
]
,
payment_type: [
{ required: true, message: t('paymentTypePlaceholder'), trigger: 'blur' },
]
,
order_amount: [
{ required: true, message: t('orderAmountPlaceholder'), trigger: 'blur' },
]
,
course_id: [
{ required: true, message: t('courseIdPlaceholder'), trigger: 'blur' },
]
,
class_id: [
{ required: true, message: t('classIdPlaceholder'), trigger: 'blur' },
]
,
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
]
,
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
after_sales_status: [
{ required: true, message: t('afterSalesStatusPlaceholder'), trigger: 'blur' },
]
,
after_sales_reason: [
{ required: true, message: t('afterSalesReasonPlaceholder'), trigger: 'blur' },
]
,
after_sales_time: [
{ required: true, message: t('afterSalesTimePlaceholder'), trigger: 'blur' },
]
,
payment_time: [
{ required: true, message: t('paymentTimePlaceholder'), trigger: 'blur' },
]
,
subscription_payment_time: [
{ required: true, message: t('subscriptionPaymentTimePlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editOrderTable : addOrderTable
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getOrderTableInfo(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>

231
admin/src/app/views/order_table/order_table.vue

@ -0,0 +1,231 @@
<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('addOrderTable') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="orderTableTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('paymentId')" prop="payment_id">
<el-input v-model="orderTableTable.searchParam.payment_id" :placeholder="t('paymentIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-input v-model="orderTableTable.searchParam.order_status" :placeholder="t('orderStatusPlaceholder')" />
</el-form-item>
<el-form-item :label="t('paymentType')" prop="payment_type">
<el-input v-model="orderTableTable.searchParam.payment_type" :placeholder="t('paymentTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('orderAmount')" prop="order_amount">
<el-input v-model="orderTableTable.searchParam.order_amount" :placeholder="t('orderAmountPlaceholder')" />
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input v-model="orderTableTable.searchParam.course_id" :placeholder="t('courseIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id">
<el-input v-model="orderTableTable.searchParam.class_id" :placeholder="t('classIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input v-model="orderTableTable.searchParam.staff_id" :placeholder="t('staffIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input v-model="orderTableTable.searchParam.resource_id" :placeholder="t('resourceIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('afterSalesStatus')" prop="after_sales_status">
<el-input v-model="orderTableTable.searchParam.after_sales_status" :placeholder="t('afterSalesStatusPlaceholder')" />
</el-form-item>
<el-form-item :label="t('afterSalesReason')" prop="after_sales_reason">
<el-input v-model="orderTableTable.searchParam.after_sales_reason" :placeholder="t('afterSalesReasonPlaceholder')" />
</el-form-item>
<el-form-item :label="t('afterSalesTime')" prop="after_sales_time">
<el-input v-model="orderTableTable.searchParam.after_sales_time" :placeholder="t('afterSalesTimePlaceholder')" />
</el-form-item>
<el-form-item :label="t('paymentTime')" prop="payment_time">
<el-input v-model="orderTableTable.searchParam.payment_time" :placeholder="t('paymentTimePlaceholder')" />
</el-form-item>
<el-form-item :label="t('subscriptionPaymentTime')" prop="subscription_payment_time">
<el-input v-model="orderTableTable.searchParam.subscription_payment_time" :placeholder="t('subscriptionPaymentTimePlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadOrderTableList()">{{ 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="orderTableTable.data" size="large" v-loading="orderTableTable.loading">
<template #empty>
<span>{{ !orderTableTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="payment_id" :label="t('paymentId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="order_status" :label="t('orderStatus')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="payment_type" :label="t('paymentType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="order_amount" :label="t('orderAmount')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="course_id" :label="t('courseId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_id" :label="t('classId')" 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="resource_id" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="after_sales_status" :label="t('afterSalesStatus')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="after_sales_reason" :label="t('afterSalesReason')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="after_sales_time" :label="t('afterSalesTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="payment_time" :label="t('paymentTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="subscription_payment_time" :label="t('subscriptionPaymentTime')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="orderTableTable.page" v-model:page-size="orderTableTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="orderTableTable.total"
@size-change="loadOrderTableList()" @current-change="loadOrderTableList" />
</div>
</div>
<edit ref="editOrderTableDialog" @complete="loadOrderTableList" />
</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 { getOrderTableList, deleteOrderTable } from '@/app/api/order_table'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/order_table/components/order-table-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let orderTableTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"payment_id":"",
"order_status":"",
"payment_type":"",
"order_amount":"",
"course_id":"",
"class_id":"",
"staff_id":"",
"resource_id":"",
"after_sales_status":"",
"after_sales_reason":"",
"after_sales_time":"",
"payment_time":"",
"subscription_payment_time":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取订单列表
*/
const loadOrderTableList = (page: number = 1) => {
orderTableTable.loading = true
orderTableTable.page = page
getOrderTableList({
page: orderTableTable.page,
limit: orderTableTable.limit,
...orderTableTable.searchParam
}).then(res => {
orderTableTable.loading = false
orderTableTable.data = res.data.data
orderTableTable.total = res.data.total
}).catch(() => {
orderTableTable.loading = false
})
}
loadOrderTableList()
const editOrderTableDialog: Record<string, any> | null = ref(null)
/**
* 添加订单
*/
const addEvent = () => {
editOrderTableDialog.value.setFormData()
editOrderTableDialog.value.showDialog = true
}
/**
* 编辑订单
* @param data
*/
const editEvent = (data: any) => {
editOrderTableDialog.value.setFormData(data)
editOrderTableDialog.value.showDialog = true
}
/**
* 删除订单
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('orderTableDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteOrderTable(id).then(() => {
loadOrderTableList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadOrderTableList()
}
</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>

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

@ -0,0 +1,203 @@
<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-form-item :label="t('staffId')" prop="staff_id">
<el-input v-model="formData.staff_id" clearable :placeholder="t('staffIdPlaceholder')" class="input-width" />
</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-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>
<el-form-item :label="t('performanceType')" prop="performance_type">
<el-input v-model="formData.performance_type" clearable :placeholder="t('performanceTypePlaceholder')" class="input-width" />
</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-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>
<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 { addPerformanceRecords, editPerformanceRecords, getPerformanceRecordsInfo } from '@/app/api/performance_records'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
staff_id: '',
resource_id: '',
order_id: '',
order_status: '',
performance_type: '',
performance_value: '',
remarks: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
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' },
]
,
performance_value: [
{ required: true, message: t('performanceValuePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editPerformanceRecords : addPerformanceRecords
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getPerformanceRecordsInfo(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>

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

@ -0,0 +1,195 @@
<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('addPerformanceRecords') }}
</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-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-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status">
<el-input v-model="performanceRecordsTable.searchParam.order_status" :placeholder="t('orderStatusPlaceholder')" />
</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>
<el-form-item>
<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">
<template #empty>
<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="resource_id" :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 prop="order_status" :label="t('orderStatus')" min-width="120" :show-overflow-tooltip="true"/>
<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="remarks" :label="t('remarks')" 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>
</template>
</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" />
</div>
</div>
<edit ref="editPerformanceRecordsDialog" @complete="loadPerformanceRecordsList" />
</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 { getPerformanceRecordsList, deletePerformanceRecords } from '@/app/api/performance_records'
import { img } from '@/utils/common'
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;
let performanceRecordsTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"staff_id":"",
"resource_id":"",
"order_id":"",
"order_status":"",
"performance_type":"",
"performance_value":"",
"remarks":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取绩效记录列表
*/
const loadPerformanceRecordsList = (page: number = 1) => {
performanceRecordsTable.loading = true
performanceRecordsTable.page = page
getPerformanceRecordsList({
page: performanceRecordsTable.page,
limit: performanceRecordsTable.limit,
...performanceRecordsTable.searchParam
}).then(res => {
performanceRecordsTable.loading = false
performanceRecordsTable.data = res.data.data
performanceRecordsTable.total = res.data.total
}).catch(() => {
performanceRecordsTable.loading = false
})
}
loadPerformanceRecordsList()
const editPerformanceRecordsDialog: Record<string, any> | null = ref(null)
/**
* 添加绩效记录
*/
const addEvent = () => {
editPerformanceRecordsDialog.value.setFormData()
editPerformanceRecordsDialog.value.showDialog = true
}
/**
* 编辑绩效记录
* @param data
*/
const editEvent = (data: any) => {
editPerformanceRecordsDialog.value.setFormData(data)
editPerformanceRecordsDialog.value.showDialog = true
}
/**
* 删除绩效记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('performanceRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deletePerformanceRecords(id).then(() => {
loadPerformanceRecordsList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadPerformanceRecordsList()
}
</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>

183
admin/src/app/views/person_course_schedule/components/person-course-schedule-edit.vue

@ -0,0 +1,183 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updatePersonCourseSchedule') : t('addPersonCourseSchedule')" 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('personId')" prop="person_id">
<el-input v-model="formData.person_id" clearable :placeholder="t('personIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('personType')" prop="person_type">
<el-input v-model="formData.person_type" clearable :placeholder="t('personTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('scheduleId')" prop="schedule_id">
<el-input v-model="formData.schedule_id" clearable :placeholder="t('scheduleIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('courseDate')" prop="course_date">
<el-input v-model="formData.course_date" clearable :placeholder="t('courseDatePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('timeSlot')" prop="time_slot">
<el-input v-model="formData.time_slot" clearable :placeholder="t('timeSlotPlaceholder')" 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>
</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 { addPersonCourseSchedule, editPersonCourseSchedule, getPersonCourseScheduleInfo } from '@/app/api/person_course_schedule'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
person_id: '',
person_type: '',
schedule_id: '',
course_date: '',
time_slot: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
person_id: [
{ required: true, message: t('personIdPlaceholder'), trigger: 'blur' },
]
,
person_type: [
{ required: true, message: t('personTypePlaceholder'), trigger: 'blur' },
]
,
schedule_id: [
{ required: true, message: t('scheduleIdPlaceholder'), trigger: 'blur' },
]
,
course_date: [
{ required: true, message: t('courseDatePlaceholder'), trigger: 'blur' },
]
,
time_slot: [
{ required: true, message: t('timeSlotPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editPersonCourseSchedule : addPersonCourseSchedule
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getPersonCourseScheduleInfo(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>

183
admin/src/app/views/person_course_schedule/person_course_schedule.vue

@ -0,0 +1,183 @@
<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('addPersonCourseSchedule') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="personCourseScheduleTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('personId')" prop="person_id">
<el-input v-model="personCourseScheduleTable.searchParam.person_id" :placeholder="t('personIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('personType')" prop="person_type">
<el-input v-model="personCourseScheduleTable.searchParam.person_type" :placeholder="t('personTypePlaceholder')" />
</el-form-item>
<el-form-item :label="t('scheduleId')" prop="schedule_id">
<el-input v-model="personCourseScheduleTable.searchParam.schedule_id" :placeholder="t('scheduleIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('courseDate')" prop="course_date">
<el-input v-model="personCourseScheduleTable.searchParam.course_date" :placeholder="t('courseDatePlaceholder')" />
</el-form-item>
<el-form-item :label="t('timeSlot')" prop="time_slot">
<el-input v-model="personCourseScheduleTable.searchParam.time_slot" :placeholder="t('timeSlotPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadPersonCourseScheduleList()">{{ 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="personCourseScheduleTable.data" size="large" v-loading="personCourseScheduleTable.loading">
<template #empty>
<span>{{ !personCourseScheduleTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="person_id" :label="t('personId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="person_type" :label="t('personType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="schedule_id" :label="t('scheduleId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="course_date" :label="t('courseDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="time_slot" :label="t('timeSlot')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="personCourseScheduleTable.page" v-model:page-size="personCourseScheduleTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="personCourseScheduleTable.total"
@size-change="loadPersonCourseScheduleList()" @current-change="loadPersonCourseScheduleList" />
</div>
</div>
<edit ref="editPersonCourseScheduleDialog" @complete="loadPersonCourseScheduleList" />
</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 { getPersonCourseScheduleList, deletePersonCourseSchedule } from '@/app/api/person_course_schedule'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/person_course_schedule/components/person-course-schedule-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let personCourseScheduleTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"person_id":"",
"person_type":"",
"schedule_id":"",
"course_date":"",
"time_slot":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取人员与课程安排关系列表
*/
const loadPersonCourseScheduleList = (page: number = 1) => {
personCourseScheduleTable.loading = true
personCourseScheduleTable.page = page
getPersonCourseScheduleList({
page: personCourseScheduleTable.page,
limit: personCourseScheduleTable.limit,
...personCourseScheduleTable.searchParam
}).then(res => {
personCourseScheduleTable.loading = false
personCourseScheduleTable.data = res.data.data
personCourseScheduleTable.total = res.data.total
}).catch(() => {
personCourseScheduleTable.loading = false
})
}
loadPersonCourseScheduleList()
const editPersonCourseScheduleDialog: Record<string, any> | null = ref(null)
/**
* 添加人员与课程安排关系
*/
const addEvent = () => {
editPersonCourseScheduleDialog.value.setFormData()
editPersonCourseScheduleDialog.value.showDialog = true
}
/**
* 编辑人员与课程安排关系
* @param data
*/
const editEvent = (data: any) => {
editPersonCourseScheduleDialog.value.setFormData(data)
editPersonCourseScheduleDialog.value.showDialog = true
}
/**
* 删除人员与课程安排关系
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('personCourseScheduleDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deletePersonCourseSchedule(id).then(() => {
loadPersonCourseScheduleList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadPersonCourseScheduleList()
}
</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>

303
admin/src/app/views/physical_test/components/physical-test-edit.vue

@ -0,0 +1,303 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updatePhysicalTest') : t('addPhysicalTest')" 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('resourceId')" prop="resource_id">
<el-input v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('studentId')" prop="student_id">
<el-input v-model="formData.student_id" clearable :placeholder="t('studentIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('height')" prop="height">
<el-input v-model="formData.height" clearable :placeholder="t('heightPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('weight')" prop="weight">
<el-input v-model="formData.weight" clearable :placeholder="t('weightPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('coachId')" prop="coach_id">
<el-input v-model="formData.coach_id" clearable :placeholder="t('coachIdPlaceholder')" 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>
<el-form-item :label="t('seatedForwardBend')" >
<el-input v-model="formData.seated_forward_bend" clearable :placeholder="t('seatedForwardBendPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sitUps')" >
<el-input v-model="formData.sit_ups" clearable :placeholder="t('sitUpsPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('pushUps')" >
<el-input v-model="formData.push_ups" clearable :placeholder="t('pushUpsPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('flamingoBalance')" >
<el-input v-model="formData.flamingo_balance" clearable :placeholder="t('flamingoBalancePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('thirtySecJump')" >
<el-input v-model="formData.thirty_sec_jump" clearable :placeholder="t('thirtySecJumpPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('standingLongJump')" >
<el-input v-model="formData.standing_long_jump" clearable :placeholder="t('standingLongJumpPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('agilityRun')" >
<el-input v-model="formData.agility_run" clearable :placeholder="t('agilityRunPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('balanceBeam')" >
<el-input v-model="formData.balance_beam" clearable :placeholder="t('balanceBeamPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('tennisThrow')" >
<el-input v-model="formData.tennis_throw" clearable :placeholder="t('tennisThrowPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('tenMeterShuttleRun')" >
<el-input v-model="formData.ten_meter_shuttle_run" clearable :placeholder="t('tenMeterShuttleRunPlaceholder')" 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>
</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 { addPhysicalTest, editPhysicalTest, getPhysicalTestInfo } from '@/app/api/physical_test'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
resource_id: '',
student_id: '',
height: '',
weight: '',
coach_id: '',
created_at: '',
updated_at: '',
seated_forward_bend: '',
sit_ups: '',
push_ups: '',
flamingo_balance: '',
thirty_sec_jump: '',
standing_long_jump: '',
agility_run: '',
balance_beam: '',
tennis_throw: '',
ten_meter_shuttle_run: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
student_id: [
{ required: true, message: t('studentIdPlaceholder'), trigger: 'blur' },
]
,
height: [
{ required: true, message: t('heightPlaceholder'), trigger: 'blur' },
]
,
weight: [
{ required: true, message: t('weightPlaceholder'), trigger: 'blur' },
]
,
coach_id: [
{ required: true, message: t('coachIdPlaceholder'), trigger: 'blur' },
]
,
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' },
]
,
updated_at: [
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
]
,
seated_forward_bend: [
{ required: true, message: t('seatedForwardBendPlaceholder'), trigger: 'blur' },
]
,
sit_ups: [
{ required: true, message: t('sitUpsPlaceholder'), trigger: 'blur' },
]
,
push_ups: [
{ required: true, message: t('pushUpsPlaceholder'), trigger: 'blur' },
]
,
flamingo_balance: [
{ required: true, message: t('flamingoBalancePlaceholder'), trigger: 'blur' },
]
,
thirty_sec_jump: [
{ required: true, message: t('thirtySecJumpPlaceholder'), trigger: 'blur' },
]
,
standing_long_jump: [
{ required: true, message: t('standingLongJumpPlaceholder'), trigger: 'blur' },
]
,
agility_run: [
{ required: true, message: t('agilityRunPlaceholder'), trigger: 'blur' },
]
,
balance_beam: [
{ required: true, message: t('balanceBeamPlaceholder'), trigger: 'blur' },
]
,
tennis_throw: [
{ required: true, message: t('tennisThrowPlaceholder'), trigger: 'blur' },
]
,
ten_meter_shuttle_run: [
{ required: true, message: t('tenMeterShuttleRunPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editPhysicalTest : addPhysicalTest
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getPhysicalTestInfo(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>

255
admin/src/app/views/physical_test/physical_test.vue

@ -0,0 +1,255 @@
<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('addPhysicalTest') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="physicalTestTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input v-model="physicalTestTable.searchParam.resource_id" :placeholder="t('resourceIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('studentId')" prop="student_id">
<el-input v-model="physicalTestTable.searchParam.student_id" :placeholder="t('studentIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('height')" prop="height">
<el-input v-model="physicalTestTable.searchParam.height" :placeholder="t('heightPlaceholder')" />
</el-form-item>
<el-form-item :label="t('weight')" prop="weight">
<el-input v-model="physicalTestTable.searchParam.weight" :placeholder="t('weightPlaceholder')" />
</el-form-item>
<el-form-item :label="t('coachId')" prop="coach_id">
<el-input v-model="physicalTestTable.searchParam.coach_id" :placeholder="t('coachIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input v-model="physicalTestTable.searchParam.created_at" :placeholder="t('createdAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input v-model="physicalTestTable.searchParam.updated_at" :placeholder="t('updatedAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('seatedForwardBend')" prop="seated_forward_bend">
<el-input v-model="physicalTestTable.searchParam.seated_forward_bend" :placeholder="t('seatedForwardBendPlaceholder')" />
</el-form-item>
<el-form-item :label="t('sitUps')" prop="sit_ups">
<el-input v-model="physicalTestTable.searchParam.sit_ups" :placeholder="t('sitUpsPlaceholder')" />
</el-form-item>
<el-form-item :label="t('pushUps')" prop="push_ups">
<el-input v-model="physicalTestTable.searchParam.push_ups" :placeholder="t('pushUpsPlaceholder')" />
</el-form-item>
<el-form-item :label="t('flamingoBalance')" prop="flamingo_balance">
<el-input v-model="physicalTestTable.searchParam.flamingo_balance" :placeholder="t('flamingoBalancePlaceholder')" />
</el-form-item>
<el-form-item :label="t('thirtySecJump')" prop="thirty_sec_jump">
<el-input v-model="physicalTestTable.searchParam.thirty_sec_jump" :placeholder="t('thirtySecJumpPlaceholder')" />
</el-form-item>
<el-form-item :label="t('standingLongJump')" prop="standing_long_jump">
<el-input v-model="physicalTestTable.searchParam.standing_long_jump" :placeholder="t('standingLongJumpPlaceholder')" />
</el-form-item>
<el-form-item :label="t('agilityRun')" prop="agility_run">
<el-input v-model="physicalTestTable.searchParam.agility_run" :placeholder="t('agilityRunPlaceholder')" />
</el-form-item>
<el-form-item :label="t('balanceBeam')" prop="balance_beam">
<el-input v-model="physicalTestTable.searchParam.balance_beam" :placeholder="t('balanceBeamPlaceholder')" />
</el-form-item>
<el-form-item :label="t('tennisThrow')" prop="tennis_throw">
<el-input v-model="physicalTestTable.searchParam.tennis_throw" :placeholder="t('tennisThrowPlaceholder')" />
</el-form-item>
<el-form-item :label="t('tenMeterShuttleRun')" prop="ten_meter_shuttle_run">
<el-input v-model="physicalTestTable.searchParam.ten_meter_shuttle_run" :placeholder="t('tenMeterShuttleRunPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadPhysicalTestList()">{{ 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="physicalTestTable.data" size="large" v-loading="physicalTestTable.loading">
<template #empty>
<span>{{ !physicalTestTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="resource_id" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="student_id" :label="t('studentId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="height" :label="t('height')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="weight" :label="t('weight')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="coach_id" :label="t('coachId')" 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="seated_forward_bend" :label="t('seatedForwardBend')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="sit_ups" :label="t('sitUps')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="push_ups" :label="t('pushUps')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="flamingo_balance" :label="t('flamingoBalance')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="thirty_sec_jump" :label="t('thirtySecJump')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="standing_long_jump" :label="t('standingLongJump')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="agility_run" :label="t('agilityRun')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="balance_beam" :label="t('balanceBeam')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="tennis_throw" :label="t('tennisThrow')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="ten_meter_shuttle_run" :label="t('tenMeterShuttleRun')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="physicalTestTable.page" v-model:page-size="physicalTestTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="physicalTestTable.total"
@size-change="loadPhysicalTestList()" @current-change="loadPhysicalTestList" />
</div>
</div>
<edit ref="editPhysicalTestDialog" @complete="loadPhysicalTestList" />
</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 { getPhysicalTestList, deletePhysicalTest } from '@/app/api/physical_test'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/physical_test/components/physical-test-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let physicalTestTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"resource_id":"",
"student_id":"",
"height":"",
"weight":"",
"coach_id":"",
"created_at":"",
"updated_at":"",
"seated_forward_bend":"",
"sit_ups":"",
"push_ups":"",
"flamingo_balance":"",
"thirty_sec_jump":"",
"standing_long_jump":"",
"agility_run":"",
"balance_beam":"",
"tennis_throw":"",
"ten_meter_shuttle_run":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取体测列表
*/
const loadPhysicalTestList = (page: number = 1) => {
physicalTestTable.loading = true
physicalTestTable.page = page
getPhysicalTestList({
page: physicalTestTable.page,
limit: physicalTestTable.limit,
...physicalTestTable.searchParam
}).then(res => {
physicalTestTable.loading = false
physicalTestTable.data = res.data.data
physicalTestTable.total = res.data.total
}).catch(() => {
physicalTestTable.loading = false
})
}
loadPhysicalTestList()
const editPhysicalTestDialog: Record<string, any> | null = ref(null)
/**
* 添加体测
*/
const addEvent = () => {
editPhysicalTestDialog.value.setFormData()
editPhysicalTestDialog.value.showDialog = true
}
/**
* 编辑体测
* @param data
*/
const editEvent = (data: any) => {
editPhysicalTestDialog.value.setFormData(data)
editPhysicalTestDialog.value.showDialog = true
}
/**
* 删除体测
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('physicalTestDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deletePhysicalTest(id).then(() => {
loadPhysicalTestList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadPhysicalTestList()
}
</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>

193
admin/src/app/views/reimbursement/components/reimbursement-edit.vue

@ -0,0 +1,193 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateReimbursement') : t('addReimbursement')" 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('applicantId')" prop="applicant_id">
<el-input v-model="formData.applicant_id" clearable :placeholder="t('applicantIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('amount')" prop="amount">
<el-input v-model="formData.amount" clearable :placeholder="t('amountPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input v-model="formData.description" clearable :placeholder="t('descriptionPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('receiptUrl')" >
<el-input v-model="formData.receipt_url" clearable :placeholder="t('receiptUrlPlaceholder')" class="input-width" />
</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>
<el-form-item :label="t('processId')" prop="process_id">
<el-input v-model="formData.process_id" clearable :placeholder="t('processIdPlaceholder')" 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>
</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 { addReimbursement, editReimbursement, getReimbursementInfo } from '@/app/api/reimbursement'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
applicant_id: '',
amount: '',
description: '',
receipt_url: '',
status: '',
process_id: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
applicant_id: [
{ required: true, message: t('applicantIdPlaceholder'), trigger: 'blur' },
]
,
amount: [
{ required: true, message: t('amountPlaceholder'), trigger: 'blur' },
]
,
description: [
{ required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
]
,
receipt_url: [
{ required: true, message: t('receiptUrlPlaceholder'), trigger: 'blur' },
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
process_id: [
{ required: true, message: t('processIdPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editReimbursement : addReimbursement
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getReimbursementInfo(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>

189
admin/src/app/views/reimbursement/reimbursement.vue

@ -0,0 +1,189 @@
<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('addReimbursement') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="reimbursementTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('applicantId')" prop="applicant_id">
<el-input v-model="reimbursementTable.searchParam.applicant_id" :placeholder="t('applicantIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('amount')" prop="amount">
<el-input v-model="reimbursementTable.searchParam.amount" :placeholder="t('amountPlaceholder')" />
</el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input v-model="reimbursementTable.searchParam.description" :placeholder="t('descriptionPlaceholder')" />
</el-form-item>
<el-form-item :label="t('receiptUrl')" prop="receipt_url">
<el-input v-model="reimbursementTable.searchParam.receipt_url" :placeholder="t('receiptUrlPlaceholder')" />
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-input v-model="reimbursementTable.searchParam.status" :placeholder="t('statusPlaceholder')" />
</el-form-item>
<el-form-item :label="t('processId')" prop="process_id">
<el-input v-model="reimbursementTable.searchParam.process_id" :placeholder="t('processIdPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadReimbursementList()">{{ 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="reimbursementTable.data" size="large" v-loading="reimbursementTable.loading">
<template #empty>
<span>{{ !reimbursementTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="applicant_id" :label="t('applicantId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="amount" :label="t('amount')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="description" :label="t('description')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="receipt_url" :label="t('receiptUrl')" 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="process_id" :label="t('processId')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="reimbursementTable.page" v-model:page-size="reimbursementTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="reimbursementTable.total"
@size-change="loadReimbursementList()" @current-change="loadReimbursementList" />
</div>
</div>
<edit ref="editReimbursementDialog" @complete="loadReimbursementList" />
</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 { getReimbursementList, deleteReimbursement } from '@/app/api/reimbursement'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/reimbursement/components/reimbursement-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let reimbursementTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"applicant_id":"",
"amount":"",
"description":"",
"receipt_url":"",
"status":"",
"process_id":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取报销记录列表
*/
const loadReimbursementList = (page: number = 1) => {
reimbursementTable.loading = true
reimbursementTable.page = page
getReimbursementList({
page: reimbursementTable.page,
limit: reimbursementTable.limit,
...reimbursementTable.searchParam
}).then(res => {
reimbursementTable.loading = false
reimbursementTable.data = res.data.data
reimbursementTable.total = res.data.total
}).catch(() => {
reimbursementTable.loading = false
})
}
loadReimbursementList()
const editReimbursementDialog: Record<string, any> | null = ref(null)
/**
* 添加报销记录
*/
const addEvent = () => {
editReimbursementDialog.value.setFormData()
editReimbursementDialog.value.showDialog = true
}
/**
* 编辑报销记录
* @param data
*/
const editEvent = (data: any) => {
editReimbursementDialog.value.setFormData(data)
editReimbursementDialog.value.showDialog = true
}
/**
* 删除报销记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('reimbursementDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteReimbursement(id).then(() => {
loadReimbursementList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadReimbursementList()
}
</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>

183
admin/src/app/views/resource_sharing/components/resource-sharing-edit.vue

@ -0,0 +1,183 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateResourceSharing') : t('addResourceSharing')" 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('resourceId')" prop="resource_id">
<el-input v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('userId')" >
<el-input v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('roleId')" >
<el-input v-model="formData.role_id" clearable :placeholder="t('roleIdPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sharedBy')" prop="shared_by">
<el-input v-model="formData.shared_by" clearable :placeholder="t('sharedByPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sharedAt')" >
<el-input v-model="formData.shared_at" clearable :placeholder="t('sharedAtPlaceholder')" 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>
</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 { addResourceSharing, editResourceSharing, getResourceSharingInfo } from '@/app/api/resource_sharing'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
resource_id: '',
user_id: '',
role_id: '',
shared_by: '',
shared_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
]
,
role_id: [
{ required: true, message: t('roleIdPlaceholder'), trigger: 'blur' },
]
,
shared_by: [
{ required: true, message: t('sharedByPlaceholder'), trigger: 'blur' },
]
,
shared_at: [
{ required: true, message: t('sharedAtPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editResourceSharing : addResourceSharing
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
})
}
})
}
//
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getResourceSharingInfo(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>

183
admin/src/app/views/resource_sharing/resource_sharing.vue

@ -0,0 +1,183 @@
<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('addResourceSharing') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="resourceSharingTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input v-model="resourceSharingTable.searchParam.resource_id" :placeholder="t('resourceIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('userId')" prop="user_id">
<el-input v-model="resourceSharingTable.searchParam.user_id" :placeholder="t('userIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<el-input v-model="resourceSharingTable.searchParam.role_id" :placeholder="t('roleIdPlaceholder')" />
</el-form-item>
<el-form-item :label="t('sharedBy')" prop="shared_by">
<el-input v-model="resourceSharingTable.searchParam.shared_by" :placeholder="t('sharedByPlaceholder')" />
</el-form-item>
<el-form-item :label="t('sharedAt')" prop="shared_at">
<el-input v-model="resourceSharingTable.searchParam.shared_at" :placeholder="t('sharedAtPlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadResourceSharingList()">{{ 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="resourceSharingTable.data" size="large" v-loading="resourceSharingTable.loading">
<template #empty>
<span>{{ !resourceSharingTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="resource_id" :label="t('resourceId')" 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="role_id" :label="t('roleId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="shared_by" :label="t('sharedBy')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="shared_at" :label="t('sharedAt')" 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>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="resourceSharingTable.page" v-model:page-size="resourceSharingTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="resourceSharingTable.total"
@size-change="loadResourceSharingList()" @current-change="loadResourceSharingList" />
</div>
</div>
<edit ref="editResourceSharingDialog" @complete="loadResourceSharingList" />
</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 { getResourceSharingList, deleteResourceSharing } from '@/app/api/resource_sharing'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/resource_sharing/components/resource-sharing-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let resourceSharingTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"resource_id":"",
"user_id":"",
"role_id":"",
"shared_by":"",
"shared_at":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取资源共享列表
*/
const loadResourceSharingList = (page: number = 1) => {
resourceSharingTable.loading = true
resourceSharingTable.page = page
getResourceSharingList({
page: resourceSharingTable.page,
limit: resourceSharingTable.limit,
...resourceSharingTable.searchParam
}).then(res => {
resourceSharingTable.loading = false
resourceSharingTable.data = res.data.data
resourceSharingTable.total = res.data.total
}).catch(() => {
resourceSharingTable.loading = false
})
}
loadResourceSharingList()
const editResourceSharingDialog: Record<string, any> | null = ref(null)
/**
* 添加资源共享
*/
const addEvent = () => {
editResourceSharingDialog.value.setFormData()
editResourceSharingDialog.value.showDialog = true
}
/**
* 编辑资源共享
* @param data
*/
const editEvent = (data: any) => {
editResourceSharingDialog.value.setFormData(data)
editResourceSharingDialog.value.showDialog = true
}
/**
* 删除资源共享
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('resourceSharingDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteResourceSharing(id).then(() => {
loadResourceSharingList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadResourceSharingList()
}
</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>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save