Browse Source

Merge remote-tracking branch 'origin/master'

wangzeyan
liutong 11 months ago
parent
commit
19d9b2c949
  1. 2
      .gitignore
  2. 8
      admin/.env.development
  3. 9
      admin/.env.production
  4. 3
      admin/.eslintignore
  5. 39
      admin/.eslintrc.js
  6. 4
      admin/.gitignore
  7. 7
      admin/.prettierignore
  8. 11
      admin/.prettierrc
  9. 5
      admin/auto-imports.d.ts
  10. 85
      admin/components.d.ts
  11. 52
      admin/src/app/api/aaaaaaaaaaa.ts
  12. 59
      admin/src/app/api/attendance.ts
  13. 59
      admin/src/app/api/campus.ts
  14. 73
      admin/src/app/api/campus_person_role.ts
  15. 66
      admin/src/app/api/classroom.ts
  16. 60
      admin/src/app/api/communication_records.ts
  17. 59
      admin/src/app/api/contract.ts
  18. 59
      admin/src/app/api/course.ts
  19. 59
      admin/src/app/api/course_schedule.ts
  20. 65
      admin/src/app/api/customer_resource_changes.ts
  21. 60
      admin/src/app/api/customer_resources.ts
  22. 59
      admin/src/app/api/exam_answers.ts
  23. 59
      admin/src/app/api/exam_papers.ts
  24. 59
      admin/src/app/api/exam_questions.ts
  25. 59
      admin/src/app/api/exam_records.ts
  26. 67
      admin/src/app/api/market_performance.ts
  27. 59
      admin/src/app/api/order_table.ts
  28. 60
      admin/src/app/api/performance_records.ts
  29. 62
      admin/src/app/api/person_course_schedule.ts
  30. 59
      admin/src/app/api/personnel.ts
  31. 59
      admin/src/app/api/physical_test.ts
  32. 59
      admin/src/app/api/reimbursement.ts
  33. 59
      admin/src/app/api/resource_sharing.ts
  34. 59
      admin/src/app/api/salary.ts
  35. 59
      admin/src/app/api/service.ts
  36. 58
      admin/src/app/api/six_speed.ts
  37. 72
      admin/src/app/api/six_speed_modification_log.ts
  38. 59
      admin/src/app/api/stat_hour.ts
  39. 60
      admin/src/app/api/student_course_usage.ts
  40. 59
      admin/src/app/api/student_courses.ts
  41. 12
      admin/src/app/api/sys.ts
  42. 59
      admin/src/app/api/user_feedback.ts
  43. 60
      admin/src/app/api/venue.ts
  44. 29
      admin/src/app/lang/zh-cn/attendance.attendance.json
  45. 20
      admin/src/app/lang/zh-cn/campus.campus.json
  46. 17
      admin/src/app/lang/zh-cn/campus_person_role.campus_person_role.json
  47. 27
      admin/src/app/lang/zh-cn/class.class.json
  48. 27
      admin/src/app/lang/zh-cn/classroom.classroom.json
  49. 31
      admin/src/app/lang/zh-cn/communication_records.communication_records.json
  50. 25
      admin/src/app/lang/zh-cn/contract.contract.json
  51. 27
      admin/src/app/lang/zh-cn/course.course.json
  52. 29
      admin/src/app/lang/zh-cn/course_schedule.course_schedule.json
  53. 21
      admin/src/app/lang/zh-cn/customer_resource_changes.customer_resource_changes.json
  54. 38
      admin/src/app/lang/zh-cn/customer_resources.customer_resources.json
  55. 19
      admin/src/app/lang/zh-cn/exam_answers.exam_answers.json
  56. 15
      admin/src/app/lang/zh-cn/exam_papers.exam_papers.json
  57. 33
      admin/src/app/lang/zh-cn/exam_questions.exam_questions.json
  58. 29
      admin/src/app/lang/zh-cn/exam_questions.exam_questions_edit.json
  59. 23
      admin/src/app/lang/zh-cn/exam_records.exam_records.json
  60. 13
      admin/src/app/lang/zh-cn/market_performance.market_performance.json
  61. 35
      admin/src/app/lang/zh-cn/order_table.order_table.json
  62. 23
      admin/src/app/lang/zh-cn/performance_records.performance_records.json
  63. 19
      admin/src/app/lang/zh-cn/person_course_schedule.person_course_schedule.json
  64. 35
      admin/src/app/lang/zh-cn/personnel.personnel.json
  65. 43
      admin/src/app/lang/zh-cn/physical_test.physical_test.json
  66. 21
      admin/src/app/lang/zh-cn/reimbursement.reimbursement.json
  67. 19
      admin/src/app/lang/zh-cn/resource_sharing.resource_sharing.json
  68. 33
      admin/src/app/lang/zh-cn/salary.salary.json
  69. 29
      admin/src/app/lang/zh-cn/service.service.json
  70. 29
      admin/src/app/lang/zh-cn/six_speed.six_speed.json
  71. 19
      admin/src/app/lang/zh-cn/six_speed_modification_log.six_speed_modification_log.json
  72. 73
      admin/src/app/lang/zh-cn/stat_hour.stat_hour.json
  73. 15
      admin/src/app/lang/zh-cn/student_course_usage.student_course_usage.json
  74. 21
      admin/src/app/lang/zh-cn/student_courses.student_courses.json
  75. 15
      admin/src/app/lang/zh-cn/user_feedback.user_feedback.json
  76. 23
      admin/src/app/lang/zh-cn/venue.venue.json
  77. 165
      admin/src/app/views/aaaaaaaaaaa/aaaaaaaaaaa.vue
  78. 163
      admin/src/app/views/aaaaaaaaaaa/components/aaaaaaaaaaa-edit.vue
  79. 318
      admin/src/app/views/attendance/attendance.vue
  80. 296
      admin/src/app/views/attendance/components/attendance-edit.vue
  81. 253
      admin/src/app/views/campus/campus.vue
  82. 270
      admin/src/app/views/campus/components/campus-edit.vue
  83. 306
      admin/src/app/views/campus_person_role/campus_person_role.vue
  84. 268
      admin/src/app/views/campus_person_role/components/campus-person-role-edit.vue
  85. 280
      admin/src/app/views/classroom/classroom.vue
  86. 287
      admin/src/app/views/classroom/components/classroom-edit.vue
  87. 351
      admin/src/app/views/communication_records/communication_records.vue
  88. 322
      admin/src/app/views/communication_records/components/communication-records-edit.vue
  89. 274
      admin/src/app/views/contract/components/contract-edit.vue
  90. 290
      admin/src/app/views/contract/contract.vue
  91. 290
      admin/src/app/views/course/components/course-edit.vue
  92. 307
      admin/src/app/views/course/course.vue
  93. 296
      admin/src/app/views/course_schedule/components/course-schedule-edit.vue
  94. 326
      admin/src/app/views/course_schedule/course_schedule.vue
  95. 253
      admin/src/app/views/customer_resource_changes/components/customer-resource-changes-edit.vue
  96. 277
      admin/src/app/views/customer_resource_changes/customer_resource_changes.vue
  97. 574
      admin/src/app/views/customer_resources/components/customer-resources-edit.vue
  98. 231
      admin/src/app/views/customer_resources/customer_resources.vue
  99. 223
      admin/src/app/views/exam_answers/components/exam-answers-edit.vue
  100. 248
      admin/src/app/views/exam_answers/exam_answers.vue

2
.gitignore

@ -7,5 +7,3 @@
/.idea /.idea
/niucloud/runtime /niucloud/runtime
/niucloud/vendor /niucloud/vendor
/niucloud/config
config

8
admin/.env.development

@ -1,8 +0,0 @@
# api请求地址
VITE_APP_BASE_URL='http://146.56.228.75:20024/adminapi/'
# VITE_APP_BASE_URL='https://zh.hnhbty.cn/adminapi/'
# 图片服务器地址
VITE_IMG_DOMAIN=''
# 请求时header中token的参数名
VITE_REQUEST_HEADER_TOKEN_KEY='token'

9
admin/.env.production

@ -1,9 +0,0 @@
# api请求地址
VITE_APP_BASE_URL='http://146.56.228.75:20024/adminapi/'
# VITE_APP_BASE_URL='https://zh.hnhbty.cn/adminapi/'
# 图片服务器地址
VITE_IMG_DOMAIN=''
# 请求时header中token的参数名
VITE_REQUEST_HEADER_TOKEN_KEY='token'

3
admin/.eslintignore

@ -0,0 +1,3 @@
node_modules/
dist/
public/

39
admin/.eslintrc.js

@ -0,0 +1,39 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: false,
},
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended',
],
rules: {
// Vue 推荐规则
'vue/multi-word-component-names': 0,
'vue/require-default-prop': 0,
// TypeScript 常用规则
'@typescript-eslint/no-explicit-any': ['warn'],
'@typescript-eslint/no-unused-vars': ['error'],
// 缩进设置(可选)
indent: ['error', 2],
quotes: ['error', 'single'],
semi: ['error', 'never'],
},
}

4
admin/.gitignore

@ -22,3 +22,7 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.env.development
.env.production
auto-imports.d.ts
components.d.ts

7
admin/.prettierignore

@ -0,0 +1,7 @@
node_modules
dist
.env
*.md
*.png
*.jpg
*.ico

11
admin/.prettierrc

@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "auto"
}

5
admin/auto-imports.d.ts

@ -1,5 +0,0 @@
// Generated by 'unplugin-auto-import'
export {}
declare global {
const ElNotification: typeof import('element-plus/es')['ElNotification']
}

85
admin/components.d.ts

@ -1,85 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
Editor: typeof import('./src/components/editor/index.vue')['default']
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination']
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']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
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']
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']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default']
Icon: typeof import('./src/components/icon/index.vue')['default']
PopoverInput: typeof import('./src/components/popover-input/index.vue')['default']
RangeInput: typeof import('./src/components/range-input/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SelectArea: typeof import('./src/components/select-area/index.vue')['default']
SelectIcon: typeof import('./src/components/select-icon/index.vue')['default']
UploadAttachment: typeof import('./src/components/upload-attachment/index.vue')['default']
UploadFile: typeof import('./src/components/upload-file/index.vue')['default']
UploadImage: typeof import('./src/components/upload-image/index.vue')['default']
UploadVideo: typeof import('./src/components/upload-video/index.vue')['default']
Verify: typeof import('./src/components/verifition/Verify.vue')['default']
VerifyPoints: typeof import('./src/components/verifition/Verify/VerifyPoints.vue')['default']
VerifySlide: typeof import('./src/components/verifition/Verify/VerifySlide.vue')['default']
VideoPlayer: typeof import('./src/components/video-player/index.vue')['default']
WebLink: typeof import('./src/components/web-link/web-link.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

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

@ -0,0 +1,52 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- aaaaaaaaaaa
/**
*
* @param params
* @returns
*/
export function getAaaaaaaaaaaList(params: Record<string, any>) {
return request.get(`aaaaaaaaaaa/aaaaaaaaaaa`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getAaaaaaaaaaaInfo(id: number) {
return request.get(`aaaaaaaaaaa/aaaaaaaaaaa/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addAaaaaaaaaaa(params: Record<string, any>) {
return request.post('aaaaaaaaaaa/aaaaaaaaaaa', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editAaaaaaaaaaa(params: Record<string, any>) {
return request.put(`aaaaaaaaaaa/aaaaaaaaaaa/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteAaaaaaaaaaa(id: number) {
return request.delete(`aaaaaaaaaaa/aaaaaaaaaaa/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
// USER_CODE_END -- aaaaaaaaaaa

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

@ -0,0 +1,59 @@
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

59
admin/src/app/api/campus.ts

@ -0,0 +1,59 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- campus
/**
*
* @param params
* @returns
*/
export function getCampusList(params: Record<string, any>) {
return request.get(`campus/campus`, { params })
}
/**
*
* @param id id
* @returns
*/
export function getCampusInfo(id: number) {
return request.get(`campus/campus/${id}`)
}
/**
*
* @param params
* @returns
*/
export function addCampus(params: Record<string, any>) {
return request.post('campus/campus', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCampus(params: Record<string, any>) {
return request.put(`campus/campus/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
*
* @param id
* @returns
*/
export function deleteCampus(id: number) {
return request.delete(`campus/campus/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
// USER_CODE_END -- campus

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

@ -0,0 +1,73 @@
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,
})
}
export function getWithCampusList(params: Record<string, any>) {
return request.get('campus_person_role/campus_all', { params })
}
export function getWithPersonnelList(params: Record<string, any>) {
return request.get('campus_person_role/personnel_all', { params })
}
export function getWithSysRoleList(params: Record<string, any>) {
return request.get('campus_person_role/sys_role_all', { params })
}
export function getWithDepartmentsList(params: Record<string, any>) {
return request.get('campus_person_role/departments_all', { params })
}
// USER_CODE_END -- campus_person_role

66
admin/src/app/api/classroom.ts

@ -0,0 +1,66 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- class
/**
*
* @param params
* @returns
*/
export function getClassroomList(params: Record<string, any>) {
return request.get(`classroom/classroom`, { params })
}
/**
*
* @param id id
* @returns
*/
export function getClassroomInfo(id: number) {
return request.get(`classroom/classroom/${id}`)
}
/**
*
* @param params
* @returns
*/
export function addClassroom(params: Record<string, any>) {
return request.post('classroom/classroom', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
*
* @param id
* @param params
* @returns
*/
export function editClassroom(params: Record<string, any>) {
return request.put(`classroom/classroom/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
*
* @param id
* @returns
*/
export function deleteClassroom(id: number) {
return request.delete(`classroom/classroom/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
export function getWithCampusList(params: Record<string, any>) {
return request.get('classroom/campus_all', { params })
}
export function getWithPersonnelList(params: Record<string, any>) {
return request.get('classroom/personnel_all', { params })
}
// USER_CODE_END -- class

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

@ -0,0 +1,60 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,65 @@
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

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

@ -0,0 +1,60 @@
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 })
}
export function getWithPersonnelList(params: Record<string,any>){
return request.get('customer_resources/personnel_all', {params})
}export function getWithCampusList(params: Record<string,any>){
return request.get('customer_resources/campus_all', {params})
}
// USER_CODE_END -- customer_resources

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

67
admin/src/app/api/market_performance.ts

@ -0,0 +1,67 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- market_performance
/**
*
* @param params
* @returns
*/
export function getMarketPerformanceList(params: Record<string, any>) {
return request.get(`market_performance/market_performance`, { params })
}
/**
*
* @param id id
* @returns
*/
export function getMarketPerformanceInfo(id: number) {
return request.get(`market_performance/market_performance/${id}`)
}
/**
*
* @param params
* @returns
*/
export function addMarketPerformance(params: Record<string, any>) {
return request.post('market_performance/market_performance', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
*
* @param id
* @param params
* @returns
*/
export function editMarketPerformance(params: Record<string, any>) {
return request.put(
`market_performance/market_performance/${params.id}`,
params,
{ showErrorMessage: true, showSuccessMessage: true }
)
}
/**
*
* @param id
* @returns
*/
export function deleteMarketPerformance(id: number) {
return request.delete(`market_performance/market_performance/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
export function getWithPersonnelList(params: Record<string, any>) {
return request.get('market_performance/personnel_all', { params })
}
export function getWithCampusList(params: Record<string, any>) {
return request.get('market_performance/campus_all', { params })
}
// USER_CODE_END -- market_performance

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,60 @@
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

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

@ -0,0 +1,62 @@
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

59
admin/src/app/api/personnel.ts

@ -0,0 +1,59 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- personnel
/**
* -
* @param params
* @returns
*/
export function getPersonnelList(params: Record<string, any>) {
return request.get(`personnel/personnel`, { params })
}
/**
* -
* @param id -id
* @returns
*/
export function getPersonnelInfo(id: number) {
return request.get(`personnel/personnel/${id}`)
}
/**
* -
* @param params
* @returns
*/
export function addPersonnel(params: Record<string, any>) {
return request.post('personnel/personnel', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
* -
* @param id
* @param params
* @returns
*/
export function editPersonnel(params: Record<string, any>) {
return request.put(`personnel/personnel/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
/**
* -
* @param id
* @returns
*/
export function deletePersonnel(id: number) {
return request.delete(`personnel/personnel/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
}
// USER_CODE_END -- personnel

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,58 @@
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 })
}
export function getWithPersonnelList(params: Record<string,any>){
return request.get('six_speed/personnel_all', {params})
}export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('six_speed/customer_resources_all', {params})
}
// USER_CODE_END -- six_speed

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

@ -0,0 +1,72 @@
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 }
)
}
export function getWithCampusList(params: Record<string, any>) {
return request.get('six_speed_modification_log/campus_all', { params })
}
export function getWithPersonnelList(params: Record<string, any>) {
return request.get('six_speed_modification_log/personnel_all', { params })
}
// USER_CODE_END -- six_speed_modification_log

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,60 @@
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

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

@ -0,0 +1,59 @@
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

12
admin/src/app/api/sys.ts

@ -720,3 +720,15 @@ export function deleteExport(id: number) {
export function getInstallConfig() { export function getInstallConfig() {
return request.get('sys/install/config') return request.get('sys/install/config')
} }
//业绩配置
export function getYjpzConfig() {
return request.get('sys/get_yjpz_config')
}
export function yjpzConfig(params: Record<string, any>) {
return request.post(`sys/yjpz_config`, params)
}

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

@ -0,0 +1,59 @@
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

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

@ -0,0 +1,60 @@
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 })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('venue/campus_all', {params})
}
// 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": "请选择结束时间"
}

20
admin/src/app/lang/zh-cn/campus.campus.json

@ -0,0 +1,20 @@
{
"campusName": "校区名称",
"campusNamePlaceholder": "请输入校区名称",
"campusAddress": "校区地址",
"campusAddressPlaceholder": "请输入校区地址",
"campusPreviewImage": "校区banner",
"campusPreviewImagePlaceholder": "请选择图片",
"campusCoordinates": "校区位置",
"campusCoordinatesPlaceholder": "请选择校区位置",
"campusIntroduction": "校区介绍",
"campusIntroductionPlaceholder": "请输入校区介绍",
"campusStatus": "校区状态",
"campusStatusPlaceholder": "请输入校区状态",
"createTime": "校区创建时间",
"addCampus": "添加校区",
"updateCampus": "编辑校区",
"campusDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间"
}

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

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

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

@ -0,0 +1,27 @@
{
"campusId":"所属校区",
"campusIdPlaceholder":"全部",
"className":"场地名称",
"classNamePlaceholder":"请输入场地名称",
"headCoach":"主教练",
"headCoachPlaceholder":"全部",
"ageGroup":"授课年龄段",
"ageGroupPlaceholder":"请输入授课年龄段",
"classType":"场地类型",
"classTypePlaceholder":"请输入场地类型",
"assistantCoach":"助教",
"assistantCoachPlaceholder":"全部",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"status":"班级状态",
"statusPlaceholder":"请输入班级状态",
"sortOrder":"班级排序",
"sortOrderPlaceholder":"请输入班级排序",
"remarks":"班级备注",
"remarksPlaceholder":"请输入班级备注",
"addClass":"添加场地管理",
"updateClass":"编辑场地管理",
"classDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

@ -0,0 +1,27 @@
{
"campusId":"所属校区",
"campusIdPlaceholder":"全部",
"className":"班级名称",
"classNamePlaceholder":"请输入班级名称",
"headCoach":"主教练",
"headCoachPlaceholder":"全部",
"ageGroup":"授课年龄段",
"ageGroupPlaceholder":"请输入授课年龄段",
"classType":"班级类型",
"classTypePlaceholder":"请输入班级类型",
"assistantCoach":"助教",
"assistantCoachPlaceholder":"全部",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"status":"班级状态",
"statusPlaceholder":"请输入班级状态",
"sortOrder":"班级排序",
"sortOrderPlaceholder":"请输入班级排序",
"remarks":"班级备注",
"remarksPlaceholder":"请输入班级备注",
"addClassroom":"添加场地管理",
"updateClassroom":"编辑场地管理",
"classroomDeleteTips":"确定要删除该数据吗?",
"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": "请选择结束时间"
}

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

@ -0,0 +1,38 @@
{
"source":"来源",
"sourcePlaceholder":"请输入来源",
"sourceChannel":"来源渠道",
"sourceChannelPlaceholder":"请输入来源渠道",
"consultant":"顾问",
"name":"姓名",
"namePlaceholder":"请输入姓名",
"age":"年龄",
"agePlaceholder":"请输入年龄",
"gender":"性别",
"genderPlaceholder":"请输入性别",
"phoneNumber":"联系电话",
"phoneNumberPlaceholder":"请输入联系电话",
"demand":"需求",
"demandPlaceholder":"请输入需求",
"purchasingPower":"购买力",
"purchasingPowerPlaceholder":"请输入购买力",
"cognitiveIdea":"认知理念",
"cognitiveIdeaPlaceholder":"请输入认知理念",
"optionalClassTime":"可选上课时间",
"optionalClassTimePlaceholder":"请输入可选上课时间",
"distance":"距离",
"distancePlaceholder":"请输入距离",
"decisionMaker":"决策人",
"decisionMakerPlaceholder":"请输入决策人",
"initialIntent":"客户初步意向度",
"initialIntentPlaceholder":"请输入客户初步意向度",
"campus":"所属校区",
"campusPlaceholder":"请输入所属校区",
"status":"客户状态",
"statusPlaceholder":"请输入客户状态",
"addCustomerResources":"添加客户资源",
"updateCustomerResources":"编辑客户资源",
"customerResourcesDeleteTips":"确定要删除该数据吗?",
"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": "请选择结束时间"
}

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

@ -0,0 +1,13 @@
{
"personnelId": "人员",
"personnelIdPlaceholder": "请输入人员",
"campusId": "校区",
"campusIdPlaceholder": "全部",
"performanceAmount": "绩效金额",
"performanceAmountPlaceholder": "请输入绩效金额",
"addMarketPerformance": "添加市场绩效",
"updateMarketPerformance": "编辑市场绩效",
"marketPerformanceDeleteTips": "确定要删除该数据吗?",
"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": "请选择结束时间"
}

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

@ -0,0 +1,35 @@
{
"name": "姓名",
"namePlaceholder": "请输入姓名",
"gender": "性别",
"genderPlaceholder": "请输入性别",
"phone": "电话",
"phonePlaceholder": "请输入电话",
"address": "家庭住址",
"addressPlaceholder": "请输入家庭住址",
"nativePlace": "祖籍",
"nativePlacePlaceholder": "请输入祖籍",
"education": "学历",
"educationPlaceholder": "请输入学历",
"profile": "个人简介",
"profilePlaceholder": "请输入个人简介",
"emergencyContactPhone": "应急联系人电话",
"emergencyContactPhonePlaceholder": "请输入应急联系人电话",
"idCardFront": "身份证正面",
"idCardFrontPlaceholder": "请输入身份证正面",
"idCardBack": "身份证反面",
"idCardBackPlaceholder": "请输入身份证反面",
"employeeNumber": "员工编号",
"employeeNumberPlaceholder": "请输入员工编号",
"status": "员工状态",
"statusPlaceholder": "请输入员工状态",
"isSysUser": "是否登录系统",
"isSysUserPlaceholder": "请输入是否登录系统",
"createTime": "创建时间",
"createTimePlaceholder": "请输入创建时间",
"addPersonnel": "添加人员",
"updatePersonnel": "编辑人员",
"personnelDeleteTips": "确定要删除该数据吗?",
"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": "请选择结束时间"
}

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

@ -0,0 +1,29 @@
{
"purchasePower":"需求购买力",
"purchasePowerPlaceholder":"请输入需求购买力",
"conceptAwareness":"认知理念",
"conceptAwarenessPlaceholder":"请输入认知理念",
"preferredClassTime":"可选上课时间",
"preferredClassTimePlaceholder":"请输入可选上课时间",
"distance":"距离",
"distancePlaceholder":"请输入距离",
"communication":"沟通备注",
"communicationPlaceholder":"请输入沟通备注",
"promisedVisitTime":"承诺到访时间",
"promisedVisitTimePlaceholder":"请输入承诺到访时间",
"actualVisitTime":"实际到访时间",
"actualVisitTimePlaceholder":"请输入实际到访时间",
"callIntent":"电话后的意向程度",
"callIntentPlaceholder":"请输入电话后的意向程度",
"firstVisitStatus":"一访情况",
"firstVisitStatusPlaceholder":"请输入一访情况",
"secondVisitStatus":"二访情况",
"secondVisitStatusPlaceholder":"请输入二访情况",
"isClosed":"是否关单",
"isClosedPlaceholder":"请输入是否关单",
"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": "校区",
"campusIdPlaceholder": "全部",
"staffId": "人员",
"staffIdPlaceholder": "请输入人员",
"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": "请选择结束时间"
}

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

@ -0,0 +1,23 @@
{
"campusId":"校区",
"campusIdPlaceholder":"全部",
"venueName":"场地名称",
"venueNamePlaceholder":"请输入场地名称",
"capacity":"场地可容纳人数上限",
"capacityPlaceholder":"请输入场地可容纳人数上限",
"availabilityStatus":"场地可用状态",
"availabilityStatusPlaceholder":"请输入场地可用状态",
"timeRangeType":"时间范围类型",
"timeRangeTypePlaceholder":"请输入场地可用时间范围类型",
"fixedTimeRanges":"时间范围",
"fixedTimeRangesPlaceholder":"请输入时间范围",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"updatedAtPlaceholder":"请输入修改时间",
"addVenue":"添加场地",
"updateVenue":"编辑场地",
"venueDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

165
admin/src/app/views/aaaaaaaaaaa/aaaaaaaaaaa.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('addAaaaaaaaaaa') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="aaaaaaaaaaaTable.searchParam" ref="searchFormRef">
<el-form-item>
<el-button type="primary" @click="loadAaaaaaaaaaaList()">{{ 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="aaaaaaaaaaaTable.data" size="large" v-loading="aaaaaaaaaaaTable.loading">
<template #empty>
<span>{{ !aaaaaaaaaaaTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column :label="t('url1')" width="100" align="left">
<template #default="{ row }">
<el-avatar v-if="row.url1" :src="img(row.url1)" />
<el-avatar v-else icon="UserFilled" />
</template>
</el-table-column>
<el-table-column prop="url2" :label="t('url2')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="url3" :label="t('url3')" 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="aaaaaaaaaaaTable.page" v-model:page-size="aaaaaaaaaaaTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="aaaaaaaaaaaTable.total"
@size-change="loadAaaaaaaaaaaList()" @current-change="loadAaaaaaaaaaaList" />
</div>
</div>
<edit ref="editAaaaaaaaaaaDialog" @complete="loadAaaaaaaaaaaList" />
</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 { getAaaaaaaaaaaList, deleteAaaaaaaaaaa } from '@/app/api/aaaaaaaaaaa'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/aaaaaaaaaaa/components/aaaaaaaaaaa-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let aaaaaaaaaaaTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取测试列表
*/
const loadAaaaaaaaaaaList = (page: number = 1) => {
aaaaaaaaaaaTable.loading = true
aaaaaaaaaaaTable.page = page
getAaaaaaaaaaaList({
page: aaaaaaaaaaaTable.page,
limit: aaaaaaaaaaaTable.limit,
...aaaaaaaaaaaTable.searchParam
}).then(res => {
aaaaaaaaaaaTable.loading = false
aaaaaaaaaaaTable.data = res.data.data
aaaaaaaaaaaTable.total = res.data.total
}).catch(() => {
aaaaaaaaaaaTable.loading = false
})
}
loadAaaaaaaaaaaList()
const editAaaaaaaaaaaDialog: Record<string, any> | null = ref(null)
/**
* 添加测试
*/
const addEvent = () => {
editAaaaaaaaaaaDialog.value.setFormData()
editAaaaaaaaaaaDialog.value.showDialog = true
}
/**
* 编辑测试
* @param data
*/
const editEvent = (data: any) => {
editAaaaaaaaaaaDialog.value.setFormData(data)
editAaaaaaaaaaaDialog.value.showDialog = true
}
/**
* 删除测试
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('aaaaaaaaaaaDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteAaaaaaaaaaa(id).then(() => {
loadAaaaaaaaaaaList()
}).catch(() => {
})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadAaaaaaaaaaaList()
}
</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/aaaaaaaaaaa/components/aaaaaaaaaaa-edit.vue

@ -0,0 +1,163 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateAaaaaaaaaaa') : t('addAaaaaaaaaaa')" 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('url1')">
<upload-image v-model="formData.url1" />
</el-form-item>
<el-form-item :label="t('url2')">
<upload-file v-model="formData.url2" />
</el-form-item>
<el-form-item :label="t('url3')">
<upload-video v-model="formData.url3" />
</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 { addAaaaaaaaaaa, editAaaaaaaaaaa, getAaaaaaaaaaaInfo } from '@/app/api/aaaaaaaaaaa'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
url1: '',
url2: '',
url3: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
url1: [
{ required: true, message: t('url1Placeholder'), trigger: 'blur' },
]
,
url2: [
{ required: true, message: t('url2Placeholder'), trigger: 'blur' },
]
,
url3: [
{ required: true, message: t('url3Placeholder'), trigger: 'blur' },
]
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editAaaaaaaaaaa : addAaaaaaaaaaa
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 getAaaaaaaaaaaInfo(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>

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

@ -0,0 +1,318 @@
<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>

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

@ -0,0 +1,296 @@
<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>

253
admin/src/app/views/campus/campus.vue

@ -0,0 +1,253 @@
<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('addCampus') }}
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="campusTable.searchParam"
ref="searchFormRef"
>
<el-form-item :label="t('campusName')" prop="campus_name">
<el-input
v-model="campusTable.searchParam.campus_name"
:placeholder="t('campusNamePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('campusAddress')" prop="campus_address">
<el-input
v-model="campusTable.searchParam.campus_address"
:placeholder="t('campusAddressPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('campusStatus')" prop="campus_status">
<el-select
class="w-[280px]"
v-model="campusTable.searchParam.campus_status"
clearable
:placeholder="t('campusStatusPlaceholder')"
>
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in campus_statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCampusList()">{{
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="campusTable.data"
size="large"
v-loading="campusTable.loading"
>
<template #empty>
<span>{{ !campusTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="campus_name"
:label="t('campusName')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="campus_address"
:label="t('campusAddress')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('campusStatus')"
min-width="180"
align="center"
:show-overflow-tooltip="true"
>
<template #default="{ row }">
<div v-for="(item, index) in campus_statusList">
<div v-if="item.value == row.campus_status">
{{ item.name }}
</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="create_time"
:label="t('createTime')"
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="campusTable.page"
v-model:page-size="campusTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="campusTable.total"
@size-change="loadCampusList()"
@current-change="loadCampusList"
/>
</div>
</div>
<edit ref="editCampusDialog" @complete="loadCampusList" />
</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 { getCampusList, deleteCampus } from '@/app/api/campus'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/campus/components/campus-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
let campusTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
campus_name: '',
campus_address: '',
campus_status: '',
},
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const campus_statusList = ref([] as any[])
const campus_statusDictList = async () => {
campus_statusList.value = await (
await useDictionary('campus_status')
).data.dictionary
}
campus_statusDictList()
/**
* 获取校区列表
*/
const loadCampusList = (page: number = 1) => {
campusTable.loading = true
campusTable.page = page
getCampusList({
page: campusTable.page,
limit: campusTable.limit,
...campusTable.searchParam,
})
.then((res) => {
campusTable.loading = false
campusTable.data = res.data.data
campusTable.total = res.data.total
})
.catch(() => {
campusTable.loading = false
})
}
loadCampusList()
const editCampusDialog: Record<string, any> | null = ref(null)
/**
* 添加校区
*/
const addEvent = () => {
editCampusDialog.value.setFormData()
editCampusDialog.value.showDialog = true
}
/**
* 编辑校区
* @param data
*/
const editEvent = (data: any) => {
editCampusDialog.value.setFormData(data)
editCampusDialog.value.showDialog = true
}
/**
* 删除校区
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('campusDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteCampus(id)
.then(() => {
loadCampusList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCampusList()
}
</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>

270
admin/src/app/views/campus/components/campus-edit.vue

@ -0,0 +1,270 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateCampus') : t('addCampus')"
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('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('campusAddress')">-->
<!-- <el-input-->
<!-- v-model="formData.campus_address"-->
<!-- clearable-->
<!-- :placeholder="t('campusAddressPlaceholder')"-->
<!-- class="input-width"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item :label="t('campusPreviewImage')">
<upload-image v-model="formData.campus_preview_image" />
</el-form-item>
<el-form-item :label="t('campusCoordinates')">
<el-button @click="showMapPicker">
{{
formData.campus_coordinates?.address ||
t('campusCoordinatesPlaceholder')
}}</el-button
>
<TencentMapPicker
ref="mapPickerRef"
v-model="formData.campus_coordinates"
v-model:visible="showMapPickerVisible"
/>
</el-form-item>
<el-form-item :label="t('campusIntroduction')">
<editor v-model="formData.campus_introduction" />
</el-form-item>
<el-form-item :label="t('campusStatus')">
<el-radio-group
v-model="formData.campus_status"
:placeholder="t('campusStatusPlaceholder')"
>
<el-radio
v-for="(item, index) in campus_statusList"
:key="index"
:label="item.value"
>
{{ item.name }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</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 { addCampus, editCampus, getCampusInfo } from '@/app/api/campus'
import TencentMapPicker from '@/components/TencentMapPicker.vue'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_name: '',
campus_address: '',
campus_preview_image: '',
campus_coordinates: '',
campus_introduction: '',
campus_status: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
const mapPickerRef = ref()
const showMapPickerVisible = ref(false)
const showMapPicker = () => {
showMapPickerVisible.value = true
}
//
const formRules = computed(() => {
return {
campus_name: [
{ required: true, message: t('campusNamePlaceholder'), trigger: 'blur' },
],
campus_address: [
{
required: true,
message: t('campusAddressPlaceholder'),
trigger: 'blur',
},
],
campus_preview_image: [
{
required: true,
message: t('campusPreviewImagePlaceholder'),
trigger: 'blur',
},
],
campus_coordinates: [
{
required: true,
message: t('campusCoordinatesPlaceholder'),
trigger: 'blur',
},
],
campus_introduction: [
{
required: true,
message: t('campusIntroductionPlaceholder'),
trigger: 'blur',
},
],
campus_status: [
{
required: true,
message: t('campusStatusPlaceholder'),
trigger: 'blur',
},
],
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCampus : addCampus
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data)
.then((res) => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
loading.value = false
})
}
})
}
//
let campus_statusList = ref([])
const campus_statusDictList = async () => {
campus_statusList.value = await (
await useDictionary('campus_status')
).data.dictionary
}
campus_statusDictList()
watch(
() => campus_statusList.value,
() => {
formData.campus_status = campus_statusList.value[0].value
}
)
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getCampusInfo(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>

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

@ -0,0 +1,306 @@
<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-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.campus_id"
clearable
:placeholder="t('campusIdPlaceholder')"
>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('personId')" prop="person_id">
<el-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.person_id"
clearable
:placeholder="t('personIdPlaceholder')"
>
<el-option
v-for="(item, index) in personIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<el-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.role_id"
clearable
:placeholder="t('roleIdPlaceholder')"
>
<el-option
v-for="(item, index) in roleIdList"
:key="index"
:label="item['role_name']"
:value="item['role_id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('deptId')" prop="dept_id">
<el-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.dept_id"
clearable
:placeholder="t('deptIdPlaceholder')"
>
<el-option
v-for="(item, index) in deptIdList"
:key="index"
:label="item['department_name']"
:value="item['id']"
/>
</el-select>
</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_name"
:label="t('campusId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="person_id_name"
:label="t('personId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="role_id_name"
:label="t('roleId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="dept_id_name"
:label="t('deptId')"
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,
getWithCampusList,
getWithPersonnelList,
getWithSysRoleList,
getWithDepartmentsList,
} 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: '',
},
})
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 campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const personIdList = ref([])
const setPersonIdList = async () => {
personIdList.value = await (await getWithPersonnelList({})).data
}
setPersonIdList()
const roleIdList = ref([])
const setRoleIdList = async () => {
roleIdList.value = await (await getWithSysRoleList({})).data
}
setRoleIdList()
const deptIdList = ref([])
const setDeptIdList = async () => {
deptIdList.value = await (await getWithDepartmentsList({})).data
}
setDeptIdList()
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>

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

@ -0,0 +1,268 @@
<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-select
class="input-width"
v-model="formData.campus_id"
clearable
:placeholder="t('campusIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('personId')" prop="person_id">
<el-select
class="input-width"
v-model="formData.person_id"
clearable
:placeholder="t('personIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in personIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('roleId')" prop="role_id">
<el-select
class="input-width"
v-model="formData.role_id"
clearable
:placeholder="t('roleIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in roleIdList"
:key="index"
:label="item['role_name']"
:value="item['role_id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('deptId')">
<el-select
class="input-width"
v-model="formData.dept_id"
clearable
:placeholder="t('deptIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in deptIdList"
:key="index"
:label="item['department_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addCampusPersonRole,
editCampusPersonRole,
getCampusPersonRoleInfo,
getWithCampusList,
getWithPersonnelList,
getWithSysRoleList,
getWithDepartmentsList,
} 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: '',
}
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' },
],
}
})
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 campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const personIdList = ref([] as any[])
const setPersonIdList = async () => {
personIdList.value = await (await getWithPersonnelList({})).data
}
setPersonIdList()
const roleIdList = ref([] as any[])
const setRoleIdList = async () => {
roleIdList.value = await (await getWithSysRoleList({})).data
}
setRoleIdList()
const deptIdList = ref([] as any[])
const setDeptIdList = async () => {
deptIdList.value = await (await getWithDepartmentsList({})).data
}
setDeptIdList()
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>

280
admin/src/app/views/classroom/classroom.vue

@ -0,0 +1,280 @@
<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('addClassroom') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="classroomTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-select class="w-[280px]" v-model="classroomTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('className')" prop="class_name">
<el-input v-model="classroomTable.searchParam.class_name" :placeholder="t('classNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('headCoach')" prop="head_coach">
<el-select class="w-[280px]" v-model="classroomTable.searchParam.head_coach" clearable :placeholder="t('headCoachPlaceholder')">
<el-option
v-for="(item, index) in headCoachList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('classType')" prop="class_type">
<el-select class="w-[280px]" v-model="classroomTable.searchParam.class_type" clearable :placeholder="t('classTypePlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in class_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('assistantCoach')" prop="assistant_coach">
<el-select class="w-[280px]" v-model="classroomTable.searchParam.assistant_coach" clearable :placeholder="t('assistantCoachPlaceholder')">
<el-option
v-for="(item, index) in assistantCoachList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input v-model="classroomTable.searchParam.created_at" :placeholder="t('createdAtPlaceholder')" />
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-select class="w-[280px]" v-model="classroomTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadClassroomList()">{{ 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="classroomTable.data" size="large" v-loading="classroomTable.loading">
<template #empty>
<span>{{ !classroomTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_name" :label="t('className')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="head_coach_name" :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 :label="t('classType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in class_typeList">
<div v-if="item.value == row.class_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="assistant_coach_name" :label="t('assistantCoach')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="sort_order" :label="t('sortOrder')" 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="classroomTable.page" v-model:page-size="classroomTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="classroomTable.total"
@size-change="loadClassroomList()" @current-change="loadClassroomList" />
</div>
</div>
<edit ref="editClassroomDialog" @complete="loadClassroomList" />
</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 { getClassroomList, deleteClassroom, getWithCampusList, getWithPersonnelList, getWithPersonnelList } from '@/app/api/classroom'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/classroom/components/classroom-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let classroomTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"class_name":"",
"head_coach":"",
"class_type":"",
"assistant_coach":"",
"created_at":"",
"status":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const class_typeList = ref([] as any[])
const class_typeDictList = async () => {
class_typeList.value = await (await useDictionary('class_type')).data.dictionary
}
class_typeDictList();
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
statusDictList();
/**
* 获取场地管理列表
*/
const loadClassroomList = (page: number = 1) => {
classroomTable.loading = true
classroomTable.page = page
getClassroomList({
page: classroomTable.page,
limit: classroomTable.limit,
...classroomTable.searchParam
}).then(res => {
classroomTable.loading = false
classroomTable.data = res.data.data
classroomTable.total = res.data.total
}).catch(() => {
classroomTable.loading = false
})
}
loadClassroomList()
const editClassroomDialog: Record<string, any> | null = ref(null)
/**
* 添加场地管理
*/
const addEvent = () => {
editClassroomDialog.value.setFormData()
editClassroomDialog.value.showDialog = true
}
/**
* 编辑场地管理
* @param data
*/
const editEvent = (data: any) => {
editClassroomDialog.value.setFormData(data)
editClassroomDialog.value.showDialog = true
}
/**
* 删除场地管理
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('classroomDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteClassroom(id).then(() => {
loadClassroomList()
}).catch(() => {
})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const headCoachList = ref([])
const setHeadCoachList = async () => {
headCoachList.value = await (await getWithPersonnelList({})).data
}
setHeadCoachList()
const assistantCoachList = ref([])
const setAssistantCoachList = async () => {
assistantCoachList.value = await (await getWithPersonnelList({})).data
}
setAssistantCoachList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadClassroomList()
}
</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>

287
admin/src/app/views/classroom/components/classroom-edit.vue

@ -0,0 +1,287 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateClassroom') : t('addClassroom')" 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-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('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-select class="input-width" v-model="formData.head_coach" clearable :placeholder="t('headCoachPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in headCoachList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ageGroup')" >
<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-select class="input-width" v-model="formData.class_type" clearable :placeholder="t('classTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in class_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('assistantCoach')" >
<el-select class="input-width" v-model="formData.assistant_coach" clearable :placeholder="t('assistantCoachPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in assistantCoachList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-radio-group v-model="formData.status" :placeholder="t('statusPlaceholder')">
<el-radio
v-for="(item, index) in statusList"
:key="index" :label="item.value">
{{ item.name }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('sortOrder')" >
<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 { addClassroom, editClassroom, getClassroomInfo, getWithCampusList, getWithPersonnelList, getWithPersonnelList } from '@/app/api/classroom'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
class_name: '',
head_coach: '',
age_group: '',
class_type: '',
assistant_coach: '',
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' },
]
,
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' },
]
,
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 ? editClassroom : addClassroom
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(err => {
loading.value = false
})
}
})
}
//
let class_typeList = ref([])
const class_typeDictList = async () => {
class_typeList.value = await (await useDictionary('class_type')).data.dictionary
}
class_typeDictList();
watch(() => class_typeList.value, () => { formData.class_type = class_typeList.value[0].value })
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const headCoachList = ref([] as any[])
const setHeadCoachList = async () => {
headCoachList.value = await (await getWithPersonnelList({})).data
}
setHeadCoachList()
const assistantCoachList = ref([] as any[])
const setAssistantCoachList = async () => {
assistantCoachList.value = await (await getWithPersonnelList({})).data
}
setAssistantCoachList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getClassroomInfo(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>

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

@ -0,0 +1,351 @@
<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>

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

@ -0,0 +1,322 @@
<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>

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

@ -0,0 +1,274 @@
<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>

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

@ -0,0 +1,290 @@
<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>

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

@ -0,0 +1,290 @@
<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>

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

@ -0,0 +1,307 @@
<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>

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

@ -0,0 +1,296 @@
<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>

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

@ -0,0 +1,326 @@
<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>

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

@ -0,0 +1,253 @@
<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>

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

@ -0,0 +1,277 @@
<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>

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

@ -0,0 +1,574 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCustomerResources') : t('addCustomerResources')"
width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<div class="tab-container">
<el-tabs v-model="activeTab" class="tab-pane-half">
<!-- Tab 1: 基本信息 -->
<el-tab-pane label="客户信息" name="base">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form-item :label="t('source')" prop="source">
<el-select class="input-width" v-model="formData.source" clearable
:placeholder="t('sourcePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in sourceList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('sourceChannel')" v-if="formData.source == 1">
<el-select class="input-width" v-model="formData.source_channel" clearable
:placeholder="t('sourceChannelPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in source_channelList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('name')" prop="name">
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')"
class="input-width" />
</el-form-item>
<el-form-item :label="t('age')" prop="age">
<el-input-number v-model="formData.age" clearable :placeholder="t('agePlaceholder')"
class="input-width" :min="3" max="80" />
</el-form-item>
<el-form-item :label="t('gender')" prop="gender">
<el-select class="input-width" v-model="formData.gender" clearable
:placeholder="t('genderPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in genderList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('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" type="textarea" rows="4" clearable
:placeholder="t('demandPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('purchasingPower')" prop="purchasing_power">
<el-select class="input-width" v-model="formData.purchasing_power" clearable
:placeholder="t('purchasingPowerPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in purchasing_powerList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('cognitiveIdea')" prop="cognitive_idea">
<el-select class="input-width" v-model="formData.cognitive_idea" clearable
:placeholder="t('cognitiveIdeaPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in cognitive_ideaList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('optionalClassTime')" prop="optional_class_time" class="input-width">
<el-date-picker class="flex-1 !flex" v-model="formData.optional_class_time" clearable
type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('optionalClassTimePlaceholder')">
</el-date-picker>
</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-select class="input-width" v-model="formData.initial_intent" clearable
:placeholder="t('initialIntentPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in initial_intentList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('campus')" prop="campus">
<el-select class="input-width" v-model="formData.campus" clearable
:placeholder="t('campusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in campusList" :key="index" :label="item['campus_name']"
:value="item['id']" />
</el-select>
</el-form-item>
<el-form-item :label="t('status')" prop="status">
<el-select class="input-width" v-model="formData.status" clearable
:placeholder="t('statusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option v-for="(item, index) in statusList" :key="index" :label="item.name"
:value="item.value" />
</el-select>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="客户六要素" name="sixElements">
<!-- 客户六要素表单内容 -->
<el-form :model="formData" label-width="120px">
<el-form-item label="需求购买力" prop="purchase_power">
<el-select class="input-width" v-model="formData.purchase_power" clearable placeholder="请选择需求购买力">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in purchase_powerList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="认知理念" prop="concept_awareness">
<el-select class="input-width" v-model="formData.concept_awareness" clearable placeholder="请选择认知理念">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in concept_awarenessList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="可选上课时间" prop="preferred_class_time" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.preferred_class_time"
clearable
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="可选上课时间">
</el-date-picker>
</el-form-item>
<el-form-item label="距离" prop="distance_tow">
<el-input v-model="formData.distance_tow" clearable placeholder="请填写距离" class="input-width" />
</el-form-item>
<el-form-item label="沟通备注" prop="communication">
<el-input v-model="formData.communication" type="textarea" rows="4" clearable placeholder="请填写沟通备注" class="input-width"/>
</el-form-item>
<el-form-item label="承诺到访时间" prop="promised_visit_time" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.promised_visit_time"
clearable
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择承诺到访时间">
</el-date-picker>
</el-form-item>
<el-form-item label="实际到访时间" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.actual_visit_time"
clearable
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请填写实际到访时间">
</el-date-picker>
</el-form-item>
<el-form-item label="电话后的意向程度" prop="call_intent">
<el-select class="input-width" v-model="formData.call_intent" clearable placeholder="请选择电话后的意向程度">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in call_intentList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="一访情况" >
<el-input v-model="formData.first_visit_status" type="textarea" rows="4" clearable placeholder="请填写一访情况" class="input-width"/>
</el-form-item>
<el-form-item label="二访情况" >
<el-input v-model="formData.second_visit_status" type="textarea" rows="4" clearable placeholder="请填写二访情况" class="input-width"/>
</el-form-item>
<el-form-item label="是否关单" prop="is_closed">
<el-select class="input-width" v-model="formData.is_closed" clearable placeholder="请选择是否关单">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in is_closedList"
:key="index"
:label="item.name"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
<!-- Footer -->
<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, getWithPersonnelList, getWithCampusList } from '@/app/api/customer_resources'
import { addSixSpeed, editSixSpeed, getSixSpeedInfo, getWithCustomerResourcesList } from '@/app/api/six_speed'
const activeTab = ref('base')
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
source: '',
source_channel: '',
name: '',
age: '',
gender: '',
phone_number: '',
demand: '',
purchasing_power: '',
cognitive_idea: '',
optional_class_time: '',
distance: '',
decision_maker: '',
initial_intent: '',
campus: '',
status: '',
purchase_power: '',
concept_awareness: '',
preferred_class_time: '',
distance_tow: '',
communication: '',
promised_visit_time: '',
actual_visit_time: '',
call_intent: '',
first_visit_status: '',
second_visit_status: '',
is_closed: '',
}
const formData : Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
source: [
{ required: true, message: t('sourcePlaceholder'), trigger: 'blur' },
]
,
source_channel: [
{ required: true, message: t('sourceChannelPlaceholder'), trigger: 'blur' },
]
,
name: [
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
]
,
age: [
{ required: true, message: t('agePlaceholder'), trigger: 'blur' },
{
validator: (rule : any, value : number, callback : any) => {
if (value === undefined || value === null || value === '') {
callback();
} else if (value < 3 || value > 80) {
callback(new Error(t('generateBetween')));
} else {
callback();
}
},
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' },
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl : FormInstance | undefined) => {
console.log(123123)
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
})
}
})
}
//
let sourceList = ref([])
const sourceDictList = async () => {
sourceList.value = await (await useDictionary('source')).data.dictionary
}
sourceDictList();
watch(() => sourceList.value, () => { formData.source = sourceList.value[0].value })
let source_channelList = ref([])
const source_channelDictList = async () => {
source_channelList.value = await (await useDictionary('SourceChannel')).data.dictionary
}
source_channelDictList();
watch(() => source_channelList.value, () => { formData.source_channel = source_channelList.value[0].value })
let genderList = ref([])
const genderDictList = async () => {
genderList.value = await (await useDictionary('zy_sex')).data.dictionary
}
genderDictList();
watch(() => genderList.value, () => { formData.gender = genderList.value[0].value })
let purchasing_powerList = ref([])
const purchasing_powerDictList = async () => {
purchasing_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
}
purchasing_powerDictList();
watch(() => purchasing_powerList.value, () => { formData.purchasing_power = purchasing_powerList.value[0].value })
let cognitive_ideaList = ref([])
const cognitive_ideaDictList = async () => {
cognitive_ideaList.value = await (await useDictionary('cognitive_concept')).data.dictionary
}
cognitive_ideaDictList();
watch(() => cognitive_ideaList.value, () => { formData.cognitive_idea = cognitive_ideaList.value[0].value })
let initial_intentList = ref([])
const initial_intentDictList = async () => {
initial_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
}
initial_intentDictList();
watch(() => initial_intentList.value, () => { formData.initial_intent = initial_intentList.value[0].value })
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('kh_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const consultantList = ref([] as any[])
const setConsultantList = async () => {
consultantList.value = await (await getWithPersonnelList({})).data
}
setConsultantList()
const campusList = ref([] as any[])
const setCampusList = async () => {
campusList.value = await (await getWithCampusList({})).data
}
setCampusList()
//
let purchase_powerList = ref([])
const purchase_powerDictList = async () => {
purchase_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
}
purchase_powerDictList();
watch(() => purchase_powerList.value, () => { formData.purchase_power = purchase_powerList.value[0].value })
let concept_awarenessList = ref([])
const concept_awarenessDictList = async () => {
concept_awarenessList.value = await (await useDictionary('cognitive_concept')).data.dictionary
}
concept_awarenessDictList();
watch(() => concept_awarenessList.value, () => { formData.concept_awareness = concept_awarenessList.value[0].value })
let call_intentList = ref([])
const call_intentDictList = async () => {
call_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
}
call_intentDictList();
watch(() => call_intentList.value, () => { formData.call_intent = call_intentList.value[0].value })
let is_closedList = ref([])
const is_closedDictList = async () => {
is_closedList.value = await (await useDictionary('global_true_or_false')).data.dictionary
}
is_closedDictList();
watch(() => is_closedList.value, () => { formData.is_closed = is_closedList.value[0].value })
const staffIdList = ref([] as any[])
const setStaffIdList = async () => {
staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const 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>

231
admin/src/app/views/customer_resources/customer_resources.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('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('name')" prop="name">
<el-input v-model="customerResourcesTable.searchParam.name" :placeholder="t('namePlaceholder')" />
</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>
<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 :label="t('source')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in sourceList">
<div v-if="item.value == row.source">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="consultant_name" :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 :label="t('gender')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in genderList">
<div v-if="item.value == row.gender">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="phone_number" :label="t('phoneNumber')" 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 :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, getWithPersonnelList, getWithCampusList } 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:{
"name":"",
"phone_number":""
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const sourceList = ref([] as any[])
const sourceDictList = async () => {
sourceList.value = await (await useDictionary('source')).data.dictionary
}
sourceDictList();
const source_channelList = ref([] as any[])
const source_channelDictList = async () => {
source_channelList.value = await (await useDictionary('SourceChannel')).data.dictionary
}
source_channelDictList();
const genderList = ref([] as any[])
const genderDictList = async () => {
genderList.value = await (await useDictionary('zy_sex')).data.dictionary
}
genderDictList();
const purchasing_powerList = ref([] as any[])
const purchasing_powerDictList = async () => {
purchasing_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
}
purchasing_powerDictList();
const cognitive_ideaList = ref([] as any[])
const cognitive_ideaDictList = async () => {
cognitive_ideaList.value = await (await useDictionary('cognitive_concept')).data.dictionary
}
cognitive_ideaDictList();
const initial_intentList = ref([] as any[])
const initial_intentDictList = async () => {
initial_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
}
initial_intentDictList();
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('kh_status')).data.dictionary
}
statusDictList();
/**
* 获取客户资源列表
*/
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 consultantList = ref([])
const setConsultantList = async () => {
consultantList.value = await (await getWithPersonnelList({})).data
}
setConsultantList()
const campusList = ref([])
const setCampusList = async () => {
campusList.value = await (await getWithCampusList({})).data
}
setCampusList()
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>

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

@ -0,0 +1,223 @@
<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>

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

@ -0,0 +1,248 @@
<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>

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

Loading…
Cancel
Save