Browse Source

处理冲突

master
王泽彦 10 months ago
parent
commit
ad9d26e957
  1. 2
      .gitignore
  2. 8
      admin/.env.development
  3. 9
      admin/.env.production
  4. 1
      admin/.gitignore
  5. 5
      admin/auto-imports.d.ts
  6. 5
      admin/components.d.ts
  7. 60
      admin/src/app/api/campus_pay.ts
  8. 31
      admin/src/app/api/reimbursement.ts
  9. 33
      admin/src/app/api/salary.ts
  10. 23
      admin/src/app/api/service.ts
  11. 25
      admin/src/app/api/user_feedback.ts
  12. 25
      admin/src/app/lang/zh-cn/campus_pay.campus_pay.json
  13. 39
      admin/src/app/lang/zh-cn/reimbursement.reimbursement.json
  14. 62
      admin/src/app/lang/zh-cn/salary.salary.json
  15. 54
      admin/src/app/lang/zh-cn/service.service.json
  16. 26
      admin/src/app/lang/zh-cn/user_feedback.user_feedback.json
  17. 12
      admin/src/app/views/auth/components/edit-role.vue
  18. 9
      admin/src/app/views/auth/role.vue
  19. 183
      admin/src/app/views/campus_pay/campus_pay.vue
  20. 216
      admin/src/app/views/campus_pay/components/campus-pay-edit.vue
  21. 16
      admin/src/app/views/campus_person_role/campus_person_role.vue
  22. 2
      admin/src/app/views/course/components/course-edit.vue
  23. 62
      admin/src/app/views/course/course.vue
  24. 31
      admin/src/app/views/customer_resources/components/customer-resources-edit.vue
  25. 878
      admin/src/app/views/customer_resources/customer_resources.vue
  26. 4
      admin/src/app/views/departments/departments.vue
  27. 3
      admin/src/app/views/member/components/edit-member.vue
  28. 446
      admin/src/app/views/order_table/components/order-table-edit.vue
  29. 445
      admin/src/app/views/reimbursement/components/reimbursement-edit.vue
  30. 465
      admin/src/app/views/reimbursement/reimbursement.vue
  31. 621
      admin/src/app/views/salary/components/salary-edit.vue
  32. 592
      admin/src/app/views/salary/salary.vue
  33. 599
      admin/src/app/views/service/components/service-edit.vue
  34. 531
      admin/src/app/views/service/service.vue
  35. 9
      admin/src/app/views/setting/components/pay-wechatpay.vue
  36. 356
      admin/src/app/views/setting/pay.vue
  37. 380
      admin/src/app/views/user_feedback/components/user-feedback-edit.vue
  38. 400
      admin/src/app/views/user_feedback/user_feedback.vue
  39. 102
      niucloud/app/adminapi/controller/campus_pay/CampusPay.php
  40. 4
      niucloud/app/adminapi/controller/customer_resources/CustomerResources.php
  41. 8
      niucloud/app/adminapi/controller/departments/Departments.php
  42. 9
      niucloud/app/adminapi/controller/order_table/OrderTable.php
  43. 12
      niucloud/app/adminapi/controller/reimbursement/Reimbursement.php
  44. 32
      niucloud/app/adminapi/controller/salary/Salary.php
  45. 7
      niucloud/app/adminapi/controller/service/Service.php
  46. 2
      niucloud/app/adminapi/controller/sys/Role.php
  47. 8
      niucloud/app/adminapi/controller/user_feedback/UserFeedback.php
  48. 42
      niucloud/app/adminapi/route/campus_pay.php
  49. 6
      niucloud/app/adminapi/route/reimbursement.php
  50. 8
      niucloud/app/adminapi/route/salary.php
  51. 1
      niucloud/app/adminapi/route/service.php
  52. 3
      niucloud/app/adminapi/route/user_feedback.php
  53. 28
      niucloud/app/api/controller/apiController/CustomerResources.php
  54. 3
      niucloud/app/api/route/route.php
  55. 8
      niucloud/app/dict/common/ChannelDict.php
  56. 48
      niucloud/app/dict/pay/PayDict.php
  57. 98
      niucloud/app/model/campus_pay/CampusPay.php
  58. 40
      niucloud/app/model/customer_resources/CustomerResources.php
  59. 80
      niucloud/app/model/reimbursement/Reimbursement.php
  60. 140
      niucloud/app/model/salary/Salary.php
  61. 96
      niucloud/app/model/service/Service.php
  62. 21
      niucloud/app/model/six_speed/SixSpeed.php
  63. 44
      niucloud/app/model/user_feedback/UserFeedback.php
  64. 105
      niucloud/app/service/admin/campus_pay/CampusPayService.php
  65. 32
      niucloud/app/service/admin/customer_resources/CustomerResourcesService.php
  66. 13
      niucloud/app/service/admin/departments/DepartmentsService.php
  67. 12
      niucloud/app/service/admin/order_table/OrderTableService.php
  68. 55
      niucloud/app/service/admin/pay/PayChannelService.php
  69. 10
      niucloud/app/service/admin/reimbursement/ReimbursementService.php
  70. 20
      niucloud/app/service/admin/salary/SalaryService.php
  71. 2
      niucloud/app/service/admin/service/ServiceService.php
  72. 4
      niucloud/app/service/admin/sys/RoleService.php
  73. 10
      niucloud/app/service/admin/user_feedback/UserFeedbackService.php
  74. 258
      niucloud/app/service/api/apiService/CustomerResourcesService.php
  75. 47
      niucloud/app/validate/campus_pay/CampusPay.php
  76. 4
      niucloud/app/validate/order_table/OrderTable.php
  77. 6
      niucloud/app/validate/reimbursement/Reimbursement.php
  78. 10
      niucloud/app/validate/salary/Salary.php
  79. 6
      niucloud/app/validate/user_feedback/UserFeedback.php
  80. 1
      niucloud/public/admin/assets/404-145f080f.css
  81. 1
      niucloud/public/admin/assets/404-62395b03.js
  82. 1
      niucloud/public/admin/assets/404-c962cf1f.js
  83. 1
      niucloud/public/admin/assets/404-e4083eb7.css
  84. 1
      niucloud/public/admin/assets/App-0882181b.js
  85. 1
      niucloud/public/admin/assets/App-16d4b42a.js
  86. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-306ddab0.js
  87. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-aa05ac94.js
  88. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-b8059124.js
  89. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-cf13a734.js
  90. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-e2131f72.js
  91. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit-ee5b45e9.js
  92. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-0fbc701d.js
  93. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-5df4a241.js
  94. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-91677b3b.js
  95. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-9c5c9cc4.js
  96. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a1f23d9d.js
  97. 1
      niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a658c3b6.js
  98. 1
      niucloud/public/admin/assets/TencentMapPicker-59c0503c.js
  99. 1
      niucloud/public/admin/assets/TencentMapPicker-96eea39a.css
  100. 1
      niucloud/public/admin/assets/Verify-3982a86a.css

2
.gitignore

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

8
admin/.env.development

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

9
admin/.env.production

@ -0,0 +1,9 @@
# 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'

1
admin/.gitignore

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

5
admin/auto-imports.d.ts

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

5
admin/components.d.ts

@ -17,10 +17,7 @@ declare module '@vue/runtime-core' {
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard'] ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
@ -57,7 +54,7 @@ declare module '@vue/runtime-core' {
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default'] ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default'] HeatMap: typeof import('./src/components/heat-map/index.vue')['default']

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

@ -0,0 +1,60 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- campus_pay
/**
*
* @param params
* @returns
*/
export function getCampusPayList(params: Record<string, any>) {
return request.get(`campus_pay/campus_pay`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getCampusPayInfo(id: number) {
return request.get(`campus_pay/campus_pay/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addCampusPay(params: Record<string, any>) {
return request.post('campus_pay/campus_pay', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editCampusPay(params: Record<string, any>) {
return request.put(`campus_pay/campus_pay/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteCampusPay(id: number) {
return request.delete(`campus_pay/campus_pay/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCampusList(params: Record<string,any>){
return request.get('campus_pay/campus_all', {params})
}
// USER_CODE_END -- campus_pay

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

@ -1,5 +1,13 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- reimbursement // USER_CODE_BEGIN -- reimbursement
/** /**
* *
@ -7,7 +15,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getReimbursementList(params: Record<string, any>) { export function getReimbursementList(params: Record<string, any>) {
return request.get(`reimbursement/reimbursement`, { params }) return request.get(`reimbursement/reimbursement`, {params})
} }
/** /**
@ -16,7 +24,7 @@ export function getReimbursementList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getReimbursementInfo(id: number) { export function getReimbursementInfo(id: number) {
return request.get(`reimbursement/reimbursement/${id}`) return request.get(`reimbursement/reimbursement/${id}`);
} }
/** /**
@ -25,10 +33,7 @@ export function getReimbursementInfo(id: number) {
* @returns * @returns
*/ */
export function addReimbursement(params: Record<string, any>) { export function addReimbursement(params: Record<string, any>) {
return request.post('reimbursement/reimbursement', params, { return request.post('reimbursement/reimbursement', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +43,7 @@ export function addReimbursement(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editReimbursement(params: Record<string, any>) { export function editReimbursement(params: Record<string, any>) {
return request.put(`reimbursement/reimbursement/${params.id}`, params, { return request.put(`reimbursement/reimbursement/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +52,11 @@ export function editReimbursement(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteReimbursement(id: number) { export function deleteReimbursement(id: number) {
return request.delete(`reimbursement/reimbursement/${id}`, { return request.delete(`reimbursement/reimbursement/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithPersonnelList(params: Record<string,any>){
return request.get('reimbursement/personnel_all', {params})
} }
// USER_CODE_END -- reimbursement // USER_CODE_END -- reimbursement

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

@ -1,5 +1,13 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- salary // USER_CODE_BEGIN -- salary
/** /**
* *
@ -7,7 +15,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getSalaryList(params: Record<string, any>) { export function getSalaryList(params: Record<string, any>) {
return request.get(`salary/salary`, { params }) return request.get(`salary/salary`, {params})
} }
/** /**
@ -16,7 +24,7 @@ export function getSalaryList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getSalaryInfo(id: number) { export function getSalaryInfo(id: number) {
return request.get(`salary/salary/${id}`) return request.get(`salary/salary/${id}`);
} }
/** /**
@ -25,10 +33,7 @@ export function getSalaryInfo(id: number) {
* @returns * @returns
*/ */
export function addSalary(params: Record<string, any>) { export function addSalary(params: Record<string, any>) {
return request.post('salary/salary', params, { return request.post('salary/salary', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +43,7 @@ export function addSalary(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editSalary(params: Record<string, any>) { export function editSalary(params: Record<string, any>) {
return request.put(`salary/salary/${params.id}`, params, { return request.put(`salary/salary/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +52,13 @@ export function editSalary(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteSalary(id: number) { export function deleteSalary(id: number) {
return request.delete(`salary/salary/${id}`, { return request.delete(`salary/salary/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithPersonnelList(params: Record<string,any>){
return request.get('salary/personnel_all', {params})
}export function getWithDepartmentsList(params: Record<string,any>){
return request.get('salary/departments_all', {params})
} }
// USER_CODE_END -- salary // USER_CODE_END -- salary

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

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

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

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- user_feedback // USER_CODE_BEGIN -- user_feedback
/** /**
* *
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getUserFeedbackList(params: Record<string, any>) { export function getUserFeedbackList(params: Record<string, any>) {
return request.get(`user_feedback/user_feedback`, { params }) return request.get(`user_feedback/user_feedback`, {params})
} }
/** /**
@ -16,7 +18,7 @@ export function getUserFeedbackList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getUserFeedbackInfo(id: number) { export function getUserFeedbackInfo(id: number) {
return request.get(`user_feedback/user_feedback/${id}`) return request.get(`user_feedback/user_feedback/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getUserFeedbackInfo(id: number) {
* @returns * @returns
*/ */
export function addUserFeedback(params: Record<string, any>) { export function addUserFeedback(params: Record<string, any>) {
return request.post('user_feedback/user_feedback', params, { return request.post('user_feedback/user_feedback', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addUserFeedback(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editUserFeedback(params: Record<string, any>) { export function editUserFeedback(params: Record<string, any>) {
return request.put(`user_feedback/user_feedback/${params.id}`, params, { return request.put(`user_feedback/user_feedback/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,11 @@ export function editUserFeedback(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteUserFeedback(id: number) { export function deleteUserFeedback(id: number) {
return request.delete(`user_feedback/user_feedback/${id}`, { return request.delete(`user_feedback/user_feedback/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('user_feedback/customer_resources_all', {params})
} }
// USER_CODE_END -- user_feedback // USER_CODE_END -- user_feedback

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

@ -0,0 +1,25 @@
{
"id":"",
"idPlaceholder":"请输入",
"campusId":"校区",
"campusIdPlaceholder":"全部",
"mchid":"商户号",
"mchidPlaceholder":"请输入商户号",
"paySignKey":"APIv3密钥",
"paySignKeyPlaceholder":"请输入APIv3密钥",
"apiclientKey":"商户私钥",
"apiclientKeyPlaceholder":"请输入商户私钥",
"apiclientCert":"商户公钥",
"apiclientCertPlaceholder":"请输入商户公钥",
"wxPayKey":"微信支付公钥",
"wxPayKeyPlaceholder":"请输入微信支付公钥",
"wxPayKeyId":"微信支付公钥ID",
"wxPayKeyIdPlaceholder":"请输入微信支付公钥ID",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"addCampusPay":"添加账户及资金管理",
"updateCampusPay":"编辑账户及资金管理",
"campusPayDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

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

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

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

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

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

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

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

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

12
admin/src/app/views/auth/components/edit-role.vue

@ -24,6 +24,17 @@
:show-word-limit="true" :show-word-limit="true"
/> />
</el-form-item> </el-form-item>
<el-form-item label="类型">
<el-radio-group v-model="formData.role_key">
<el-radio label="market">销售</el-radio>
<el-radio label="teacher">老师</el-radio>
<el-radio label="manager">主管</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('status')"> <el-form-item :label="t('status')">
<el-radio-group v-model="formData.status"> <el-radio-group v-model="formData.status">
@ -142,6 +153,7 @@ const initialFormData = {
role_id: 0, role_id: 0,
role_name: '', role_name: '',
status: 1, status: 1,
role_key:'',
rules: [], rules: [],
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })

9
admin/src/app/views/auth/role.vue

@ -56,6 +56,15 @@
}}</el-tag> }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="类型">
<template #default="{ row }">
<el-tag type="success" v-if="row.role_key == 'market'">销售</el-tag>
<el-tag type="success" v-if="row.role_key == 'teacher'">老师</el-tag>
<el-tag type="success" v-if="row.role_key == 'manager'">主管</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="create_time" prop="create_time"
:label="t('createTime')" :label="t('createTime')"

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

@ -0,0 +1,183 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addCampusPay') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="campusPayTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('campusId')" prop="campus_id">
<el-select class="w-[280px]" v-model="campusPayTable.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('createdAt')" prop="created_at">
<el-date-picker v-model="campusPayTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCampusPayList()">{{ 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="campusPayTable.data" size="large" v-loading="campusPayTable.loading">
<template #empty>
<span>{{ !campusPayTable.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="mchid" :label="t('mchid')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="campusPayTable.page" v-model:page-size="campusPayTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="campusPayTable.total"
@size-change="loadCampusPayList()" @current-change="loadCampusPayList" />
</div>
</div>
<edit ref="editCampusPayDialog" @complete="loadCampusPayList" />
</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 { getCampusPayList, deleteCampusPay, getWithCampusList } from '@/app/api/campus_pay'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/campus_pay/components/campus-pay-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let campusPayTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
"campus_id":"",
"created_at":[]
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取账户及资金管理列表
*/
const loadCampusPayList = (page: number = 1) => {
campusPayTable.loading = true
campusPayTable.page = page
getCampusPayList({
page: campusPayTable.page,
limit: campusPayTable.limit,
...campusPayTable.searchParam
}).then(res => {
campusPayTable.loading = false
campusPayTable.data = res.data.data
campusPayTable.total = res.data.total
}).catch(() => {
campusPayTable.loading = false
})
}
loadCampusPayList()
const editCampusPayDialog: Record<string, any> | null = ref(null)
/**
* 添加账户及资金管理
*/
const addEvent = () => {
editCampusPayDialog.value.setFormData()
editCampusPayDialog.value.showDialog = true
}
/**
* 编辑账户及资金管理
* @param data
*/
const editEvent = (data: any) => {
editCampusPayDialog.value.setFormData(data)
editCampusPayDialog.value.showDialog = true
}
/**
* 删除账户及资金管理
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('campusPayDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteCampusPay(id).then(() => {
loadCampusPayList()
}).catch(() => {
})
})
}
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadCampusPayList()
}
</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>

216
admin/src/app/views/campus_pay/components/campus-pay-edit.vue

@ -0,0 +1,216 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCampusPay') : t('addCampusPay')" 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('mchid')" prop="mchid">
<el-input v-model="formData.mchid" clearable :placeholder="t('mchidPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('paySignKey')" prop="pay_sign_key">
<el-input v-model="formData.pay_sign_key" clearable :placeholder="t('paySignKeyPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('apiclientKey')">
<upload-file v-model="formData.apiclient_key" />
</el-form-item>
<el-form-item :label="t('apiclientCert')">
<upload-file v-model="formData.apiclient_cert" />
</el-form-item>
<el-form-item :label="t('wxPayKey')">
<upload-file v-model="formData.wx_pay_key" />
</el-form-item>
<el-form-item :label="t('wxPayKeyId')" prop="wx_pay_key_id">
<el-input v-model="formData.wx_pay_key_id" clearable :placeholder="t('wxPayKeyIdPlaceholder')" 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 { addCampusPay, editCampusPay, getCampusPayInfo, getWithCampusList } from '@/app/api/campus_pay'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
campus_id: '',
mchid: '',
pay_sign_key: '',
apiclient_key: '',
apiclient_cert: '',
wx_pay_key: '',
wx_pay_key_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' },
]
,
mchid: [
{ required: true, message: t('mchidPlaceholder'), trigger: 'blur' },
]
,
pay_sign_key: [
{ required: true, message: t('paySignKeyPlaceholder'), trigger: 'blur' },
]
,
apiclient_key: [
{ required: true, message: t('apiclientKeyPlaceholder'), trigger: 'blur' },
]
,
apiclient_cert: [
{ required: true, message: t('apiclientCertPlaceholder'), trigger: 'blur' },
]
,
wx_pay_key: [
{ required: true, message: t('wxPayKeyPlaceholder'), trigger: 'blur' },
]
,
wx_pay_key_id: [
{ required: true, message: t('wxPayKeyIdPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editCampusPay : addCampusPay
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 setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCampusPayInfo(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>

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

@ -65,7 +65,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('deptId')" prop="dept_id"> <!-- <el-form-item :label="t('deptId')" prop="dept_id">
<el-select <el-select
class="w-[280px]" class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.dept_id" v-model="campusPersonRoleTable.searchParam.dept_id"
@ -79,7 +79,7 @@
:value="item['id']" :value="item['id']"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadCampusPersonRoleList()">{{ <el-button type="primary" @click="loadCampusPersonRoleList()">{{
@ -186,7 +186,6 @@ const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
// ?dept_id=1 // ?dept_id=1
const dept_id = pageName == '市场人员列表' ? 1 : 2
let campusPersonRoleTable = reactive({ let campusPersonRoleTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
@ -197,10 +196,19 @@ let campusPersonRoleTable = reactive({
campus_id: '', campus_id: '',
person_id: '', person_id: '',
role_id: '', role_id: '',
dept_id: dept_id, dept_id: '',
}, },
}) })
if(pageName == '市场人员列表'){
campusPersonRoleTable.searchParam.dept_id = 1;
}else if(pageName == '销售人员列表'){
campusPersonRoleTable.searchParam.dept_id = 2;
}else if(pageName == '教练管理'){
campusPersonRoleTable.searchParam.role_id = 5;
}
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
// //

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

@ -33,7 +33,7 @@
v-for="(item, index) in courseTypeList" v-for="(item, index) in courseTypeList"
:key="index" :key="index"
:label="item.name" :label="item.name"
:value="item.value" :value="item.name"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>

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

@ -31,56 +31,12 @@
<el-option <el-option
v-for="item in courseTypeList" v-for="item in courseTypeList"
:key="item.value" :key="item.value"
:label="item.label" :label="item.name"
:value="item.value" :value="item.name"
/> />
</el-select> </el-select>
</el-form-item> </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-form-item>
<el-button type="primary" @click="loadCourseList()">{{ <el-button type="primary" @click="loadCourseList()">{{
@ -227,7 +183,17 @@ let courseTable = reactive({
remarks: '', remarks: '',
}, },
}) })
const courseTypeList = useDictionary('course_type') // const courseTypeList = useDictionary('course_type')
const courseTypeList = ref([])
const getcourseTypeList = async () => {
courseTypeList.value = await (
await useDictionary('course_type')
).data.dictionary
}
getcourseTypeList()
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
// //

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

@ -230,6 +230,26 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="会员标签">
<el-select
v-model="formData.member_label"
multiple
collapse-tags
placeholder="请选择会员标签"
class="input-width"
>
<el-option
:label="item['label_name']"
:value="item['label_id']"
v-for="(item, index) in labelSelectData"
:key="index"
/>
</el-select>
</el-form-item>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
@ -410,6 +430,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { getMemberLabelAll } from '@/app/api/member'
import { import {
addCustomerResources, addCustomerResources,
editCustomerResources, editCustomerResources,
@ -448,6 +469,7 @@ const initialFormData = {
initial_intent: '', initial_intent: '',
campus: '', campus: '',
status: '', status: '',
member_label:'',
purchase_power: '', purchase_power: '',
concept_awareness: '', concept_awareness: '',
@ -461,6 +483,15 @@ const initialFormData = {
second_visit_status: '', second_visit_status: '',
is_closed: '', is_closed: '',
} }
const labelSelectData: any = ref(null)
//
const getMemberLabelAllFn = async () => {
labelSelectData.value = await (await getMemberLabelAll()).data
}
getMemberLabelAllFn()
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()

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

@ -1,496 +1,396 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button <span class="text-lg">{{pageName}}</span>
type="primary" <el-button type="primary" @click="addEvent" v-if="customerResourcesTable.searchParam.type == 'khzy'">
@click="addEvent" {{ t('addCustomerResources') }}
v-if="customerResourcesTable.searchParam.type == 'khzy'" </el-button>
> </div>
{{ t('addCustomerResources') }}
</el-button> <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
</div> <el-form :inline="true" :model="customerResourcesTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('name')" prop="name">
<el-card <el-input v-model="customerResourcesTable.searchParam.name"
class="box-card !border-none my-[10px] table-search-wrap" :placeholder="t('namePlaceholder')" />
shadow="never" </el-form-item>
>
<el-form <el-form-item label="年龄" prop="age">
:inline="true" <el-input v-model="customerResourcesTable.searchParam.age" placeholder="请输入年龄" />
:model="customerResourcesTable.searchParam" </el-form-item>
ref="searchFormRef"
>
<el-form-item :label="t('name')" prop="name"> <el-form-item label="性别" prop="gender">
<el-input <el-select v-model="customerResourcesTable.searchParam.gender" placeholder="请选择性别">
v-model="customerResourcesTable.searchParam.name" <el-option label="男性" value="male" />
:placeholder="t('namePlaceholder')" <el-option label="女性" value="female" />
/> <el-option label="其他" value="other" />
</el-form-item> </el-select>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input
v-model="customerResourcesTable.searchParam.age"
placeholder="请输入年龄" <el-form-item :label="t('phoneNumber')" prop="phone_number">
/> <el-input v-model="customerResourcesTable.searchParam.phone_number"
</el-form-item> :placeholder="t('phoneNumberPlaceholder')" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-select
v-model="customerResourcesTable.searchParam.gender" <el-form-item label="创建时间">
placeholder="请选择性别" <el-date-picker v-model="customerResourcesTable.searchParam.created_at" type="daterange" range-separator=""
> start-placeholder="开始日期" end-placeholder="结束日期" format="YYYY-MM-DD"
<el-option label="男性" value="male" /> value-format="YYYY-MM-DD" />
<el-option label="女性" value="female" /> </el-form-item>
<el-option label="其他" value="other" />
</el-select> <!-- 更新时间 -->
</el-form-item> <el-form-item label="更新时间">
<el-date-picker v-model="customerResourcesTable.searchParam.updated_at" type="daterange" range-separator=""
<el-form-item :label="t('phoneNumber')" prop="phone_number"> start-placeholder="开始日期" end-placeholder="结束日期" format="YYYY-MM-DD"
<el-input value-format="YYYY-MM-DD" />
v-model="customerResourcesTable.searchParam.phone_number" </el-form-item>
:placeholder="t('phoneNumberPlaceholder')"
/>
</el-form-item> <el-form-item>
<el-button type="primary" @click="loadCustomerResourcesList()">{{ t('search') }}</el-button>
<el-form-item label="创建时间"> <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
<el-date-picker </el-form-item>
v-model="customerResourcesTable.searchParam.created_at" </el-form>
type="daterange" </el-card>
range-separator="至"
start-placeholder="开始日期" <div class="mt-[10px]">
end-placeholder="结束日期" <el-table :data="customerResourcesTable.data" size="large" v-loading="customerResourcesTable.loading">
format="YYYY-MM-DD" <template #empty>
value-format="YYYY-MM-DD" <span>{{ !customerResourcesTable.loading ? t('emptyData') : '' }}</span>
/> </template>
</el-form-item> <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">
<el-form-item label="更新时间"> <div v-if="item.value == row.source">{{ item.name }}</div>
<el-date-picker </div>
v-model="customerResourcesTable.searchParam.updated_at" </template>
type="daterange" </el-table-column>
range-separator="至"
start-placeholder="开始日期" <el-table-column prop="consultant_name" :label="t('consultant')" min-width="120"
end-placeholder="结束日期" :show-overflow-tooltip="true" />
format="YYYY-MM-DD"
value-format="YYYY-MM-DD" <el-table-column prop="name" :label="t('name')" min-width="120" :show-overflow-tooltip="true" />
/>
</el-form-item> <el-table-column prop="age" :label="t('age')" min-width="50" :show-overflow-tooltip="true" />
<el-form-item> <el-table-column :label="t('gender')" min-width="60" align="center" :show-overflow-tooltip="true">
<el-button type="primary" @click="loadCustomerResourcesList()">{{ <template #default="{ row }">
t('search') <div v-for="(item, index) in genderList">
}}</el-button> <div v-if="item.value == row.gender">{{ item.name }}</div>
<el-button @click="resetForm(searchFormRef)">{{ </div>
t('reset') </template>
}}</el-button> </el-table-column>
</el-form-item>
</el-form> <el-table-column prop="phone_number" :label="t('phoneNumber')" min-width="120"
</el-card> :show-overflow-tooltip="true" />
<div class="mt-[10px]"> <el-table-column prop="decision_maker" :label="t('decisionMaker')" min-width="120"
<el-table :show-overflow-tooltip="true" />
:data="customerResourcesTable.data"
size="large"
v-loading="customerResourcesTable.loading" <el-table-column
> prop="member_label"
<template #empty> label="会员标签"
<span>{{ min-width="120"
!customerResourcesTable.loading ? t('emptyData') : '' align="center"
}}</span> >
</template> <template #default="{ row }">
<el-table-column <div class="flex flex-col items-center">
:label="t('source')" <div
min-width="180" v-for="(item, key) in row.member_label_array"
align="center" class="my-[3px]"
:show-overflow-tooltip="true" :key="key"
> >
<template #default="{ row }"> <el-tag type="info">{{ item.label_name }}</el-tag>
<div v-for="(item, index) in sourceList"> </div>
<div v-if="item.value == row.source">{{ item.name }}</div> </div>
</div> </template>
</template> </el-table-column>
</el-table-column>
<el-table-column <el-table-column prop="created_at" label="添加时间" min-width="120" :show-overflow-tooltip="true" />
prop="consultant_name"
:label="t('consultant')" <el-table-column prop="updated_at" label="修改时间" min-width="120" :show-overflow-tooltip="true" />
min-width="120"
:show-overflow-tooltip="true"
/> <el-table-column :label="t('operation')" fixed="right" min-width="200" v-if="customerResourcesTable.searchParam.type == 'khzy'">
<template #default="{ row }">
<el-table-column <el-button type="primary" link @click="modificationLog(row.id)">六要素修改记录</el-button>
prop="name" <el-button type="primary" link @click="resourceChanges(row.id)">客户信息修改记录</el-button>
:label="t('name')" <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
min-width="120" <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
:show-overflow-tooltip="true"
/> </template>
</el-table-column>
<el-table-column
prop="age"
:label="t('age')"
min-width="50" <el-table-column :label="t('operation')" fixed="right" min-width="200"
:show-overflow-tooltip="true" v-if="customerResourcesTable.searchParam.type == 'yjfp'">
/> <template #default="{ row }">
<el-button type="primary" link @click="fpEvent(row)">分配</el-button>
<el-table-column </template>
:label="t('gender')" </el-table-column>
min-width="60"
align="center"
:show-overflow-tooltip="true" <el-table-column :label="t('operation')" fixed="right" min-width="200"
> v-if="customerResourcesTable.searchParam.type == 'zylb'">
<template #default="{ row }"> <template #default="{ row }">
<div v-for="(item, index) in genderList"> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<div v-if="item.value == row.gender">{{ item.name }}</div>
</div> <el-button type="primary" link @click="addOrder({'resource_id':row.id})">添加订单</el-button>
</template>
</el-table-column> <el-button type="primary" link @click="tcEvent({'resource_id':row.id})">体测</el-button>
</template>
<el-table-column </el-table-column>
prop="phone_number"
:label="t('phoneNumber')" </el-table>
min-width="120" <div class="mt-[16px] flex justify-end">
:show-overflow-tooltip="true" <el-pagination v-model:current-page="customerResourcesTable.page"
/> v-model:page-size="customerResourcesTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="customerResourcesTable.total"
<el-table-column @size-change="loadCustomerResourcesList()" @current-change="loadCustomerResourcesList" />
prop="decision_maker" </div>
:label="t('decisionMaker')" </div>
min-width="120"
:show-overflow-tooltip="true" <edit ref="editCustomerResourcesDialog" @complete="loadCustomerResourcesList" />
/>
<fp ref="fpCustomerResourcesDialog" @complete="loadCustomerResourcesList" />
<el-table-column
prop="created_at" <Order ref="editOrderTableDialog" @complete="loadCustomerResourcesList" />
label="添加时间"
min-width="120" <tc ref="TcCustomerResourcesDialog" @complete="loadCustomerResourcesList" />
:show-overflow-tooltip="true"
/> </el-card>
</div>
<el-table-column
prop="updated_at"
label="修改时间"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="200"
v-if="customerResourcesTable.searchParam.type == 'khzy'"
>
<template #default="{ row }">
<el-button type="primary" link @click="modificationLog(row.id)"
>六要素修改记录</el-button
>
<el-button type="primary" link @click="resourceChanges(row.id)"
>客户信息修改记录</el-button
>
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="200"
v-if="customerResourcesTable.searchParam.type == 'yjfp'"
>
<template #default="{ row }">
<el-button type="primary" link @click="fpEvent(row)"
>分配</el-button
>
</template>
</el-table-column>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="200"
v-if="customerResourcesTable.searchParam.type == 'zylb'"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button
type="primary"
link
@click="addOrder({ resource_id: row.id })"
>添加订单</el-button
>
<el-button
type="primary"
link
@click="tcEvent({ resource_id: row.id })"
>体测</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"
/>
<fp
ref="fpCustomerResourcesDialog"
@complete="loadCustomerResourcesList"
/>
<Order ref="editOrderTableDialog" @complete="loadCustomerResourcesList" />
<tc
ref="TcCustomerResourcesDialog"
@complete="loadCustomerResourcesList"
/>
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { import { getCustomerResourcesList, deleteCustomerResources, getWithPersonnelList, getWithCampusList } from '@/app/api/customer_resources'
getCustomerResourcesList, import { img } from '@/utils/common'
deleteCustomerResources, import { ElMessageBox, FormInstance } from 'element-plus'
getWithPersonnelList, import Edit from '@/app/views/customer_resources/components/customer-resources-edit.vue'
getWithCampusList, import Fp from '@/app/views/customer_resources/components/fp.vue'
} from '@/app/api/customer_resources' import Order from '@/app/views/order_table/components/order-table-edit.vue'
import { img } from '@/utils/common' import Tc from '@/app/views/tc_dialog/tc_dialog.vue'
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/customer_resources/components/customer-resources-edit.vue' import { getMemberLabelAll } from '@/app/api/member'
import Fp from '@/app/views/customer_resources/components/fp.vue'
import Order from '@/app/views/order_table/components/order-table-edit.vue' import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
import Tc from '@/app/views/tc_dialog/tc_dialog.vue' const pageName = route.meta.title;
const router = useRouter()
import { useRouter, useRoute } from 'vue-router'
const route = useRoute() let customerResourcesTable = reactive({
const pageName = route.meta.title page: 1,
const router = useRouter() limit: 10,
total: 0,
let customerResourcesTable = reactive({ loading: true,
page: 1, data: [],
limit: 10, searchParam: {
total: 0, "name": "",
loading: true, "age": "",
data: [], "gender": "",
searchParam: { "phone_number": "",
name: '', "member_label" : "",
age: '', 'type': '',
gender: '', "created_at" : "",
phone_number: '', "updated_at" : ""
type: '', }
created_at: '', })
updated_at: '',
}, if (pageName == '业绩分配') {
}) customerResourcesTable.searchParam.type = 'yjfp';
} else if (pageName == '客户资源列表') {
if (pageName == '业绩分配') { customerResourcesTable.searchParam.type = 'khzy';
customerResourcesTable.searchParam.type = 'yjfp' } else if (pageName == '资源列表') {
} else if (pageName == '客户资源列表') { customerResourcesTable.searchParam.type = 'zylb';
customerResourcesTable.searchParam.type = 'khzy' }
} else if (pageName == '资源列表') {
customerResourcesTable.searchParam.type = 'zylb' // const type = pageName == '' ? 'yjfp' : 'khzy';
}
//
// const type = pageName == '' ? 'yjfp' : 'khzy'; const labelSelectData = ref([])
const getMemberLabelAllFn = async () => {
const modificationLog = (id: number) => { labelSelectData.value = await (await getMemberLabelAll()).data
router.push({ }
path: '/six_speed_modification_log/six_speed_modification_log', getMemberLabelAllFn()
query: { id: id },
})
} const modificationLog = (id : number) => {
router.push({ path: '/six_speed_modification_log/six_speed_modification_log', query: { id: id } })
const resourceChanges = (id: number) => { }
router.push({
path: '/customer_resource_changes/customer_resource_changes', const resourceChanges = (id : number) => {
query: { id: id }, router.push({ path: '/customer_resource_changes/customer_resource_changes', query: { id: id } })
}) }
}
/** /**
* 添加订单 * 添加订单
*/ */
const editOrderTableDialog: Record<string, any> | null = ref(null) const editOrderTableDialog : Record<string, any> | null = ref(null)
const addOrder = (row: any) => { const addOrder = (row : any) => {
console.log(row)
editOrderTableDialog.value.setFormData(row) console.log(row);
editOrderTableDialog.value.showDialog = true editOrderTableDialog.value.setFormData(row)
} editOrderTableDialog.value.showDialog = true
}
const TcCustomerResourcesDialog: Record<string, any> | null = ref(null)
const tcEvent = (row: any) => {
TcCustomerResourcesDialog.value.setFormData(row) const TcCustomerResourcesDialog : Record<string, any> | null = ref(null)
TcCustomerResourcesDialog.value.showDialog = true const tcEvent = (row : any) => {
} TcCustomerResourcesDialog.value.setFormData(row)
TcCustomerResourcesDialog.value.showDialog = true
const searchFormRef = ref<FormInstance>() }
//
const selectData = ref<any[]>([])
// const searchFormRef = ref<FormInstance>()
const sourceList = ref([] as any[])
const sourceDictList = async () => { //
sourceList.value = await (await useDictionary('source')).data.dictionary const selectData = ref<any[]>([])
}
sourceDictList() //
const source_channelList = ref([] as any[]) const sourceList = ref([] as any[])
const source_channelDictList = async () => { const sourceDictList = async () => {
source_channelList.value = await ( sourceList.value = await (await useDictionary('source')).data.dictionary
await useDictionary('SourceChannel') }
).data.dictionary sourceDictList();
} const source_channelList = ref([] as any[])
source_channelDictList() const source_channelDictList = async () => {
const genderList = ref([] as any[]) source_channelList.value = await (await useDictionary('SourceChannel')).data.dictionary
const genderDictList = async () => { }
genderList.value = await (await useDictionary('zy_sex')).data.dictionary source_channelDictList();
} const genderList = ref([] as any[])
genderDictList() const genderDictList = async () => {
const purchasing_powerList = ref([] as any[]) genderList.value = await (await useDictionary('zy_sex')).data.dictionary
const purchasing_powerDictList = async () => { }
purchasing_powerList.value = await ( genderDictList();
await useDictionary('customer_purchasing_power') const purchasing_powerList = ref([] as any[])
).data.dictionary const purchasing_powerDictList = async () => {
} purchasing_powerList.value = await (await useDictionary('customer_purchasing_power')).data.dictionary
purchasing_powerDictList() }
const cognitive_ideaList = ref([] as any[]) purchasing_powerDictList();
const cognitive_ideaDictList = async () => { const cognitive_ideaList = ref([] as any[])
cognitive_ideaList.value = await ( const cognitive_ideaDictList = async () => {
await useDictionary('cognitive_concept') cognitive_ideaList.value = await (await useDictionary('cognitive_concept')).data.dictionary
).data.dictionary }
} cognitive_ideaDictList();
cognitive_ideaDictList() const initial_intentList = ref([] as any[])
const initial_intentList = ref([] as any[]) const initial_intentDictList = async () => {
const initial_intentDictList = async () => { initial_intentList.value = await (await useDictionary('preliminarycustomerintention')).data.dictionary
initial_intentList.value = await ( }
await useDictionary('preliminarycustomerintention') initial_intentDictList();
).data.dictionary const statusList = ref([] as any[])
} const statusDictList = async () => {
initial_intentDictList() statusList.value = await (await useDictionary('kh_status')).data.dictionary
const statusList = ref([] as any[]) }
const statusDictList = async () => { statusDictList();
statusList.value = await (await useDictionary('kh_status')).data.dictionary
}
statusDictList() /**
* 获取客户资源列表
/** */
* 获取客户资源列表 const loadCustomerResourcesList = (page : number = 1) => {
*/ customerResourcesTable.loading = true
const loadCustomerResourcesList = (page: number = 1) => { customerResourcesTable.page = page
customerResourcesTable.loading = true
customerResourcesTable.page = page getCustomerResourcesList({
page: customerResourcesTable.page,
getCustomerResourcesList({ limit: customerResourcesTable.limit,
page: customerResourcesTable.page, ...customerResourcesTable.searchParam
limit: customerResourcesTable.limit, }).then(res => {
...customerResourcesTable.searchParam, customerResourcesTable.loading = false
}) customerResourcesTable.data = res.data.data
.then((res) => { customerResourcesTable.total = res.data.total
customerResourcesTable.loading = false }).catch(() => {
customerResourcesTable.data = res.data.data customerResourcesTable.loading = false
customerResourcesTable.total = res.data.total })
}) }
.catch(() => { loadCustomerResourcesList()
customerResourcesTable.loading = false
}) const editCustomerResourcesDialog : Record<string, any> | null = ref(null)
}
loadCustomerResourcesList() const fpCustomerResourcesDialog : Record<string, any> | null = ref(null)
const editCustomerResourcesDialog: Record<string, any> | null = ref(null) /**
* 添加客户资源
const fpCustomerResourcesDialog: Record<string, any> | null = ref(null) */
const addEvent = () => {
/** editCustomerResourcesDialog.value.setFormData()
* 添加客户资源 editCustomerResourcesDialog.value.showDialog = true
*/ }
const addEvent = () => {
editCustomerResourcesDialog.value.setFormData() /**
editCustomerResourcesDialog.value.showDialog = true * 编辑客户资源
} * @param data
*/
/** const editEvent = (data : any) => {
* 编辑客户资源 editCustomerResourcesDialog.value.setFormData(data)
* @param data editCustomerResourcesDialog.value.showDialog = true
*/ }
const editEvent = (data: any) => {
editCustomerResourcesDialog.value.setFormData(data) const fpEvent = (data : any) => {
editCustomerResourcesDialog.value.showDialog = true fpCustomerResourcesDialog.value.setFormData(data)
} fpCustomerResourcesDialog.value.showDialog = true
}
const fpEvent = (data: any) => {
fpCustomerResourcesDialog.value.setFormData(data)
fpCustomerResourcesDialog.value.showDialog = true /**
} * 删除客户资源
*/
/** const deleteEvent = (id : number) => {
* 删除客户资源 ElMessageBox.confirm(t('customerResourcesDeleteTips'), t('warning'),
*/ {
const deleteEvent = (id: number) => { confirmButtonText: t('confirm'),
ElMessageBox.confirm(t('customerResourcesDeleteTips'), t('warning'), { cancelButtonText: t('cancel'),
confirmButtonText: t('confirm'), type: 'warning',
cancelButtonText: t('cancel'), }
type: 'warning', ).then(() => {
}).then(() => { deleteCustomerResources(id).then(() => {
deleteCustomerResources(id) loadCustomerResourcesList()
.then(() => { }).catch(() => {
loadCustomerResourcesList() })
}) })
.catch(() => {}) }
})
}
const consultantList = ref([])
const consultantList = ref([]) const setConsultantList = async () => {
const setConsultantList = async () => { consultantList.value = await (await getWithPersonnelList({})).data
consultantList.value = await (await getWithPersonnelList({})).data }
} setConsultantList()
setConsultantList() const campusList = ref([])
const campusList = ref([]) const setCampusList = async () => {
const setCampusList = async () => { campusList.value = await (await getWithCampusList({})).data
campusList.value = await (await getWithCampusList({})).data }
} setCampusList()
setCampusList()
const resetForm = (formEl : FormInstance | undefined) => {
const resetForm = (formEl: FormInstance | undefined) => { if (!formEl) return
if (!formEl) return formEl.resetFields()
formEl.resetFields() loadCustomerResourcesList()
loadCustomerResourcesList() }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

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

@ -25,7 +25,7 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="t('parentDepartmentId')" label="上级部门"
prop="parent_department_id" prop="parent_department_id"
> >
<el-select <el-select
@ -72,7 +72,7 @@
<el-table-column <el-table-column
prop="parent_department_id_name" prop="parent_department_id_name"
:label="t('parentDepartmentId')" label="上级部门"
min-width="120" min-width="120"
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
/> />

3
admin/src/app/views/member/components/edit-member.vue

@ -47,6 +47,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('memberLabel')" v-if="type == 'member_label'"> <el-form-item :label="t('memberLabel')" v-if="type == 'member_label'">
<el-select <el-select
v-model="saveData.member_label" v-model="saveData.member_label"
@ -63,6 +64,8 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<div v-if="type == 'member_level'"> <div v-if="type == 'member_level'">
<el-form-item :label="t('memberLevelUpdate')" prop="member_level"> <el-form-item :label="t('memberLevelUpdate')" prop="member_level">
<el-select <el-select

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

@ -1,126 +1,85 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateOrderTable') : t('addOrderTable')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateOrderTable') : t('addOrderTable')" <el-form-item :label="t('resourceId')" prop="resource_id">
width="50%" <el-select class="input-width" v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in resourceIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading" <!--
> <el-form-item :label="t('orderStatus')" prop="order_status">
<el-form-item :label="t('resourceId')" prop="resource_id"> <el-select class="input-width" v-model="formData.order_status" clearable :placeholder="t('orderStatusPlaceholder')">
<el-select <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
v-model="formData.resource_id" v-for="(item, index) in order_statusList"
clearable :key="index"
:placeholder="t('resourceIdPlaceholder')" :label="item.name"
> :value="item.value"
<el-option label="请选择" value=""></el-option> />
<el-option </el-select>
v-for="(item, index) in resourceIdList" </el-form-item> -->
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('orderStatus')" prop="order_status"> <el-form-item :label="t('paymentType')" prop="payment_type">
<el-select <el-select class="input-width" v-model="formData.payment_type" clearable :placeholder="t('paymentTypePlaceholder')">
class="input-width" <el-option label="请选择" value=""></el-option>
v-model="formData.order_status" <el-option
clearable v-for="(item, index) in payment_typeList"
:placeholder="t('orderStatusPlaceholder')" :key="index"
> :label="item.name"
<el-option label="请选择" value=""></el-option> :value="item.value"
<el-option />
v-for="(item, index) in order_statusList" </el-select>
:key="index" </el-form-item>
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('paymentType')" prop="payment_type"> <el-form-item :label="t('courseId')" prop="course_id">
<el-select <el-select class="input-width" v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')" @change="handleCourseChange">
class="input-width" <el-option label="请选择" value=""></el-option>
v-model="formData.payment_type" <el-option
clearable v-for="(item, index) in courseIdList"
:placeholder="t('paymentTypePlaceholder')" :key="index"
> :label="item['course_name']"
<el-option label="请选择" value=""></el-option> :value="item['id']"
<el-option />
v-for="(item, index) in payment_typeList" </el-select>
:key="index" </el-form-item>
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('orderAmount')" prop="order_amount">
<el-input
v-model="formData.order_amount"
clearable
:placeholder="t('orderAmountPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id"> <el-form-item :label="t('orderAmount')" prop="order_amount">
<el-select <el-input v-model="formData.order_amount" :placeholder="t('orderAmountPlaceholder')" class="input-width" disabled/>
class="input-width" </el-form-item>
v-model="formData.course_id"
clearable
:placeholder="t('courseIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in courseIdList"
:key="index"
:label="item['course_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id">
<el-select
class="input-width"
v-model="formData.class_id"
clearable
:placeholder="t('classIdPlaceholder')"
>
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in classIdList"
:key="index"
:label="item['class_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer"> <el-form-item :label="t('classId')" prop="class_id">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> <el-select class="input-width" v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')">
<el-button <el-option label="请选择" value=""></el-option>
type="primary" <el-option
:loading="loading" v-for="(item, index) in classIdList"
@click="confirm(formRef)" :key="index"
>{{ t('confirm') }}</el-button :label="item['class_name']"
> :value="item['id']"
</span> />
</template> </el-select>
</el-dialog> </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> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -128,30 +87,27 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { import { addOrderTable, editOrderTable, getOrderTableInfo, getWithCustomerResourcesList, getWithCourseList, getWithClassGradeList, getWithPersonnelList } from '@/app/api/order_table'
addOrderTable,
editOrderTable,
getOrderTableInfo,
getWithCustomerResourcesList,
getWithCourseList,
getWithClassGradeList,
getWithPersonnelList,
} from '@/app/api/order_table'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
function handleCourseChange(selectedId) {
const selectedCourse = courseIdList.value.find(item => item.id === selectedId)
formData.order_amount = selectedCourse ? selectedCourse.price : ''
}
/** /**
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
resource_id: '', resource_id: '',
order_status: '', // order_status: '',
payment_type: '', payment_type: '',
order_amount: '', order_amount: '',
course_id: '', course_id: '',
class_id: '', class_id: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -159,26 +115,33 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
resource_id: [ resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
],
order_status: [ ]
{ required: true, message: t('orderStatusPlaceholder'), trigger: 'blur' }, ,
],
payment_type: [ payment_type: [
{ required: true, message: t('paymentTypePlaceholder'), trigger: 'blur' }, { required: true, message: t('paymentTypePlaceholder'), trigger: 'blur' },
],
]
,
order_amount: [ order_amount: [
{ required: true, message: t('orderAmountPlaceholder'), trigger: 'blur' }, { required: true, message: t('orderAmountPlaceholder'), trigger: 'blur' },
],
]
,
course_id: [ course_id: [
{ required: true, message: t('courseIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('courseIdPlaceholder'), trigger: 'blur' },
],
]
,
class_id: [ class_id: [
{ required: true, message: t('classIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('classIdPlaceholder'), trigger: 'blur' },
],
} ]
,
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -188,141 +151,122 @@ const emit = defineEmits(['complete'])
* @param formEl * @param formEl
*/ */
const confirm = async (formEl: FormInstance | undefined) => { const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return if (loading.value || !formEl) return
let save = formData.id ? editOrderTable : addOrderTable let save = formData.id ? editOrderTable : addOrderTable
await formEl.validate(async (valid) => { await formEl.validate(async (valid) => {
if (valid) { if (valid) {
loading.value = true loading.value = true
let data = formData let data = formData
save(data) save(data).then(res => {
.then((res) => { loading.value = false
loading.value = false showDialog.value = false
showDialog.value = false emit('complete')
emit('complete') }).catch(err => {
}) loading.value = false
.catch((err) => { })
loading.value = false }
}) })
}
})
} }
// //
let order_statusList = ref([]) // let order_statusList = ref([])
const order_statusDictList = async () => { // const order_statusDictList = async () => {
order_statusList.value = await ( // order_statusList.value = await (await useDictionary('order_status')).data.dictionary
await useDictionary('order_status') // }
).data.dictionary // order_statusDictList();
} // watch(() => order_statusList.value, () => { formData.order_status = order_statusList.value[0].value })
order_statusDictList() let payment_typeList = ref([])
watch( const payment_typeDictList = async () => {
() => order_statusList.value, payment_typeList.value = await (await useDictionary('payment_type')).data.dictionary
() => { }
formData.order_status = order_statusList.value[0].value payment_typeDictList();
} watch(() => payment_typeList.value, () => { formData.payment_type = payment_typeList.value[0].value })
)
let payment_typeList = ref([])
const payment_typeDictList = async () => {
payment_typeList.value = await (
await useDictionary('payment_type')
).data.dictionary
}
payment_typeDictList()
watch(
() => payment_typeList.value,
() => {
formData.payment_type = payment_typeList.value[0].value
}
)
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data const resourceIdList = ref([] as any[])
} const setResourceIdList = async () => {
setResourceIdList() resourceIdList.value = await (await getWithCustomerResourcesList({})).data
const courseIdList = ref([] as any[]) }
const setCourseIdList = async () => { setResourceIdList()
courseIdList.value = await (await getWithCourseList({})).data const courseIdList = ref([] as any[])
} const setCourseIdList = async () => {
setCourseIdList() courseIdList.value = await (await getWithCourseList({})).data
const classIdList = ref([] as any[]) }
const setClassIdList = async () => { setCourseIdList()
classIdList.value = await (await getWithClassGradeList({})).data const classIdList = ref([] as any[])
} const setClassIdList = async () => {
setClassIdList() classIdList.value = await (await getWithClassGradeList({})).data
const staffIdList = ref([] as any[]) }
const setStaffIdList = async () => { setClassIdList()
staffIdList.value = await (await getWithPersonnelList({})).data const staffIdList = ref([] as any[])
} const setStaffIdList = async () => {
setStaffIdList() staffIdList.value = await (await getWithPersonnelList({})).data
}
setStaffIdList()
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
Object.assign(formData, row) Object.assign(formData, row)
// formData.resource_id = row.resource_id; // formData.resource_id = row.resource_id;
// console.log(0) // console.log(0)
// loading.value = true // loading.value = true
// if(row){ // if(row){
// const data = await (await getOrderTableInfo(row.id)).data // const data = await (await getOrderTableInfo(row.id)).data
// if (data) Object.keys(formData).forEach((key: string) => { // if (data) Object.keys(formData).forEach((key: string) => {
// if (data[key] != undefined) formData[key] = data[key] // if (data[key] != undefined) formData[key] = data[key]
// }) // })
// } // }
// loading.value = false // loading.value = false
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateMobile')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const idCardVerify = (rule: any, value: any, callback: any) => {
if ( 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)) {
value && callback(new Error(t('generateIdCard')))
!/^[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( } else {
value callback()
) }
) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
} }
// //
const emailVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const numberVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber'))) callback(new Error(t('generateNumber')))
} else { } else {
callback() callback()
} }
} }
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData, setFormData
}) })
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>
<style lang="scss"> <style lang="scss">
.diy-dialog-wrap .el-form-item__label { .diy-dialog-wrap .el-form-item__label{
height: auto !important; height: auto !important;
} }
</style> </style>

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

@ -1,236 +1,209 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateReimbursement') : t('addReimbursement')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateReimbursement') : t('addReimbursement')" <el-form-item :label="t('applicantId')" prop="applicant_id">
width="50%" <el-select class="input-width" v-model="formData.applicant_id" clearable :placeholder="t('applicantIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in applicantIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('amount')" prop="amount">
<el-form-item :label="t('applicantId')" prop="applicant_id"> <el-input v-model="formData.amount" clearable :placeholder="t('amountPlaceholder')" class="input-width" />
<el-input </el-form-item>
v-model="formData.applicant_id"
clearable <el-form-item :label="t('description')" prop="description">
:placeholder="t('applicantIdPlaceholder')" <el-input v-model="formData.description" clearable :placeholder="t('descriptionPlaceholder')" class="input-width" />
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('receiptUrl')">
<upload-file v-model="formData.receipt_url" />
<el-form-item :label="t('amount')" prop="amount"> </el-form-item>
<el-input
v-model="formData.amount" <el-form-item :label="t('status')" prop="status">
clearable <el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('amountPlaceholder')" <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
/> v-for="(item, index) in statusList"
</el-form-item> :key="index"
:label="item.name"
<el-form-item :label="t('description')" prop="description"> :value="item.value"
<el-input />
v-model="formData.description" </el-select>
clearable </el-form-item>
:placeholder="t('descriptionPlaceholder')"
class="input-width" </el-form>
/>
</el-form-item> <template #footer>
<span class="dialog-footer">
<el-form-item :label="t('receiptUrl')"> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-input <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
v-model="formData.receipt_url" t('confirm')
clearable }}</el-button>
:placeholder="t('receiptUrlPlaceholder')" </span>
class="input-width" </template>
/> </el-dialog>
</el-form-item> </template>
<el-form-item :label="t('status')" prop="status"> <script lang="ts" setup>
<el-input import { ref, reactive, computed, watch } from 'vue'
v-model="formData.status" import { useDictionary } from '@/app/api/dict'
clearable import { t } from '@/lang'
:placeholder="t('statusPlaceholder')" import type { FormInstance } from 'element-plus'
class="input-width" import { addReimbursement, editReimbursement, getReimbursementInfo, getWithPersonnelList } from '@/app/api/reimbursement'
/>
</el-form-item> let showDialog = ref(false)
const loading = ref(false)
<el-form-item :label="t('processId')" prop="process_id">
<el-input /**
v-model="formData.process_id" * 表单数据
clearable */
:placeholder="t('processIdPlaceholder')" const initialFormData = {
class="input-width" id: '',
/> applicant_id: '',
</el-form-item> amount: '',
</el-form> description: '',
receipt_url: '',
<template #footer> status: '',
<span class="dialog-footer"> }
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> const formData: Record<string, any> = reactive({ ...initialFormData })
<el-button
type="primary" const formRef = ref<FormInstance>()
:loading="loading"
@click="confirm(formRef)" //
>{{ t('confirm') }}</el-button const formRules = computed(() => {
> return {
</span> applicant_id: [
</template> { required: true, message: t('applicantIdPlaceholder'), trigger: 'blur' },
</el-dialog>
</template> ]
,
<script lang="ts" setup> amount: [
import { ref, reactive, computed, watch } from 'vue' { required: true, message: t('amountPlaceholder'), trigger: 'blur' },
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' ]
import type { FormInstance } from 'element-plus' ,
import { description: [
addReimbursement, { required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
editReimbursement,
getReimbursementInfo, ]
} from '@/app/api/reimbursement' ,
receipt_url: [
let showDialog = ref(false) { required: true, message: t('receiptUrlPlaceholder'), trigger: 'blur' },
const loading = ref(false)
]
/** ,
* 表单数据 status: [
*/ { required: true, message: t('statusPlaceholder'), trigger: 'blur' },
const initialFormData = {
id: '', ]
applicant_id: '', ,
amount: '', }
description: '', })
receipt_url: '',
status: '', const emit = defineEmits(['complete'])
process_id: '',
} /**
const formData: Record<string, any> = reactive({ ...initialFormData }) * 确认
* @param formEl
const formRef = ref<FormInstance>() */
const confirm = async (formEl: FormInstance | undefined) => {
// if (loading.value || !formEl) return
const formRules = computed(() => { let save = formData.id ? editReimbursement : addReimbursement
return {
applicant_id: [ await formEl.validate(async (valid) => {
{ required: true, message: t('applicantIdPlaceholder'), trigger: 'blur' }, if (valid) {
], loading.value = true
amount: [
{ required: true, message: t('amountPlaceholder'), trigger: 'blur' }, let data = formData
],
description: [ save(data).then(res => {
{ required: true, message: t('descriptionPlaceholder'), trigger: 'blur' }, loading.value = false
], showDialog.value = false
receipt_url: [ emit('complete')
{ required: true, message: t('receiptUrlPlaceholder'), trigger: 'blur' }, }).catch(err => {
], loading.value = false
status: [ })
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' }, }
], })
process_id: [ }
{ required: true, message: t('processIdPlaceholder'), trigger: 'blur' },
], //
} let statusList = ref([])
}) const statusDictList = async () => {
statusList.value = await (await useDictionary('sp_status')).data.dictionary
const emit = defineEmits(['complete']) }
statusDictList();
/** watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
* 确认
* @param formEl
*/ const applicantIdList = ref([] as any[])
const confirm = async (formEl: FormInstance | undefined) => { const setApplicantIdList = async () => {
if (loading.value || !formEl) return applicantIdList.value = await (await getWithPersonnelList({})).data
let save = formData.id ? editReimbursement : addReimbursement }
setApplicantIdList()
await formEl.validate(async (valid) => { const setFormData = async (row: any = null) => {
if (valid) { Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if(row){
let data = formData const data = await (await getReimbursementInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => {
save(data) if (data[key] != undefined) formData[key] = data[key]
.then((res) => { })
loading.value = false }
showDialog.value = false loading.value = false
emit('complete') }
})
.catch((err) => { //
loading.value = false const mobileVerify = (rule: any, value: any, callback: any) => {
}) if (value && !/^1[3-9]\d{9}$/.test(value)) {
} callback(new Error(t('generateMobile')))
}) } else {
} callback()
}
// }
const setFormData = async (row: any = null) => { //
Object.assign(formData, initialFormData) const idCardVerify = (rule: any, value: any, callback: any) => {
loading.value = true if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
if (row) { callback(new Error(t('generateIdCard')))
const data = await (await getReimbursementInfo(row.id)).data } else {
if (data) callback()
Object.keys(formData).forEach((key: string) => { }
if (data[key] != undefined) formData[key] = data[key] }
})
} //
loading.value = false const emailVerify = (rule: any, value: any, callback: any) => {
} if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
// } else {
const mobileVerify = (rule: any, value: any, callback: any) => { callback()
if (value && !/^1[3-9]\d{9}$/.test(value)) { }
callback(new Error(t('generateMobile'))) }
} else {
callback() //
} const numberVerify = (rule: any, value: any, callback: any) => {
} if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
// } else {
const idCardVerify = (rule: any, value: any, callback: any) => { callback()
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 defineExpose({
) showDialog,
) { setFormData
callback(new Error(t('generateIdCard'))) })
} else { </script>
callback()
} <style lang="scss" scoped></style>
} <style lang="scss">
.diy-dialog-wrap .el-form-item__label{
// height: auto !important;
const emailVerify = (rule: any, value: any, callback: any) => { }
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { </style>
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>

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

@ -1,265 +1,200 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addReimbursement') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addReimbursement') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="reimbursementTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('status')" prop="status">
:inline="true" <el-select class="w-[280px]" v-model="reimbursementTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
:model="reimbursementTable.searchParam" <el-option label="全部" value=""></el-option>
ref="searchFormRef" <el-option
> v-for="(item, index) in statusList"
<el-form-item :label="t('applicantId')" prop="applicant_id"> :key="index"
<el-input :label="item.name"
v-model="reimbursementTable.searchParam.applicant_id" :value="item.value"
:placeholder="t('applicantIdPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('amount')" prop="amount">
<el-input <el-form-item :label="t('createdAt')" prop="created_at">
v-model="reimbursementTable.searchParam.amount" <el-date-picker v-model="reimbursementTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('amountPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('description')" prop="description"> <el-form-item>
<el-input <el-button type="primary" @click="loadReimbursementList()">{{ t('search') }}</el-button>
v-model="reimbursementTable.searchParam.description" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('descriptionPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('receiptUrl')" prop="receipt_url">
<el-input <div class="mt-[10px]">
v-model="reimbursementTable.searchParam.receipt_url" <el-table :data="reimbursementTable.data" size="large" v-loading="reimbursementTable.loading">
:placeholder="t('receiptUrlPlaceholder')" <template #empty>
/> <span>{{ !reimbursementTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-form-item :label="t('status')" prop="status"> <el-table-column prop="applicant_id_name" :label="t('applicantId')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="reimbursementTable.searchParam.status" <el-table-column prop="amount" :label="t('amount')" min-width="120" :show-overflow-tooltip="true"/>
:placeholder="t('statusPlaceholder')"
/> <el-table-column prop="description" :label="t('description')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('processId')" prop="process_id"> <el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-input <template #default="{ row }">
v-model="reimbursementTable.searchParam.process_id" <div v-for="(item, index) in statusList">
:placeholder="t('processIdPlaceholder')" <div v-if="item.value == row.status">{{ item.name }}</div>
/> </div>
</el-form-item> </template>
</el-table-column>
<el-form-item>
<el-button type="primary" @click="loadReimbursementList()">{{ <el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-button @click="resetForm(searchFormRef)">{{
t('reset') <el-table-column :label="t('operation')" fixed="right" min-width="120">
}}</el-button> <template #default="{ row }">
</el-form-item> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
</el-form> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</el-card> </template>
</el-table-column>
<div class="mt-[10px]">
<el-table </el-table>
:data="reimbursementTable.data" <div class="mt-[16px] flex justify-end">
size="large" <el-pagination v-model:current-page="reimbursementTable.page" v-model:page-size="reimbursementTable.limit"
v-loading="reimbursementTable.loading" layout="total, sizes, prev, pager, next, jumper" :total="reimbursementTable.total"
> @size-change="loadReimbursementList()" @current-change="loadReimbursementList" />
<template #empty> </div>
<span>{{ !reimbursementTable.loading ? t('emptyData') : '' }}</span> </div>
</template>
<el-table-column <edit ref="editReimbursementDialog" @complete="loadReimbursementList" />
prop="applicant_id" </el-card>
:label="t('applicantId')" </div>
min-width="120" </template>
:show-overflow-tooltip="true"
/> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
<el-table-column import { t } from '@/lang'
prop="amount" import { useDictionary } from '@/app/api/dict'
:label="t('amount')" import { getReimbursementList, deleteReimbursement, getWithPersonnelList } from '@/app/api/reimbursement'
min-width="120" import { img } from '@/utils/common'
:show-overflow-tooltip="true" import { ElMessageBox,FormInstance } from 'element-plus'
/> import Edit from '@/app/views/reimbursement/components/reimbursement-edit.vue'
import { useRoute } from 'vue-router'
<el-table-column const route = useRoute()
prop="description" const pageName = route.meta.title;
:label="t('description')"
min-width="120" let reimbursementTable = reactive({
:show-overflow-tooltip="true" page: 1,
/> limit: 10,
total: 0,
<el-table-column loading: true,
prop="receipt_url" data: [],
:label="t('receiptUrl')" searchParam:{
min-width="120" "status":"",
:show-overflow-tooltip="true" "created_at":[]
/> }
})
<el-table-column
prop="status" const searchFormRef = ref<FormInstance>()
:label="t('status')"
min-width="120" //
:show-overflow-tooltip="true" const selectData = ref<any[]>([])
/>
//
<el-table-column const statusList = ref([] as any[])
prop="process_id" const statusDictList = async () => {
:label="t('processId')" statusList.value = await (await useDictionary('sp_status')).data.dictionary
min-width="120" }
:show-overflow-tooltip="true" statusDictList();
/>
/**
<el-table-column * 获取报销记录列表
:label="t('operation')" */
fixed="right" const loadReimbursementList = (page: number = 1) => {
min-width="120" reimbursementTable.loading = true
> reimbursementTable.page = page
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ getReimbursementList({
t('edit') page: reimbursementTable.page,
}}</el-button> limit: reimbursementTable.limit,
<el-button type="primary" link @click="deleteEvent(row.id)">{{ ...reimbursementTable.searchParam
t('delete') }).then(res => {
}}</el-button> reimbursementTable.loading = false
</template> reimbursementTable.data = res.data.data
</el-table-column> reimbursementTable.total = res.data.total
</el-table> }).catch(() => {
<div class="mt-[16px] flex justify-end"> reimbursementTable.loading = false
<el-pagination })
v-model:current-page="reimbursementTable.page" }
v-model:page-size="reimbursementTable.limit" loadReimbursementList()
layout="total, sizes, prev, pager, next, jumper"
:total="reimbursementTable.total" const editReimbursementDialog: Record<string, any> | null = ref(null)
@size-change="loadReimbursementList()"
@current-change="loadReimbursementList" /**
/> * 添加报销记录
</div> */
</div> const addEvent = () => {
editReimbursementDialog.value.setFormData()
<edit ref="editReimbursementDialog" @complete="loadReimbursementList" /> editReimbursementDialog.value.showDialog = true
</el-card> }
</div>
</template> /**
* 编辑报销记录
<script lang="ts" setup> * @param data
import { reactive, ref, watch } from 'vue' */
import { t } from '@/lang' const editEvent = (data: any) => {
import { useDictionary } from '@/app/api/dict' editReimbursementDialog.value.setFormData(data)
import { editReimbursementDialog.value.showDialog = true
getReimbursementList, }
deleteReimbursement,
} from '@/app/api/reimbursement' /**
import { img } from '@/utils/common' * 删除报销记录
import { ElMessageBox, FormInstance } from 'element-plus' */
import Edit from '@/app/views/reimbursement/components/reimbursement-edit.vue' const deleteEvent = (id: number) => {
import { useRoute } from 'vue-router' ElMessageBox.confirm(t('reimbursementDeleteTips'), t('warning'),
const route = useRoute() {
const pageName = route.meta.title confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
let reimbursementTable = reactive({ type: 'warning',
page: 1, }
limit: 10, ).then(() => {
total: 0, deleteReimbursement(id).then(() => {
loading: true, loadReimbursementList()
data: [], }).catch(() => {
searchParam: { })
applicant_id: '', })
amount: '', }
description: '',
receipt_url: '',
status: '', const applicantIdList = ref([])
process_id: '', const setApplicantIdList = async () => {
}, applicantIdList.value = await (await getWithPersonnelList({})).data
}) }
setApplicantIdList()
const searchFormRef = ref<FormInstance>()
const resetForm = (formEl: FormInstance | undefined) => {
// if (!formEl) return
const selectData = ref<any[]>([]) formEl.resetFields()
loadReimbursementList()
// }
</script>
/**
* 获取报销记录列表 <style lang="scss" scoped>
*/ /* 多行超出隐藏 */
const loadReimbursementList = (page: number = 1) => { .multi-hidden {
reimbursementTable.loading = true word-break: break-all;
reimbursementTable.page = page text-overflow: ellipsis;
overflow: hidden;
getReimbursementList({ display: -webkit-box;
page: reimbursementTable.page, -webkit-line-clamp: 2;
limit: reimbursementTable.limit, -webkit-box-orient: vertical;
...reimbursementTable.searchParam, }
}) </style>
.then((res) => {
reimbursementTable.loading = false
reimbursementTable.data = res.data.data
reimbursementTable.total = res.data.total
})
.catch(() => {
reimbursementTable.loading = false
})
}
loadReimbursementList()
const editReimbursementDialog: Record<string, any> | null = ref(null)
/**
* 添加报销记录
*/
const addEvent = () => {
editReimbursementDialog.value.setFormData()
editReimbursementDialog.value.showDialog = true
}
/**
* 编辑报销记录
* @param data
*/
const editEvent = (data: any) => {
editReimbursementDialog.value.setFormData(data)
editReimbursementDialog.value.showDialog = true
}
/**
* 删除报销记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('reimbursementDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteReimbursement(id)
.then(() => {
loadReimbursementList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadReimbursementList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

621
admin/src/app/views/salary/components/salary-edit.vue

@ -1,330 +1,291 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateSalary') : t('addSalary')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateSalary') : t('addSalary')" <el-form-item :label="t('staffId')" prop="staff_id">
width="50%" <el-select class="input-width" v-model="formData.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in staffIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('departmentId')" prop="department_id">
<el-form-item :label="t('staffId')" prop="staff_id"> <el-select class="input-width" v-model="formData.department_id" clearable :placeholder="t('departmentIdPlaceholder')">
<el-input <el-option label="请选择" value=""></el-option>
v-model="formData.staff_id" <el-option
clearable v-for="(item, index) in departmentIdList"
:placeholder="t('staffIdPlaceholder')" :key="index"
class="input-width" :label="item['department_name']"
/> :value="item['id']"
</el-form-item> />
</el-select>
<el-form-item :label="t('baseSalary')" prop="base_salary"> </el-form-item>
<el-input
v-model="formData.base_salary" <el-form-item :label="t('baseSalary')" prop="base_salary">
clearable <el-input v-model="formData.base_salary" clearable :placeholder="t('baseSalaryPlaceholder')" class="input-width" />
:placeholder="t('baseSalaryPlaceholder')" </el-form-item>
class="input-width"
/> <el-form-item :label="t('performanceBonus')" prop="performance_bonus">
</el-form-item> <el-input v-model="formData.performance_bonus" clearable :placeholder="t('performanceBonusPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('performanceBonus')" prop="performance_bonus">
<el-input <el-form-item :label="t('deductions')" prop="deductions">
v-model="formData.performance_bonus" <el-input v-model="formData.deductions" clearable :placeholder="t('deductionsPlaceholder')" class="input-width" />
clearable </el-form-item>
:placeholder="t('performanceBonusPlaceholder')"
class="input-width" <el-form-item :label="t('otherSubsidies')" prop="other_subsidies">
/> <el-input v-model="formData.other_subsidies" clearable :placeholder="t('otherSubsidiesPlaceholder')" class="input-width" />
</el-form-item> </el-form-item>
<el-form-item :label="t('deductions')" prop="deductions"> <el-form-item :label="t('paymentStatus')" prop="payment_status">
<el-input <el-select class="input-width" v-model="formData.payment_status" clearable :placeholder="t('paymentStatusPlaceholder')">
v-model="formData.deductions" <el-option label="请选择" value=""></el-option>
clearable <el-option
:placeholder="t('deductionsPlaceholder')" v-for="(item, index) in payment_statusList"
class="input-width" :key="index"
/> :label="item.name"
</el-form-item> :value="item.value"
/>
<el-form-item :label="t('otherSubsidies')"> </el-select>
<el-input </el-form-item>
v-model="formData.other_subsidies"
clearable <el-form-item :label="t('paymentMethod')" prop="payment_method">
:placeholder="t('otherSubsidiesPlaceholder')" <el-select class="input-width" v-model="formData.payment_method" clearable :placeholder="t('paymentMethodPlaceholder')">
class="input-width" <el-option label="请选择" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in payment_methodList"
:key="index"
<el-form-item :label="t('netSalary')"> :label="item.name"
<el-input :value="item.value"
v-model="formData.net_salary" />
clearable </el-select>
:placeholder="t('netSalaryPlaceholder')" </el-form-item>
class="input-width"
/> <el-form-item :label="t('remarks')" >
</el-form-item> <el-input v-model="formData.remarks" type="textarea" rows="4" clearable :placeholder="t('remarksPlaceholder')" class="input-width"/>
</el-form-item>
<el-form-item :label="t('paymentStatus')" prop="payment_status"> <el-form-item :label="t('salaryMonth')" prop="salary_month" class="input-width">
<el-input <el-date-picker
v-model="formData.payment_status" class="flex-1 !flex"
clearable v-model="formData.salary_month"
:placeholder="t('paymentStatusPlaceholder')" clearable
class="input-width" type="date"
/> value-format="YYYY-MM-DD"
</el-form-item> :placeholder="t('salaryMonthPlaceholder')">
</el-date-picker>
<el-form-item :label="t('paymentMethod')"> </el-form-item>
<el-input </el-form>
v-model="formData.payment_method"
clearable <template #footer>
:placeholder="t('paymentMethodPlaceholder')" <span class="dialog-footer">
class="input-width" <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
/> <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
</el-form-item> t('confirm')
}}</el-button>
<el-form-item :label="t('remarks')"> </span>
<el-input </template>
v-model="formData.remarks" </el-dialog>
clearable </template>
:placeholder="t('remarksPlaceholder')"
class="input-width" <script lang="ts" setup>
/> import { ref, reactive, computed, watch } from 'vue'
</el-form-item> import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
<el-form-item :label="t('salaryMonth')" prop="salary_month"> import type { FormInstance } from 'element-plus'
<el-input import { addSalary, editSalary, getSalaryInfo, getWithPersonnelList, getWithDepartmentsList } from '@/app/api/salary'
v-model="formData.salary_month"
clearable let showDialog = ref(false)
:placeholder="t('salaryMonthPlaceholder')" const loading = ref(false)
class="input-width"
/> /**
</el-form-item> * 表单数据
*/
<el-form-item :label="t('departmentId')"> const initialFormData = {
<el-input id: '',
v-model="formData.department_id" staff_id: '',
clearable department_id: '',
:placeholder="t('departmentIdPlaceholder')" base_salary: '',
class="input-width" performance_bonus: '',
/> deductions: '',
</el-form-item> other_subsidies: '',
payment_status: '',
<el-form-item :label="t('processId')"> payment_method: '',
<el-input remarks: '',
v-model="formData.process_id" salary_month: '',
clearable }
:placeholder="t('processIdPlaceholder')" const formData: Record<string, any> = reactive({ ...initialFormData })
class="input-width"
/> const formRef = ref<FormInstance>()
</el-form-item>
</el-form> //
const formRules = computed(() => {
<template #footer> return {
<span class="dialog-footer"> staff_id: [
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> { required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
<el-button
type="primary" ]
:loading="loading" ,
@click="confirm(formRef)" department_id: [
>{{ t('confirm') }}</el-button { required: true, message: t('departmentIdPlaceholder'), trigger: 'blur' },
>
</span> ]
</template> ,
</el-dialog> base_salary: [
</template> { required: true, message: t('baseSalaryPlaceholder'), trigger: 'blur' },
<script lang="ts" setup> ]
import { ref, reactive, computed, watch } from 'vue' ,
import { useDictionary } from '@/app/api/dict' performance_bonus: [
import { t } from '@/lang' { required: true, message: t('performanceBonusPlaceholder'), trigger: 'blur' },
import type { FormInstance } from 'element-plus'
import { addSalary, editSalary, getSalaryInfo } from '@/app/api/salary' ]
,
let showDialog = ref(false) deductions: [
const loading = ref(false) { required: true, message: t('deductionsPlaceholder'), trigger: 'blur' },
/** ]
* 表单数据 ,
*/ other_subsidies: [
const initialFormData = { { required: true, message: t('otherSubsidiesPlaceholder'), trigger: 'blur' },
id: '',
staff_id: '', ]
base_salary: '', ,
performance_bonus: '', payment_status: [
deductions: '', { required: true, message: t('paymentStatusPlaceholder'), trigger: 'blur' },
other_subsidies: '',
net_salary: '', ]
payment_status: '', ,
payment_method: '', payment_method: [
remarks: '', { required: true, message: t('paymentMethodPlaceholder'), trigger: 'blur' },
salary_month: '',
department_id: '', ]
process_id: '', ,
} remarks: [
const formData: Record<string, any> = reactive({ ...initialFormData }) { required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
const formRef = ref<FormInstance>() ]
,
// salary_month: [
const formRules = computed(() => { { required: true, message: t('salaryMonthPlaceholder'), trigger: 'blur' },
return {
staff_id: [ ]
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' }, ,
], }
base_salary: [ })
{ required: true, message: t('baseSalaryPlaceholder'), trigger: 'blur' },
], const emit = defineEmits(['complete'])
performance_bonus: [
{ /**
required: true, * 确认
message: t('performanceBonusPlaceholder'), * @param formEl
trigger: 'blur', */
}, const confirm = async (formEl: FormInstance | undefined) => {
], if (loading.value || !formEl) return
deductions: [ let save = formData.id ? editSalary : addSalary
{ required: true, message: t('deductionsPlaceholder'), trigger: 'blur' },
], await formEl.validate(async (valid) => {
other_subsidies: [ if (valid) {
{ loading.value = true
required: true,
message: t('otherSubsidiesPlaceholder'), let data = formData
trigger: 'blur',
}, save(data).then(res => {
], loading.value = false
net_salary: [ showDialog.value = false
{ required: true, message: t('netSalaryPlaceholder'), trigger: 'blur' }, emit('complete')
], }).catch(err => {
payment_status: [ loading.value = false
{ })
required: true, }
message: t('paymentStatusPlaceholder'), })
trigger: 'blur', }
},
], //
payment_method: [ let payment_statusList = ref([])
{ const payment_statusDictList = async () => {
required: true, payment_statusList.value = await (await useDictionary('payment_status')).data.dictionary
message: t('paymentMethodPlaceholder'), }
trigger: 'blur', payment_statusDictList();
}, watch(() => payment_statusList.value, () => { formData.payment_status = payment_statusList.value[0].value })
], let payment_methodList = ref([])
remarks: [ const payment_methodDictList = async () => {
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' }, payment_methodList.value = await (await useDictionary('payment_method')).data.dictionary
], }
salary_month: [ payment_methodDictList();
{ required: true, message: t('salaryMonthPlaceholder'), trigger: 'blur' }, watch(() => payment_methodList.value, () => { formData.payment_method = payment_methodList.value[0].value })
],
department_id: [
{ const staffIdList = ref([] as any[])
required: true, const setStaffIdList = async () => {
message: t('departmentIdPlaceholder'), staffIdList.value = await (await getWithPersonnelList({})).data
trigger: 'blur', }
}, setStaffIdList()
], const departmentIdList = ref([] as any[])
process_id: [ const setDepartmentIdList = async () => {
{ required: true, message: t('processIdPlaceholder'), trigger: 'blur' }, departmentIdList.value = await (await getWithDepartmentsList({})).data
], }
} setDepartmentIdList()
}) const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
const emit = defineEmits(['complete']) loading.value = true
if(row){
/** const data = await (await getSalaryInfo(row.id)).data
* 确认 if (data) Object.keys(formData).forEach((key: string) => {
* @param formEl if (data[key] != undefined) formData[key] = data[key]
*/ })
const confirm = async (formEl: FormInstance | undefined) => { }
if (loading.value || !formEl) return loading.value = false
let save = formData.id ? editSalary : addSalary }
await formEl.validate(async (valid) => { //
if (valid) { const mobileVerify = (rule: any, value: any, callback: any) => {
loading.value = true if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
let data = formData } else {
callback()
save(data) }
.then((res) => { }
loading.value = false
showDialog.value = false //
emit('complete') 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)) {
.catch((err) => { callback(new Error(t('generateIdCard')))
loading.value = false } else {
}) callback()
} }
}) }
}
//
// const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
const setFormData = async (row: any = null) => { callback(new Error(t('generateEmail')))
Object.assign(formData, initialFormData) } else {
loading.value = true callback()
if (row) { }
const data = await (await getSalaryInfo(row.id)).data }
if (data)
Object.keys(formData).forEach((key: string) => { //
if (data[key] != undefined) formData[key] = data[key] const numberVerify = (rule: any, value: any, callback: any) => {
}) if (!Number.isInteger(value)) {
} callback(new Error(t('generateNumber')))
loading.value = false } else {
} callback()
}
// }
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { defineExpose({
callback(new Error(t('generateMobile'))) showDialog,
} else { setFormData
callback() })
} </script>
}
<style lang="scss" scoped></style>
// <style lang="scss">
const idCardVerify = (rule: any, value: any, callback: any) => { .diy-dialog-wrap .el-form-item__label{
if ( height: auto !important;
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( </style>
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>

592
admin/src/app/views/salary/salary.vue

@ -1,346 +1,246 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addSalary') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addSalary') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="salaryTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('staffId')" prop="staff_id">
:inline="true" <el-select class="w-[280px]" v-model="salaryTable.searchParam.staff_id" clearable :placeholder="t('staffIdPlaceholder')">
:model="salaryTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in staffIdList"
> :key="index"
<el-form-item :label="t('staffId')" prop="staff_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="salaryTable.searchParam.staff_id" />
:placeholder="t('staffIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('baseSalary')" prop="base_salary">
<el-input <el-form-item :label="t('departmentId')" prop="department_id">
v-model="salaryTable.searchParam.base_salary" <el-select class="w-[280px]" v-model="salaryTable.searchParam.department_id" clearable :placeholder="t('departmentIdPlaceholder')">
:placeholder="t('baseSalaryPlaceholder')" <el-option
/> v-for="(item, index) in departmentIdList"
</el-form-item> :key="index"
<el-form-item :label="t('performanceBonus')" prop="performance_bonus"> :label="item['department_name']"
<el-input :value="item['id']"
v-model="salaryTable.searchParam.performance_bonus" />
:placeholder="t('performanceBonusPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('deductions')" prop="deductions">
<el-input <el-form-item :label="t('paymentStatus')" prop="payment_status">
v-model="salaryTable.searchParam.deductions" <el-select class="w-[280px]" v-model="salaryTable.searchParam.payment_status" clearable :placeholder="t('paymentStatusPlaceholder')">
:placeholder="t('deductionsPlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in payment_statusList"
<el-form-item :label="t('otherSubsidies')" prop="other_subsidies"> :key="index"
<el-input :label="item.name"
v-model="salaryTable.searchParam.other_subsidies" :value="item.value"
:placeholder="t('otherSubsidiesPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('netSalary')" prop="net_salary">
<el-input <el-form-item :label="t('createdAt')" prop="created_at">
v-model="salaryTable.searchParam.net_salary" <el-date-picker v-model="salaryTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('netSalaryPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('paymentStatus')" prop="payment_status"> <el-form-item>
<el-input <el-button type="primary" @click="loadSalaryList()">{{ t('search') }}</el-button>
v-model="salaryTable.searchParam.payment_status" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('paymentStatusPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('paymentMethod')" prop="payment_method">
<el-input <div class="mt-[10px]">
v-model="salaryTable.searchParam.payment_method" <el-table :data="salaryTable.data" size="large" v-loading="salaryTable.loading">
:placeholder="t('paymentMethodPlaceholder')" <template #empty>
/> <span>{{ !salaryTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-form-item :label="t('remarks')" prop="remarks"> <el-table-column prop="staff_id_name" :label="t('staffId')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="salaryTable.searchParam.remarks" <el-table-column prop="department_id_name" :label="t('departmentId')" min-width="120" :show-overflow-tooltip="true"/>
:placeholder="t('remarksPlaceholder')"
/> <el-table-column prop="net_salary" :label="t('netSalary')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('salaryMonth')" prop="salary_month"> <el-table-column :label="t('paymentStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-input <template #default="{ row }">
v-model="salaryTable.searchParam.salary_month" <div v-for="(item, index) in payment_statusList">
:placeholder="t('salaryMonthPlaceholder')" <div v-if="item.value == row.payment_status">{{ item.name }}</div>
/> </div>
</el-form-item> </template>
<el-form-item :label="t('departmentId')" prop="department_id"> </el-table-column>
<el-input
v-model="salaryTable.searchParam.department_id" <el-table-column :label="t('paymentMethod')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('departmentIdPlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in payment_methodList">
</el-form-item> <div v-if="item.value == row.payment_method">{{ item.name }}</div>
<el-form-item :label="t('processId')" prop="process_id"> </div>
<el-input </template>
v-model="salaryTable.searchParam.process_id" </el-table-column>
:placeholder="t('processIdPlaceholder')"
/> <el-table-column prop="salary_month" :label="t('salaryMonth')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item>
<el-button type="primary" @click="loadSalaryList()">{{ <el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column :label="t('operation')" fixed="right" min-width="120">
<el-button @click="resetForm(searchFormRef)">{{ <template #default="{ row }">
t('reset') <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
}}</el-button> <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</el-form-item> </template>
</el-form> </el-table-column>
</el-card>
</el-table>
<div class="mt-[10px]"> <div class="mt-[16px] flex justify-end">
<el-table <el-pagination v-model:current-page="salaryTable.page" v-model:page-size="salaryTable.limit"
:data="salaryTable.data" layout="total, sizes, prev, pager, next, jumper" :total="salaryTable.total"
size="large" @size-change="loadSalaryList()" @current-change="loadSalaryList" />
v-loading="salaryTable.loading" </div>
> </div>
<template #empty>
<span>{{ !salaryTable.loading ? t('emptyData') : '' }}</span> <edit ref="editSalaryDialog" @complete="loadSalaryList" />
</template> </el-card>
<el-table-column </div>
prop="staff_id" </template>
:label="t('staffId')"
min-width="120" <script lang="ts" setup>
:show-overflow-tooltip="true" import { reactive, ref, watch } from 'vue'
/> import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
<el-table-column import { getSalaryList, deleteSalary, getWithPersonnelList, getWithDepartmentsList } from '@/app/api/salary'
prop="base_salary" import { img } from '@/utils/common'
:label="t('baseSalary')" import { ElMessageBox,FormInstance } from 'element-plus'
min-width="120" import Edit from '@/app/views/salary/components/salary-edit.vue'
:show-overflow-tooltip="true" import { useRoute } from 'vue-router'
/> const route = useRoute()
const pageName = route.meta.title;
<el-table-column
prop="performance_bonus" let salaryTable = reactive({
:label="t('performanceBonus')" page: 1,
min-width="120" limit: 10,
:show-overflow-tooltip="true" total: 0,
/> loading: true,
data: [],
<el-table-column searchParam:{
prop="deductions" "staff_id":"",
:label="t('deductions')" "department_id":"",
min-width="120" "payment_status":"",
:show-overflow-tooltip="true" "created_at":[]
/> }
})
<el-table-column
prop="other_subsidies" const searchFormRef = ref<FormInstance>()
:label="t('otherSubsidies')"
min-width="120" //
:show-overflow-tooltip="true" const selectData = ref<any[]>([])
/>
//
<el-table-column const payment_statusList = ref([] as any[])
prop="net_salary" const payment_statusDictList = async () => {
:label="t('netSalary')" payment_statusList.value = await (await useDictionary('payment_status')).data.dictionary
min-width="120" }
:show-overflow-tooltip="true" payment_statusDictList();
/> const payment_methodList = ref([] as any[])
const payment_methodDictList = async () => {
<el-table-column payment_methodList.value = await (await useDictionary('payment_method')).data.dictionary
prop="payment_status" }
:label="t('paymentStatus')" payment_methodDictList();
min-width="120"
:show-overflow-tooltip="true" /**
/> * 获取工资列表
*/
<el-table-column const loadSalaryList = (page: number = 1) => {
prop="payment_method" salaryTable.loading = true
:label="t('paymentMethod')" salaryTable.page = page
min-width="120"
:show-overflow-tooltip="true" getSalaryList({
/> page: salaryTable.page,
limit: salaryTable.limit,
<el-table-column ...salaryTable.searchParam
prop="remarks" }).then(res => {
:label="t('remarks')" salaryTable.loading = false
min-width="120" salaryTable.data = res.data.data
:show-overflow-tooltip="true" salaryTable.total = res.data.total
/> }).catch(() => {
salaryTable.loading = false
<el-table-column })
prop="salary_month" }
:label="t('salaryMonth')" loadSalaryList()
min-width="120"
:show-overflow-tooltip="true" const editSalaryDialog: Record<string, any> | null = ref(null)
/>
/**
<el-table-column * 添加工资
prop="department_id" */
:label="t('departmentId')" const addEvent = () => {
min-width="120" editSalaryDialog.value.setFormData()
:show-overflow-tooltip="true" editSalaryDialog.value.showDialog = true
/> }
<el-table-column /**
prop="process_id" * 编辑工资
:label="t('processId')" * @param data
min-width="120" */
:show-overflow-tooltip="true" const editEvent = (data: any) => {
/> editSalaryDialog.value.setFormData(data)
editSalaryDialog.value.showDialog = true
<el-table-column }
:label="t('operation')"
fixed="right" /**
min-width="120" * 删除工资
> */
<template #default="{ row }"> const deleteEvent = (id: number) => {
<el-button type="primary" link @click="editEvent(row)">{{ ElMessageBox.confirm(t('salaryDeleteTips'), t('warning'),
t('edit') {
}}</el-button> confirmButtonText: t('confirm'),
<el-button type="primary" link @click="deleteEvent(row.id)">{{ cancelButtonText: t('cancel'),
t('delete') type: 'warning',
}}</el-button> }
</template> ).then(() => {
</el-table-column> deleteSalary(id).then(() => {
</el-table> loadSalaryList()
<div class="mt-[16px] flex justify-end"> }).catch(() => {
<el-pagination })
v-model:current-page="salaryTable.page" })
v-model:page-size="salaryTable.limit" }
layout="total, sizes, prev, pager, next, jumper"
:total="salaryTable.total"
@size-change="loadSalaryList()" const staffIdList = ref([])
@current-change="loadSalaryList" const setStaffIdList = async () => {
/> staffIdList.value = await (await getWithPersonnelList({})).data
</div> }
</div> setStaffIdList()
const departmentIdList = ref([])
<edit ref="editSalaryDialog" @complete="loadSalaryList" /> const setDepartmentIdList = async () => {
</el-card> departmentIdList.value = await (await getWithDepartmentsList({})).data
</div> }
</template> setDepartmentIdList()
<script lang="ts" setup> const resetForm = (formEl: FormInstance | undefined) => {
import { reactive, ref, watch } from 'vue' if (!formEl) return
import { t } from '@/lang' formEl.resetFields()
import { useDictionary } from '@/app/api/dict' loadSalaryList()
import { getSalaryList, deleteSalary } from '@/app/api/salary' }
import { img } from '@/utils/common' </script>
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/salary/components/salary-edit.vue' <style lang="scss" scoped>
import { useRoute } from 'vue-router' /* 多行超出隐藏 */
const route = useRoute() .multi-hidden {
const pageName = route.meta.title word-break: break-all;
text-overflow: ellipsis;
let salaryTable = reactive({ overflow: hidden;
page: 1, display: -webkit-box;
limit: 10, -webkit-line-clamp: 2;
total: 0, -webkit-box-orient: vertical;
loading: true, }
data: [], </style>
searchParam: {
staff_id: '',
base_salary: '',
performance_bonus: '',
deductions: '',
other_subsidies: '',
net_salary: '',
payment_status: '',
payment_method: '',
remarks: '',
salary_month: '',
department_id: '',
process_id: '',
},
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取工资列表
*/
const loadSalaryList = (page: number = 1) => {
salaryTable.loading = true
salaryTable.page = page
getSalaryList({
page: salaryTable.page,
limit: salaryTable.limit,
...salaryTable.searchParam,
})
.then((res) => {
salaryTable.loading = false
salaryTable.data = res.data.data
salaryTable.total = res.data.total
})
.catch(() => {
salaryTable.loading = false
})
}
loadSalaryList()
const editSalaryDialog: Record<string, any> | null = ref(null)
/**
* 添加工资
*/
const addEvent = () => {
editSalaryDialog.value.setFormData()
editSalaryDialog.value.showDialog = true
}
/**
* 编辑工资
* @param data
*/
const editEvent = (data: any) => {
editSalaryDialog.value.setFormData(data)
editSalaryDialog.value.showDialog = true
}
/**
* 删除工资
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('salaryDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteSalary(id)
.then(() => {
loadSalaryList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadSalaryList()
}
</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>

599
admin/src/app/views/service/components/service-edit.vue

@ -1,311 +1,288 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateService') : t('addService')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateService') : t('addService')" <el-form-item :label="t('serviceName')" prop="service_name">
width="50%" <el-input v-model="formData.service_name" clearable :placeholder="t('serviceNamePlaceholder')" class="input-width" />
class="diy-dialog-wrap" </el-form-item>
:destroy-on-close="true"
> <el-form-item :label="t('previewImageUrl')">
<el-form <upload-image v-model="formData.preview_image_url" />
:model="formData" </el-form-item>
label-width="120px"
ref="formRef" <el-form-item :label="t('description')" prop="description">
:rules="formRules" <el-input v-model="formData.description" clearable :placeholder="t('descriptionPlaceholder')" class="input-width" />
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('serviceType')" prop="service_type">
<el-form-item :label="t('serviceName')" prop="service_name"> <el-input v-model="formData.service_type" clearable :placeholder="t('serviceTypePlaceholder')" class="input-width" />
<el-input </el-form-item>
v-model="formData.service_name"
clearable <el-form-item :label="t('executionRules')" prop="execution_rules">
:placeholder="t('serviceNamePlaceholder')" <el-input v-model="formData.execution_rules" clearable :placeholder="t('executionRulesPlaceholder')" class="input-width" />
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('staffReminder')" prop="staff_reminder">
<el-select class="input-width" v-model="formData.staff_reminder" clearable :placeholder="t('staffReminderPlaceholder')">
<el-form-item :label="t('previewImageUrl')"> <el-option label="请选择" value=""></el-option>
<el-input <el-option
v-model="formData.preview_image_url" v-for="(item, index) in staff_reminderList"
clearable :key="index"
:placeholder="t('previewImageUrlPlaceholder')" :label="item.name"
class="input-width" :value="item.value"
/> />
</el-form-item> </el-select>
</el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input <el-form-item :label="t('customerReminder')" prop="customer_reminder">
v-model="formData.description" <el-select class="input-width" v-model="formData.customer_reminder" clearable :placeholder="t('customerReminderPlaceholder')">
clearable <el-option label="请选择" value=""></el-option>
:placeholder="t('descriptionPlaceholder')" <el-option
class="input-width" v-for="(item, index) in customer_reminderList"
/> :key="index"
</el-form-item> :label="item.name"
:value="item.value"
<el-form-item :label="t('serviceType')" prop="service_type"> />
<el-input </el-select>
v-model="formData.service_type" </el-form-item>
clearable
:placeholder="t('serviceTypePlaceholder')" <el-form-item :label="t('customerConfirmation')" prop="customer_confirmation">
class="input-width" <el-select class="input-width" v-model="formData.customer_confirmation" clearable :placeholder="t('customerConfirmationPlaceholder')">
/> <el-option label="请选择" value=""></el-option>
</el-form-item> <el-option
v-for="(item, index) in customer_confirmationList"
<el-form-item :label="t('executionRules')" prop="execution_rules"> :key="index"
<el-input :label="item.name"
v-model="formData.execution_rules" :value="item.value"
clearable />
:placeholder="t('executionRulesPlaceholder')" </el-select>
class="input-width" </el-form-item>
/>
</el-form-item> <el-form-item :label="t('customerFeedback')" >
<el-input v-model="formData.customer_feedback" clearable :placeholder="t('customerFeedbackPlaceholder')" class="input-width" />
<el-form-item :label="t('staffReminder')" prop="staff_reminder"> </el-form-item>
<el-input
v-model="formData.staff_reminder" <el-form-item :label="t('status')" prop="status">
clearable <el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('staffReminderPlaceholder')" <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
/> v-for="(item, index) in statusList"
</el-form-item> :key="index"
:label="item.name"
<el-form-item :label="t('customerReminder')" prop="customer_reminder"> :value="item.value"
<el-input />
v-model="formData.customer_reminder" </el-select>
clearable </el-form-item>
:placeholder="t('customerReminderPlaceholder')"
class="input-width" </el-form>
/>
</el-form-item> <template #footer>
<span class="dialog-footer">
<el-form-item <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
:label="t('customerConfirmation')" <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
prop="customer_confirmation" t('confirm')
> }}</el-button>
<el-input </span>
v-model="formData.customer_confirmation" </template>
clearable </el-dialog>
:placeholder="t('customerConfirmationPlaceholder')" </template>
class="input-width"
/> <script lang="ts" setup>
</el-form-item> import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
<el-form-item :label="t('customerFeedback')"> import { t } from '@/lang'
<el-input import type { FormInstance } from 'element-plus'
v-model="formData.customer_feedback" import { addService, editService, getServiceInfo } from '@/app/api/service'
clearable
:placeholder="t('customerFeedbackPlaceholder')" let showDialog = ref(false)
class="input-width" const loading = ref(false)
/>
</el-form-item> /**
* 表单数据
<el-form-item :label="t('status')" prop="status"> */
<el-input const initialFormData = {
v-model="formData.status" id: '',
clearable service_name: '',
:placeholder="t('statusPlaceholder')" preview_image_url: '',
class="input-width" description: '',
/> service_type: '',
</el-form-item> execution_rules: '',
</el-form> staff_reminder: '',
customer_reminder: '',
<template #footer> customer_confirmation: '',
<span class="dialog-footer"> customer_feedback: '',
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> status: '',
<el-button }
type="primary" const formData: Record<string, any> = reactive({ ...initialFormData })
:loading="loading"
@click="confirm(formRef)" const formRef = ref<FormInstance>()
>{{ t('confirm') }}</el-button
> //
</span> const formRules = computed(() => {
</template> return {
</el-dialog> service_name: [
</template> { required: true, message: t('serviceNamePlaceholder'), trigger: 'blur' },
<script lang="ts" setup> ]
import { ref, reactive, computed, watch } from 'vue' ,
import { useDictionary } from '@/app/api/dict' preview_image_url: [
import { t } from '@/lang' { required: true, message: t('previewImageUrlPlaceholder'), trigger: 'blur' },
import type { FormInstance } from 'element-plus'
import { addService, editService, getServiceInfo } from '@/app/api/service' ]
,
let showDialog = ref(false) description: [
const loading = ref(false) { required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
/** ]
* 表单数据 ,
*/ service_type: [
const initialFormData = { { required: true, message: t('serviceTypePlaceholder'), trigger: 'blur' },
id: '',
service_name: '', ]
preview_image_url: '', ,
description: '', execution_rules: [
service_type: '', { required: true, message: t('executionRulesPlaceholder'), trigger: 'blur' },
execution_rules: '',
staff_reminder: '', ]
customer_reminder: '', ,
customer_confirmation: '', staff_reminder: [
customer_feedback: '', { required: true, message: t('staffReminderPlaceholder'), trigger: 'blur' },
status: '',
} ]
const formData: Record<string, any> = reactive({ ...initialFormData }) ,
customer_reminder: [
const formRef = ref<FormInstance>() { required: true, message: t('customerReminderPlaceholder'), trigger: 'blur' },
// ]
const formRules = computed(() => { ,
return { customer_confirmation: [
service_name: [ { required: true, message: t('customerConfirmationPlaceholder'), trigger: 'blur' },
{ required: true, message: t('serviceNamePlaceholder'), trigger: 'blur' },
], ]
preview_image_url: [ ,
{ customer_feedback: [
required: true, { required: true, message: t('customerFeedbackPlaceholder'), trigger: 'blur' },
message: t('previewImageUrlPlaceholder'),
trigger: 'blur', ]
}, ,
], status: [
description: [ { required: true, message: t('statusPlaceholder'), trigger: 'blur' },
{ required: true, message: t('descriptionPlaceholder'), trigger: 'blur' },
], ]
service_type: [ ,
{ required: true, message: t('serviceTypePlaceholder'), trigger: 'blur' }, }
], })
execution_rules: [
{ const emit = defineEmits(['complete'])
required: true,
message: t('executionRulesPlaceholder'), /**
trigger: 'blur', * 确认
}, * @param formEl
], */
staff_reminder: [ const confirm = async (formEl: FormInstance | undefined) => {
{ if (loading.value || !formEl) return
required: true, let save = formData.id ? editService : addService
message: t('staffReminderPlaceholder'),
trigger: 'blur', await formEl.validate(async (valid) => {
}, if (valid) {
], loading.value = true
customer_reminder: [
{ let data = formData
required: true,
message: t('customerReminderPlaceholder'), save(data).then(res => {
trigger: 'blur', loading.value = false
}, showDialog.value = false
], emit('complete')
customer_confirmation: [ }).catch(err => {
{ loading.value = false
required: true, })
message: t('customerConfirmationPlaceholder'), }
trigger: 'blur', })
}, }
],
customer_feedback: [ //
{ let staff_reminderList = ref([])
required: true, const staff_reminderDictList = async () => {
message: t('customerFeedbackPlaceholder'), staff_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
trigger: 'blur', }
}, staff_reminderDictList();
], watch(() => staff_reminderList.value, () => { formData.staff_reminder = staff_reminderList.value[0].value })
status: [ let customer_reminderList = ref([])
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' }, const customer_reminderDictList = async () => {
], customer_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
} }
}) customer_reminderDictList();
watch(() => customer_reminderList.value, () => { formData.customer_reminder = customer_reminderList.value[0].value })
const emit = defineEmits(['complete']) let customer_confirmationList = ref([])
const customer_confirmationDictList = async () => {
/** customer_confirmationList.value = await (await useDictionary('global_true_or_false')).data.dictionary
* 确认 }
* @param formEl customer_confirmationDictList();
*/ watch(() => customer_confirmationList.value, () => { formData.customer_confirmation = customer_confirmationList.value[0].value })
const confirm = async (formEl: FormInstance | undefined) => { let statusList = ref([])
if (loading.value || !formEl) return const statusDictList = async () => {
let save = formData.id ? editService : addService statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
await formEl.validate(async (valid) => { statusDictList();
if (valid) { watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
loading.value = true
let data = formData const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
save(data) loading.value = true
.then((res) => { if(row){
loading.value = false const data = await (await getServiceInfo(row.id)).data
showDialog.value = false if (data) Object.keys(formData).forEach((key: string) => {
emit('complete') if (data[key] != undefined) formData[key] = data[key]
}) })
.catch((err) => { }
loading.value = false 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 {
const setFormData = async (row: any = null) => { callback()
Object.assign(formData, initialFormData) }
loading.value = true }
if (row) {
const data = await (await getServiceInfo(row.id)).data //
if (data) const idCardVerify = (rule: any, value: any, callback: any) => {
Object.keys(formData).forEach((key: string) => { if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
if (data[key] != undefined) formData[key] = data[key] callback(new Error(t('generateIdCard')))
}) } else {
} callback()
loading.value = false }
} }
// //
const mobileVerify = (rule: any, value: any, callback: any) => { const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateMobile'))) callback(new Error(t('generateEmail')))
} else { } else {
callback() callback()
} }
} }
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const numberVerify = (rule: any, value: any, callback: any) => {
if ( if (!Number.isInteger(value)) {
value && callback(new Error(t('generateNumber')))
!/^[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( } else {
value callback()
) }
) { }
callback(new Error(t('generateIdCard')))
} else { defineExpose({
callback() showDialog,
} setFormData
} })
</script>
//
const emailVerify = (rule: any, value: any, callback: any) => { <style lang="scss" scoped></style>
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) { <style lang="scss">
callback(new Error(t('generateEmail'))) .diy-dialog-wrap .el-form-item__label{
} else { height: auto !important;
callback() }
} </style>
}
//
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>

531
admin/src/app/views/service/service.vue

@ -1,321 +1,210 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addService') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addService') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="serviceTable.searchParam" ref="searchFormRef">
> <el-form-item :label="t('serviceName')" prop="service_name">
<el-form <el-input v-model="serviceTable.searchParam.service_name" :placeholder="t('serviceNamePlaceholder')" />
:inline="true" </el-form-item>
:model="serviceTable.searchParam" <el-form-item :label="t('serviceType')" prop="service_type">
ref="searchFormRef" <el-input v-model="serviceTable.searchParam.service_type" :placeholder="t('serviceTypePlaceholder')" />
> </el-form-item>
<el-form-item :label="t('serviceName')" prop="service_name">
<el-input <el-form-item :label="t('status')" prop="status">
v-model="serviceTable.searchParam.service_name" <el-select class="w-[280px]" v-model="serviceTable.searchParam.status" clearable :placeholder="t('statusPlaceholder')">
:placeholder="t('serviceNamePlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in statusList"
<el-form-item :label="t('previewImageUrl')" prop="preview_image_url"> :key="index"
<el-input :label="item.name"
v-model="serviceTable.searchParam.preview_image_url" :value="item.value"
:placeholder="t('previewImageUrlPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('description')" prop="description">
<el-input <el-form-item>
v-model="serviceTable.searchParam.description" <el-button type="primary" @click="loadServiceList()">{{ t('search') }}</el-button>
:placeholder="t('descriptionPlaceholder')" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
/> </el-form-item>
</el-form-item> </el-form>
<el-form-item :label="t('serviceType')" prop="service_type"> </el-card>
<el-input
v-model="serviceTable.searchParam.service_type" <div class="mt-[10px]">
:placeholder="t('serviceTypePlaceholder')" <el-table :data="serviceTable.data" size="large" v-loading="serviceTable.loading">
/> <template #empty>
</el-form-item> <span>{{ !serviceTable.loading ? t('emptyData') : '' }}</span>
<el-form-item :label="t('executionRules')" prop="execution_rules"> </template>
<el-input <el-table-column prop="service_name" :label="t('serviceName')" min-width="120" :show-overflow-tooltip="true"/>
v-model="serviceTable.searchParam.execution_rules"
:placeholder="t('executionRulesPlaceholder')" <el-table-column prop="description" :label="t('description')" min-width="120" :show-overflow-tooltip="true"/>
/>
</el-form-item> <el-table-column prop="service_type" :label="t('serviceType')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item :label="t('staffReminder')" prop="staff_reminder">
<el-input <el-table-column prop="customer_feedback" :label="t('customerFeedback')" min-width="120" :show-overflow-tooltip="true"/>
v-model="serviceTable.searchParam.staff_reminder"
:placeholder="t('staffReminderPlaceholder')" <el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
/> <template #default="{ row }">
</el-form-item> <div v-for="(item, index) in statusList">
<el-form-item :label="t('customerReminder')" prop="customer_reminder"> <div v-if="item.value == row.status">{{ item.name }}</div>
<el-input </div>
v-model="serviceTable.searchParam.customer_reminder" </template>
:placeholder="t('customerReminderPlaceholder')" </el-table-column>
/>
</el-form-item> <el-table-column :label="t('operation')" fixed="right" min-width="120">
<el-form-item <template #default="{ row }">
:label="t('customerConfirmation')" <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
prop="customer_confirmation" <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
> </template>
<el-input </el-table-column>
v-model="serviceTable.searchParam.customer_confirmation"
:placeholder="t('customerConfirmationPlaceholder')" </el-table>
/> <div class="mt-[16px] flex justify-end">
</el-form-item> <el-pagination v-model:current-page="serviceTable.page" v-model:page-size="serviceTable.limit"
<el-form-item :label="t('customerFeedback')" prop="customer_feedback"> layout="total, sizes, prev, pager, next, jumper" :total="serviceTable.total"
<el-input @size-change="loadServiceList()" @current-change="loadServiceList" />
v-model="serviceTable.searchParam.customer_feedback" </div>
:placeholder="t('customerFeedbackPlaceholder')" </div>
/>
</el-form-item> <edit ref="editServiceDialog" @complete="loadServiceList" />
<el-form-item :label="t('status')" prop="status"> </el-card>
<el-input </div>
v-model="serviceTable.searchParam.status" </template>
:placeholder="t('statusPlaceholder')"
/> <script lang="ts" setup>
</el-form-item> import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
<el-form-item> import { useDictionary } from '@/app/api/dict'
<el-button type="primary" @click="loadServiceList()">{{ import { getServiceList, deleteService } from '@/app/api/service'
t('search') import { img } from '@/utils/common'
}}</el-button> import { ElMessageBox,FormInstance } from 'element-plus'
<el-button @click="resetForm(searchFormRef)">{{ import Edit from '@/app/views/service/components/service-edit.vue'
t('reset') import { useRoute } from 'vue-router'
}}</el-button> const route = useRoute()
</el-form-item> const pageName = route.meta.title;
</el-form>
</el-card> let serviceTable = reactive({
page: 1,
<div class="mt-[10px]"> limit: 10,
<el-table total: 0,
:data="serviceTable.data" loading: true,
size="large" data: [],
v-loading="serviceTable.loading" searchParam:{
> "service_name":"",
<template #empty> "service_type":"",
<span>{{ !serviceTable.loading ? t('emptyData') : '' }}</span> "status":""
</template> }
<el-table-column })
prop="service_name"
:label="t('serviceName')" const searchFormRef = ref<FormInstance>()
min-width="120"
:show-overflow-tooltip="true" //
/> const selectData = ref<any[]>([])
<el-table-column //
prop="preview_image_url" const staff_reminderList = ref([] as any[])
:label="t('previewImageUrl')" const staff_reminderDictList = async () => {
min-width="120" staff_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
:show-overflow-tooltip="true" }
/> staff_reminderDictList();
const customer_reminderList = ref([] as any[])
<el-table-column const customer_reminderDictList = async () => {
prop="description" customer_reminderList.value = await (await useDictionary('global_true_or_false')).data.dictionary
:label="t('description')" }
min-width="120" customer_reminderDictList();
:show-overflow-tooltip="true" const customer_confirmationList = ref([] as any[])
/> const customer_confirmationDictList = async () => {
customer_confirmationList.value = await (await useDictionary('global_true_or_false')).data.dictionary
<el-table-column }
prop="service_type" customer_confirmationDictList();
:label="t('serviceType')" const statusList = ref([] as any[])
min-width="120" const statusDictList = async () => {
:show-overflow-tooltip="true" statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
/> }
statusDictList();
<el-table-column
prop="execution_rules" /**
:label="t('executionRules')" * 获取服务列表
min-width="120" */
:show-overflow-tooltip="true" const loadServiceList = (page: number = 1) => {
/> serviceTable.loading = true
serviceTable.page = page
<el-table-column
prop="staff_reminder" getServiceList({
:label="t('staffReminder')" page: serviceTable.page,
min-width="120" limit: serviceTable.limit,
:show-overflow-tooltip="true" ...serviceTable.searchParam
/> }).then(res => {
serviceTable.loading = false
<el-table-column serviceTable.data = res.data.data
prop="customer_reminder" serviceTable.total = res.data.total
:label="t('customerReminder')" }).catch(() => {
min-width="120" serviceTable.loading = false
:show-overflow-tooltip="true" })
/> }
loadServiceList()
<el-table-column
prop="customer_confirmation" const editServiceDialog: Record<string, any> | null = ref(null)
:label="t('customerConfirmation')"
min-width="120" /**
:show-overflow-tooltip="true" * 添加服务
/> */
const addEvent = () => {
<el-table-column editServiceDialog.value.setFormData()
prop="customer_feedback" editServiceDialog.value.showDialog = true
:label="t('customerFeedback')" }
min-width="120"
:show-overflow-tooltip="true" /**
/> * 编辑服务
* @param data
<el-table-column */
prop="status" const editEvent = (data: any) => {
:label="t('status')" editServiceDialog.value.setFormData(data)
min-width="120" editServiceDialog.value.showDialog = true
:show-overflow-tooltip="true" }
/>
/**
<el-table-column * 删除服务
:label="t('operation')" */
fixed="right" const deleteEvent = (id: number) => {
min-width="120" ElMessageBox.confirm(t('serviceDeleteTips'), t('warning'),
> {
<template #default="{ row }"> confirmButtonText: t('confirm'),
<el-button type="primary" link @click="editEvent(row)">{{ cancelButtonText: t('cancel'),
t('edit') type: 'warning',
}}</el-button> }
<el-button type="primary" link @click="deleteEvent(row.id)">{{ ).then(() => {
t('delete') deleteService(id).then(() => {
}}</el-button> loadServiceList()
</template> }).catch(() => {
</el-table-column> })
</el-table> })
<div class="mt-[16px] flex justify-end"> }
<el-pagination
v-model:current-page="serviceTable.page"
v-model:page-size="serviceTable.limit"
layout="total, sizes, prev, pager, next, jumper" const resetForm = (formEl: FormInstance | undefined) => {
:total="serviceTable.total" if (!formEl) return
@size-change="loadServiceList()" formEl.resetFields()
@current-change="loadServiceList" loadServiceList()
/> }
</div> </script>
</div>
<style lang="scss" scoped>
<edit ref="editServiceDialog" @complete="loadServiceList" /> /* 多行超出隐藏 */
</el-card> .multi-hidden {
</div> word-break: break-all;
</template> text-overflow: ellipsis;
overflow: hidden;
<script lang="ts" setup> display: -webkit-box;
import { reactive, ref, watch } from 'vue' -webkit-line-clamp: 2;
import { t } from '@/lang' -webkit-box-orient: vertical;
import { useDictionary } from '@/app/api/dict' }
import { getServiceList, deleteService } from '@/app/api/service' </style>
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/service/components/service-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
let serviceTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
service_name: '',
preview_image_url: '',
description: '',
service_type: '',
execution_rules: '',
staff_reminder: '',
customer_reminder: '',
customer_confirmation: '',
customer_feedback: '',
status: '',
},
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取服务列表
*/
const loadServiceList = (page: number = 1) => {
serviceTable.loading = true
serviceTable.page = page
getServiceList({
page: serviceTable.page,
limit: serviceTable.limit,
...serviceTable.searchParam,
})
.then((res) => {
serviceTable.loading = false
serviceTable.data = res.data.data
serviceTable.total = res.data.total
})
.catch(() => {
serviceTable.loading = false
})
}
loadServiceList()
const editServiceDialog: Record<string, any> | null = ref(null)
/**
* 添加服务
*/
const addEvent = () => {
editServiceDialog.value.setFormData()
editServiceDialog.value.showDialog = true
}
/**
* 编辑服务
* @param data
*/
const editEvent = (data: any) => {
editServiceDialog.value.setFormData(data)
editServiceDialog.value.showDialog = true
}
/**
* 删除服务
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('serviceDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteService(id)
.then(() => {
loadServiceList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadServiceList()
}
</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>

9
admin/src/app/views/setting/components/pay-wechatpay.vue

@ -257,6 +257,8 @@ const confirm = async (formEl: FormInstance | undefined) => {
const cancel = () => { const cancel = () => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (initData.value) { if (initData.value) {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (initData.value[key] != undefined) formData[key] = initData.value[key] if (initData.value[key] != undefined) formData[key] = initData.value[key]
@ -271,13 +273,18 @@ const setFormData = async (data: any = null) => {
initData.value = cloneDeep(data) initData.value = cloneDeep(data)
loading.value = true loading.value = true
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
if (data) { if (data) {
Object.keys(formData).forEach((key: string) => { Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key] if (data[key] != undefined) formData[key] = data[key]
}) })
formData.channel = data.redio_key.split('_')[0] formData.channel = data.radio_key.split('_')[0]
formData.status = Number(formData.status) formData.status = Number(formData.status)
} }
initData.value = formData;
loading.value = false loading.value = false
} }

356
admin/src/app/views/setting/pay.vue

@ -1,116 +1,68 @@
<template> <template>
<!--支付设置--> <!--支付设置-->
<div class="main-container" v-loading="payLoading"> <div class="main-container" v-loading="payLoading">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center" v-if="!payLoading">
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" @click="isEdit = true" ref="setConfigBtn">{{
t('setConfig')
}}</el-button>
</div>
</el-card>
<el-card
class="box-card mt-[15px] !border-none"
shadow="never"
v-for="(payItems, payKey) in payConfigData"
:key="payKey"
>
<h3 class="panel-title !text-sm">{{ payItems.name }}</h3>
<div>
<div
class="flex items-center justify-between p-[10px] table-item-border bg"
>
<span class="text-base w-[230px]">{{ t('payType') }}</span>
<span class="text-base w-[110px] text-center">{{
t('onState')
}}</span>
<span class="text-base w-[80px] text-center" v-if="isEdit">{{
t('templateName')
}}</span>
</div>
<div ref="fieldBoxRefs" :data-key="payKey"> <el-card class="box-card !border-none" shadow="never">
<div <div class="flex justify-between items-center" v-if="!payLoading">
class="flex items-center justify-between p-[10px] table-item-border" <span class="text-page-title">{{ pageName }}</span>
v-for="(childrenItem, childrenIndex) in payItems.pay_type" <el-button type="primary" @click="isEdit = true" ref="setConfigBtn">{{ t('setConfig') }}</el-button>
:key="childrenItem.redio_key"
:id="payKey + '_' + childrenIndex"
>
<div class="flex w-[230px] flex-shrink-0">
<span
v-if="isEdit"
class="iconfont icontuodong mr-2 handle cursor-pointer"
></span>
<div class="flex items-center select-none">
<div class="mr-[15px] w-[30px] h-[30px] flex-shrink-0">
<img class="w-[30px]" :src="img(childrenItem.icon)" />
</div>
<span class="text-base text-[#666]">{{
childrenItem.name
}}</span>
</div>
</div>
<div class="flex items-center justify-center w-[110px] select-none">
<el-switch
v-if="isEdit"
v-model="childrenItem.status"
:active-value="1"
:inactive-value="0"
:active-text="t('isEnable')"
@change="enablePaymentMode(childrenItem)"
/>
<div v-else>
<el-tag
v-if="childrenItem.status"
class="ml-2"
type="success"
>{{ t('open') }}</el-tag
>
<el-tag v-else class="ml-2" type="info">{{
t('notOpen')
}}</el-tag>
</div>
</div> </div>
<div </el-card>
class="flex items-center justify-center w-[80px] select-none"
v-if="isEdit" <el-card class="box-card mt-[15px] !border-none" shadow="never" v-for="(item, key) in payConfigData" :key="key">
> <view v-for="(payItems, payKey) in item" :key="payKey">
<button <h3 class="panel-title !text-sm">{{ payItems.campus_name }}</h3>
class="text-base"
@click="configPayFn(childrenItem)" <div>
v-if="childrenItem.setting_component" <div class="flex items-center justify-between p-[10px] table-item-border bg">
> <span class="text-base w-[230px]">{{ t('payType') }}</span>
{{ t('clickConfigure') }} <span class="text-base w-[110px] text-center">{{ t('onState') }}</span>
</button> <span class="text-base w-[80px] text-center" v-if="isEdit">{{ t('templateName') }}</span>
<button v-else>--</button> </div>
<div ref="fieldBoxRefs" :data-key="payKey">
<div class="flex items-center justify-between p-[10px] table-item-border" v-for="(childrenItem, childrenIndex) in payItems.pay_type" :key="childrenItem.redio_key" :id="payKey + '_' + childrenIndex">
<div class="flex w-[230px] flex-shrink-0">
<span v-if="isEdit" class="iconfont icontuodong mr-2 handle cursor-pointer"></span>
<div class="flex items-center select-none">
<div class="mr-[15px] w-[30px] h-[30px] flex-shrink-0">
<img class="w-[30px]" :src="img(childrenItem.icon)" />
</div>
<span class="text-base text-[#666]">{{ childrenItem.name }}</span>
</div>
</div>
<div class="flex items-center justify-center w-[110px] select-none">
<el-switch v-if="isEdit" v-model="childrenItem.status" :active-value="1" :inactive-value="0" :active-text="t('isEnable')" @change="enablePaymentMode(childrenItem)" />
<div v-else>
<el-tag v-if="childrenItem.status" class="ml-2" type="success">{{ t('open') }}</el-tag>
<el-tag v-else class="ml-2" type="info">{{ t('notOpen') }}</el-tag>
</div>
</div>
<div class="flex items-center justify-center w-[80px] select-none" v-if="isEdit">
<button class="text-base" @click="configPayFn(childrenItem)" v-if="childrenItem.setting_component">{{ t('clickConfigure') }}</button>
<button v-else>--</button>
</div>
</div>
</div>
</div>
</view>
</el-card>
<div class="fixed-footer-wrap" v-if="isEdit">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="cancelFn">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="saveFn(formRef)">{{ t('save') }}</el-button>
</div> </div>
</div>
</div> </div>
</div>
</el-card>
<div class="fixed-footer-wrap" v-if="isEdit">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="cancelFn">{{
t('cancel')
}}</el-button>
<el-button type="primary" :loading="loading" @click="saveFn(formRef)">{{
t('save')
}}</el-button>
</div>
</div>
<template v-for="(item, index) in payTypeList"> <template v-for="(item, index) in payConfigData">
<component <component :is="is" :ref="(el) => setPayTypeRefs(el, 'wechatpay')" @complete="setConfigInfo"/>
:is="item.setting_component" </template>
:ref="(el) => setPayTypeRefs(el, item.key)"
v-if="item.setting_component" </div>
@complete="setConfigInfo"
/>
</template>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -127,22 +79,21 @@ import { cloneDeep } from 'lodash-es'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
const payTypeList = ref([]) const payTypeList = ref([])
const payTypeRefs = ref({}) const payTypeRefs = ref({})
const modules: any = import.meta.glob('@/**/*.vue') const modules: any = import.meta.glob('@/**/*.vue')
const is = defineAsyncComponent(modules["/src/app/views/setting/components/pay-wechatpay.vue"]);
getAllPayType().then(({ data }) => { getAllPayType().then(({ data }) => {
Object.keys(data).forEach((key: string) => { Object.keys(data).forEach((key: string) => {
data[key].setting_component && data[key].setting_component && (data[key].setting_component = defineAsyncComponent(modules[data[key].setting_component]))
(data[key].setting_component = defineAsyncComponent( })
modules[data[key].setting_component] payTypeList.value = data
))
})
payTypeList.value = data
}) })
const setPayTypeRefs = (el: any, index: string) => { const setPayTypeRefs = (el: any, index: string) => {
payTypeRefs.value[index] = el payTypeRefs.value[index] = (el)
} }
const payLoading = ref(true) const payLoading = ref(true)
@ -153,127 +104,134 @@ const setConfigBtn = ref()
// //
const payConfigData = ref([]) const payConfigData = ref([])
const checkPayConfigList = () => { const checkPayConfigList = () => {
getPayConfigList().then((res) => { getPayConfigList().then(res => {
const payData = res.data const list = res.data;
for (const i in payData) { const data = [];
const payType = payData[i].pay_type
const pay_type = [] for (const z in list) {
let default_key = '' const payDataGroup = list[z];
for (const i in payDataGroup) {
payType.forEach((item, index) => { const payItem = payDataGroup[i];
item.redio_key = payData[i].key + '_' + item.key const payTypeList = payItem.pay_type || [];
item.defauit_key = '' const processedPayTypes = [];
if (item.is_default == 1) { let defaultKey = '';
default_key = item.redio_key
} payTypeList.forEach((item) => {
pay_type.push(item) item.radio_key = `${payItem.key}_${item.key}`;
}) if (item.is_default === 1) {
defaultKey = item.radio_key;
payData[payData[i].key].default_pay_type = default_key }
payData[payData[i].key].pay_type = pay_type processedPayTypes.push(item);
} });
payConfigData.value = payData
payLoading.value = false
nextTick(() => { list[z][payDataGroup[i].key].default_pay_type = defaultKey
fieldBoxRefs.value.forEach((item, index) => { list[z][payDataGroup[i].key].pay_type = processedPayTypes
sortableFn(item, index) }
})
}
console.log(list);
payConfigData.value = list
payLoading.value = false
nextTick(() => {
fieldBoxRefs.value.forEach((item, index) => {
sortableFn(item, index)
})
})
}) })
})
} }
checkPayConfigList() checkPayConfigList()
// //
const setConfigInfo = (data: any) => { const setConfigInfo = (data:any) => {
payConfigData.value[data.channel].pay_type.forEach((element) => { payConfigData.value[data.channel].pay_type.forEach(element => {
if (element.key == data.type) { if (element.key == data.type) {
element.config = data.config element.config = data.config
} }
}) })
console.log(payConfigData.value) console.log(payConfigData.value)
} }
// //
const configPayFn = (data: any) => { const configPayFn = (data:any) => {
payTypeRefs.value[data.key].setFormData(data) payTypeRefs.value[data.key].setFormData(data)
payTypeRefs.value[data.key].showDialog = true payTypeRefs.value[data.key].showDialog = true
} }
// //
const enablePaymentMode = async (data: any) => { const enablePaymentMode = async (data: any) => {
if ( if (payTypeRefs.value[data.key] && typeof payTypeRefs.value[data.key].enableVerify == 'function') {
payTypeRefs.value[data.key] && payTypeRefs.value[data.key].setFormData(data)
typeof payTypeRefs.value[data.key].enableVerify == 'function'
) { const verify = payTypeRefs.value[data.key].enableVerify()
payTypeRefs.value[data.key].setFormData(data) if (!verify) {
data.status = 0
const verify = payTypeRefs.value[data.key].enableVerify() ElMessage(t('configurePaymentMethod'))
if (!verify) { return false
data.status = 0 }
ElMessage(t('configurePaymentMethod'))
return false
} }
}
} }
interface SortableEvt extends SortableEvent { interface SortableEvt extends SortableEvent {
originalEvent?: DragEvent originalEvent?: DragEvent
} }
// //
const fieldBoxRefs = ref<any>([]) const fieldBoxRefs = ref<any>([])
watch(isEdit, (newValue, oldValue) => { watch(isEdit, (newValue, oldValue) => {
if (newValue) { if (newValue) {
nextTick(() => { nextTick(() => {
fieldBoxRefs.value.forEach((item: any, index: any) => { fieldBoxRefs.value.forEach((item:any, index:any) => {
sortableFn(item, index) sortableFn(item, index)
}) })
}) })
} }
}) })
// item=>index // item=>index
const sortableFn = (item, index) => { const sortableFn = (item, index) => {
const sortable = Sortable.create(item, { const sortable = Sortable.create(item, {
group: { group: {
put: false, // put: false //
}, },
handle: '.handle', handle: '.handle',
animation: 200, animation: 200,
disabled: false, disabled: false,
onEnd: (evt) => { onEnd: (evt) => {
const key = evt.target.getAttribute('data-key') const key = evt.target.getAttribute('data-key')
const data = payConfigData.value[key].pay_type const data = payConfigData.value[key].pay_type
data.splice(evt.newIndex, 0, ...data.splice(evt.oldIndex, 1)) data.splice(evt.newIndex, 0, ...data.splice(evt.oldIndex, 1))
}, }
}) })
} }
// //
const saveFn = () => { const saveFn = () => {
payLoading.value = true payLoading.value = true
const data = cloneDeep(payConfigData.value) const data = cloneDeep(payConfigData.value)
Object.values(data).forEach((item, index) => { Object.values(data).forEach((item, index) => {
item.pay_type.forEach((subItem: any, subIndex: any) => { item.pay_type.forEach((subItem:any, subIndex:any) => {
subItem.sort = subIndex subItem.sort = subIndex
})
}) })
})
setPatConfig({ config: data }).then((res) => { setPatConfig({ config: data }).then(res => {
checkPayConfigList() checkPayConfigList()
isEdit.value = false isEdit.value = false
payLoading.value = false payLoading.value = false
}) })
} }
// //
const cancelFn = () => { const cancelFn = () => {
location.reload() location.reload()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.table-item-border { .table-item-border {
@apply border-b border-[var(--el-border-color)]; @apply border-b border-[var(--el-border-color)];
} }
</style> </style>

380
admin/src/app/views/user_feedback/components/user-feedback-edit.vue

@ -1,205 +1,175 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateUserFeedback') : t('addUserFeedback')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateUserFeedback') : t('addUserFeedback')" <el-form-item :label="t('userId')" >
width="50%" <el-select class="input-width" v-model="formData.user_id" clearable :placeholder="t('userIdPlaceholder')" disabled>
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in userIdList"
<el-form :key="index"
:model="formData" :label="item['name']"
label-width="120px" :value="item['id']"
ref="formRef" />
:rules="formRules" </el-select>
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('feedbackText')" >
<el-form-item :label="t('userId')" prop="user_id"> <el-input disabled v-model="formData.feedback_text" type="textarea" rows="4" clearable :placeholder="t('feedbackTextPlaceholder')" class="input-width"/>
<el-input </el-form-item>
v-model="formData.user_id" <el-form-item :label="t('attachmentUrl')" >
clearable <upload-file v-model="formData.attachment_url" disabled/>
:placeholder="t('userIdPlaceholder')" </el-form-item>
class="input-width"
/> </el-form>
</el-form-item>
<template #footer>
<el-form-item :label="t('feedbackText')" prop="feedback_text"> <span class="dialog-footer">
<el-input <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
v-model="formData.feedback_text" <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
clearable t('confirm')
:placeholder="t('feedbackTextPlaceholder')" }}</el-button>
class="input-width" </span>
/> </template>
</el-form-item> </el-dialog>
</template>
<el-form-item :label="t('attachmentUrl')">
<el-input <script lang="ts" setup>
v-model="formData.attachment_url" import { ref, reactive, computed, watch } from 'vue'
clearable import { useDictionary } from '@/app/api/dict'
:placeholder="t('attachmentUrlPlaceholder')" import { t } from '@/lang'
class="input-width" import type { FormInstance } from 'element-plus'
/> import { addUserFeedback, editUserFeedback, getUserFeedbackInfo, getWithCustomerResourcesList } from '@/app/api/user_feedback'
</el-form-item>
</el-form> let showDialog = ref(false)
const loading = ref(false)
<template #footer>
<span class="dialog-footer"> /**
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> * 表单数据
<el-button */
type="primary" const initialFormData = {
:loading="loading" id: '',
@click="confirm(formRef)" user_id: '',
>{{ t('confirm') }}</el-button feedback_text: '',
> attachment_url: '',
</span> }
</template> const formData: Record<string, any> = reactive({ ...initialFormData })
</el-dialog>
</template> const formRef = ref<FormInstance>()
<script lang="ts" setup> //
import { ref, reactive, computed, watch } from 'vue' const formRules = computed(() => {
import { useDictionary } from '@/app/api/dict' return {
import { t } from '@/lang' user_id: [
import type { FormInstance } from 'element-plus' { required: true, message: t('userIdPlaceholder'), trigger: 'blur' },
import {
addUserFeedback, ]
editUserFeedback, ,
getUserFeedbackInfo, feedback_text: [
} from '@/app/api/user_feedback' { required: true, message: t('feedbackTextPlaceholder'), trigger: 'blur' },
let showDialog = ref(false) ]
const loading = ref(false) ,
attachment_url: [
/** { required: true, message: t('attachmentUrlPlaceholder'), trigger: 'blur' },
* 表单数据
*/ ]
const initialFormData = { ,
id: '', }
user_id: '', })
feedback_text: '',
attachment_url: '', const emit = defineEmits(['complete'])
}
const formData: Record<string, any> = reactive({ ...initialFormData }) /**
* 确认
const formRef = ref<FormInstance>() * @param formEl
*/
// const confirm = async (formEl: FormInstance | undefined) => {
const formRules = computed(() => { if (loading.value || !formEl) return
return { let save = formData.id ? editUserFeedback : addUserFeedback
user_id: [
{ required: true, message: t('userIdPlaceholder'), trigger: 'blur' }, await formEl.validate(async (valid) => {
], if (valid) {
feedback_text: [ loading.value = true
{
required: true, let data = formData
message: t('feedbackTextPlaceholder'),
trigger: 'blur', save(data).then(res => {
}, loading.value = false
], showDialog.value = false
attachment_url: [ emit('complete')
{ }).catch(err => {
required: true, loading.value = false
message: t('attachmentUrlPlaceholder'), })
trigger: 'blur', }
}, })
], }
}
}) //
const emit = defineEmits(['complete'])
/** const userIdList = ref([] as any[])
* 确认 const setUserIdList = async () => {
* @param formEl userIdList.value = await (await getWithCustomerResourcesList({})).data
*/ }
const confirm = async (formEl: FormInstance | undefined) => { setUserIdList()
if (loading.value || !formEl) return const setFormData = async (row: any = null) => {
let save = formData.id ? editUserFeedback : addUserFeedback Object.assign(formData, initialFormData)
loading.value = true
await formEl.validate(async (valid) => { if(row){
if (valid) { const data = await (await getUserFeedbackInfo(row.id)).data
loading.value = true if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
let data = formData })
}
save(data) loading.value = false
.then((res) => { }
loading.value = false
showDialog.value = false //
emit('complete') const mobileVerify = (rule: any, value: any, callback: any) => {
}) if (value && !/^1[3-9]\d{9}$/.test(value)) {
.catch((err) => { callback(new Error(t('generateMobile')))
loading.value = false } else {
}) callback()
} }
}) }
}
//
// const idCardVerify = (rule: any, value: any, callback: any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
const setFormData = async (row: any = null) => { callback(new Error(t('generateIdCard')))
Object.assign(formData, initialFormData) } else {
loading.value = true callback()
if (row) { }
const data = await (await getUserFeedbackInfo(row.id)).data }
if (data)
Object.keys(formData).forEach((key: string) => { //
if (data[key] != undefined) formData[key] = data[key] const emailVerify = (rule: any, value: any, callback: any) => {
}) if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
} callback(new Error(t('generateEmail')))
loading.value = false } else {
} callback()
}
// }
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) { //
callback(new Error(t('generateMobile'))) const numberVerify = (rule: any, value: any, callback: any) => {
} else { if (!Number.isInteger(value)) {
callback() callback(new Error(t('generateNumber')))
} } else {
} callback()
}
// }
const idCardVerify = (rule: any, value: any, callback: any) => {
if ( defineExpose({
value && showDialog,
!/^[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( setFormData
value })
) </script>
) {
callback(new Error(t('generateIdCard'))) <style lang="scss" scoped></style>
} else { <style lang="scss">
callback() .diy-dialog-wrap .el-form-item__label{
} height: auto !important;
} }
</style>
//
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>

400
admin/src/app/views/user_feedback/user_feedback.vue

@ -1,223 +1,177 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addUserFeedback') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addUserFeedback') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="userFeedbackTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('userId')" prop="user_id">
:inline="true" <el-select class="w-[280px]" v-model="userFeedbackTable.searchParam.user_id" clearable :placeholder="t('userIdPlaceholder')">
:model="userFeedbackTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in userIdList"
> :key="index"
<el-form-item :label="t('userId')" prop="user_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="userFeedbackTable.searchParam.user_id" />
:placeholder="t('userIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('feedbackText')" prop="feedback_text"> <el-form-item>
<el-input <el-button type="primary" @click="loadUserFeedbackList()">{{ t('search') }}</el-button>
v-model="userFeedbackTable.searchParam.feedback_text" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('feedbackTextPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('attachmentUrl')" prop="attachment_url">
<el-input <div class="mt-[10px]">
v-model="userFeedbackTable.searchParam.attachment_url" <el-table :data="userFeedbackTable.data" size="large" v-loading="userFeedbackTable.loading">
:placeholder="t('attachmentUrlPlaceholder')" <template #empty>
/> <span>{{ !userFeedbackTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item>
<el-button type="primary" @click="loadUserFeedbackList()">{{ <el-table-column prop="feedback_text" :label="t('feedbackText')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column prop="attachment_url" :label="t('attachmentUrl')" min-width="120" :show-overflow-tooltip="true"/>
<el-button @click="resetForm(searchFormRef)">{{
t('reset') <el-table-column :label="t('operation')" fixed="right" min-width="120">
}}</el-button> <template #default="{ row }">
</el-form-item> <el-button type="primary" link @click="editEvent(row)">查看</el-button>
</el-form> <!-- <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button> -->
</el-card> </template>
</el-table-column>
<div class="mt-[10px]">
<el-table </el-table>
:data="userFeedbackTable.data" <div class="mt-[16px] flex justify-end">
size="large" <el-pagination v-model:current-page="userFeedbackTable.page" v-model:page-size="userFeedbackTable.limit"
v-loading="userFeedbackTable.loading" layout="total, sizes, prev, pager, next, jumper" :total="userFeedbackTable.total"
> @size-change="loadUserFeedbackList()" @current-change="loadUserFeedbackList" />
<template #empty> </div>
<span>{{ !userFeedbackTable.loading ? t('emptyData') : '' }}</span> </div>
</template>
<el-table-column <edit ref="editUserFeedbackDialog" @complete="loadUserFeedbackList" />
prop="user_id" </el-card>
:label="t('userId')" </div>
min-width="120" </template>
:show-overflow-tooltip="true"
/> <script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
<el-table-column import { t } from '@/lang'
prop="feedback_text" import { useDictionary } from '@/app/api/dict'
:label="t('feedbackText')" import { getUserFeedbackList, deleteUserFeedback, getWithCustomerResourcesList } from '@/app/api/user_feedback'
min-width="120" import { img } from '@/utils/common'
:show-overflow-tooltip="true" import { ElMessageBox,FormInstance } from 'element-plus'
/> import Edit from '@/app/views/user_feedback/components/user-feedback-edit.vue'
import { useRoute } from 'vue-router'
<el-table-column const route = useRoute()
prop="attachment_url" const pageName = route.meta.title;
:label="t('attachmentUrl')"
min-width="120" let userFeedbackTable = reactive({
:show-overflow-tooltip="true" page: 1,
/> limit: 10,
total: 0,
<el-table-column loading: true,
:label="t('operation')" data: [],
fixed="right" searchParam:{
min-width="120" "user_id":""
> }
<template #default="{ row }"> })
<el-button type="primary" link @click="editEvent(row)">{{
t('edit') const searchFormRef = ref<FormInstance>()
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ //
t('delete') const selectData = ref<any[]>([])
}}</el-button>
</template> //
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end"> /**
<el-pagination * 获取用户反馈信息列表
v-model:current-page="userFeedbackTable.page" */
v-model:page-size="userFeedbackTable.limit" const loadUserFeedbackList = (page: number = 1) => {
layout="total, sizes, prev, pager, next, jumper" userFeedbackTable.loading = true
:total="userFeedbackTable.total" userFeedbackTable.page = page
@size-change="loadUserFeedbackList()"
@current-change="loadUserFeedbackList" getUserFeedbackList({
/> page: userFeedbackTable.page,
</div> limit: userFeedbackTable.limit,
</div> ...userFeedbackTable.searchParam
}).then(res => {
<edit ref="editUserFeedbackDialog" @complete="loadUserFeedbackList" /> userFeedbackTable.loading = false
</el-card> userFeedbackTable.data = res.data.data
</div> userFeedbackTable.total = res.data.total
</template> }).catch(() => {
userFeedbackTable.loading = false
<script lang="ts" setup> })
import { reactive, ref, watch } from 'vue' }
import { t } from '@/lang' loadUserFeedbackList()
import { useDictionary } from '@/app/api/dict'
import { const editUserFeedbackDialog: Record<string, any> | null = ref(null)
getUserFeedbackList,
deleteUserFeedback, /**
} from '@/app/api/user_feedback' * 添加用户反馈信息
import { img } from '@/utils/common' */
import { ElMessageBox, FormInstance } from 'element-plus' const addEvent = () => {
import Edit from '@/app/views/user_feedback/components/user-feedback-edit.vue' editUserFeedbackDialog.value.setFormData()
import { useRoute } from 'vue-router' editUserFeedbackDialog.value.showDialog = true
const route = useRoute() }
const pageName = route.meta.title
/**
let userFeedbackTable = reactive({ * 编辑用户反馈信息
page: 1, * @param data
limit: 10, */
total: 0, const editEvent = (data: any) => {
loading: true, editUserFeedbackDialog.value.setFormData(data)
data: [], editUserFeedbackDialog.value.showDialog = true
searchParam: { }
user_id: '',
feedback_text: '', /**
attachment_url: '', * 删除用户反馈信息
}, */
}) const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('userFeedbackDeleteTips'), t('warning'),
const searchFormRef = ref<FormInstance>() {
confirmButtonText: t('confirm'),
// cancelButtonText: t('cancel'),
const selectData = ref<any[]>([]) type: 'warning',
}
// ).then(() => {
deleteUserFeedback(id).then(() => {
/** loadUserFeedbackList()
* 获取用户反馈信息列表 }).catch(() => {
*/ })
const loadUserFeedbackList = (page: number = 1) => { })
userFeedbackTable.loading = true }
userFeedbackTable.page = page
getUserFeedbackList({ const userIdList = ref([])
page: userFeedbackTable.page, const setUserIdList = async () => {
limit: userFeedbackTable.limit, userIdList.value = await (await getWithCustomerResourcesList({})).data
...userFeedbackTable.searchParam, }
}) setUserIdList()
.then((res) => {
userFeedbackTable.loading = false const resetForm = (formEl: FormInstance | undefined) => {
userFeedbackTable.data = res.data.data if (!formEl) return
userFeedbackTable.total = res.data.total formEl.resetFields()
}) loadUserFeedbackList()
.catch(() => { }
userFeedbackTable.loading = false </script>
})
} <style lang="scss" scoped>
loadUserFeedbackList() /* 多行超出隐藏 */
.multi-hidden {
const editUserFeedbackDialog: Record<string, any> | null = ref(null) word-break: break-all;
text-overflow: ellipsis;
/** overflow: hidden;
* 添加用户反馈信息 display: -webkit-box;
*/ -webkit-line-clamp: 2;
const addEvent = () => { -webkit-box-orient: vertical;
editUserFeedbackDialog.value.setFormData() }
editUserFeedbackDialog.value.showDialog = true </style>
}
/**
* 编辑用户反馈信息
* @param data
*/
const editEvent = (data: any) => {
editUserFeedbackDialog.value.setFormData(data)
editUserFeedbackDialog.value.showDialog = true
}
/**
* 删除用户反馈信息
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('userFeedbackDeleteTips'), t('warning'), {
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteUserFeedback(id)
.then(() => {
loadUserFeedbackList()
})
.catch(() => {})
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadUserFeedbackList()
}
</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>

102
niucloud/app/adminapi/controller/campus_pay/CampusPay.php

@ -0,0 +1,102 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\adminapi\controller\campus_pay;
use core\base\BaseAdminController;
use app\service\admin\campus_pay\CampusPayService;
/**
* 账户及资金管理控制器
* Class CampusPay
* @package app\adminapi\controller\campus_pay
*/
class CampusPay extends BaseAdminController
{
/**
* 获取账户及资金管理列表
* @return \think\Response
*/
public function lists(){
$data = $this->request->params([
["campus_id",""],
["created_at",["",""]]
]);
return success((new CampusPayService())->getPage($data));
}
/**
* 账户及资金管理详情
* @param int $id
* @return \think\Response
*/
public function info(int $id){
return success((new CampusPayService())->getInfo($id));
}
/**
* 添加账户及资金管理
* @return \think\Response
*/
public function add(){
$data = $this->request->params([
["campus_id",0],
["mchid",""],
["pay_sign_key",""],
["apiclient_key",""],
["apiclient_cert",""],
["wx_pay_key",""],
["wx_pay_key_id",""],
]);
$this->validate($data, 'app\validate\campus_pay\CampusPay.add');
$id = (new CampusPayService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
}
/**
* 账户及资金管理编辑
* @param $id 账户及资金管理id
* @return \think\Response
*/
public function edit(int $id){
$data = $this->request->params([
["campus_id",0],
["mchid",""],
["pay_sign_key",""],
["apiclient_key",""],
["apiclient_cert",""],
["wx_pay_key",""],
["wx_pay_key_id",""],
]);
$this->validate($data, 'app\validate\campus_pay\CampusPay.edit');
(new CampusPayService())->edit($id, $data);
return success('EDIT_SUCCESS');
}
/**
* 账户及资金管理删除
* @param $id 账户及资金管理id
* @return \think\Response
*/
public function del(int $id){
(new CampusPayService())->del($id);
return success('DELETE_SUCCESS');
}
public function getCampusAll(){
return success(( new CampusPayService())->getCampusAll());
}
}

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

@ -32,6 +32,7 @@ class CustomerResources extends BaseAdminController
["age",""], ["age",""],
["gender",""], ["gender",""],
["phone_number",""], ["phone_number",""],
['member_label', 0],
["type","khzy"], ["type","khzy"],
["created_at",[]], ["created_at",[]],
["updated_at",[]], ["updated_at",[]],
@ -69,6 +70,8 @@ class CustomerResources extends BaseAdminController
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""], ["status",""],
['member_label', []],
["create_year_month",date("Y-m")], ["create_year_month",date("Y-m")],
["create_date",date("Y-m-d")], ["create_date",date("Y-m-d")],
["purchase_power",""], ["purchase_power",""],
@ -110,6 +113,7 @@ class CustomerResources extends BaseAdminController
["initial_intent",""], ["initial_intent",""],
["campus",""], ["campus",""],
["status",""], ["status",""],
['member_label', []],
["create_year_month",date("Y-m")], ["create_year_month",date("Y-m")],
["create_date",date("Y-m-d")], ["create_date",date("Y-m-d")],

8
niucloud/app/adminapi/controller/departments/Departments.php

@ -54,8 +54,7 @@ class Departments extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\departments\Departments.add'); $this->validate($data, 'app\validate\departments\Departments.add');
$id = (new DepartmentsService())->add($data); return (new DepartmentsService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
} }
/** /**
@ -70,8 +69,7 @@ class Departments extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\departments\Departments.edit'); $this->validate($data, 'app\validate\departments\Departments.edit');
(new DepartmentsService())->edit($id, $data); return (new DepartmentsService())->edit($id, $data);
return success('EDIT_SUCCESS');
} }
/** /**
@ -84,7 +82,7 @@ class Departments extends BaseAdminController
return success('DELETE_SUCCESS'); return success('DELETE_SUCCESS');
} }
public function getDepartmentsAll(){ public function getDepartmentsAll(){
return success(( new DepartmentsService())->getDepartmentsAll()); return success(( new DepartmentsService())->getDepartmentsAll());
} }

9
niucloud/app/adminapi/controller/order_table/OrderTable.php

@ -50,7 +50,7 @@ class OrderTable extends BaseAdminController
public function add(){ public function add(){
$data = $this->request->params([ $data = $this->request->params([
["resource_id",0], ["resource_id",0],
["order_status",""], // ["order_status",""],
["payment_type",""], ["payment_type",""],
["order_amount",0.00], ["order_amount",0.00],
["course_id",0], ["course_id",0],
@ -58,8 +58,7 @@ class OrderTable extends BaseAdminController
]); ]);
$this->validate($data, 'app\validate\order_table\OrderTable.add'); $this->validate($data, 'app\validate\order_table\OrderTable.add');
$id = (new OrderTableService())->add($data); return (new OrderTableService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
} }
/** /**
@ -70,7 +69,7 @@ class OrderTable extends BaseAdminController
public function edit(int $id){ public function edit(int $id){
$data = $this->request->params([ $data = $this->request->params([
["resource_id",0], ["resource_id",0],
["order_status",""], // ["order_status",""],
["payment_type",""], ["payment_type",""],
["order_amount",0.00], ["order_amount",0.00],
["course_id",0], ["course_id",0],
@ -92,7 +91,7 @@ class OrderTable extends BaseAdminController
return success('DELETE_SUCCESS'); return success('DELETE_SUCCESS');
} }
public function getCustomerResourcesAll(){ public function getCustomerResourcesAll(){
return success(( new OrderTableService())->getCustomerResourcesAll()); return success(( new OrderTableService())->getCustomerResourcesAll());
} }

12
niucloud/app/adminapi/controller/reimbursement/Reimbursement.php

@ -28,12 +28,8 @@ class Reimbursement extends BaseAdminController
*/ */
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["applicant_id",""],
["amount",""],
["description",""],
["receipt_url",""],
["status",""], ["status",""],
["process_id",""] ["created_at",["",""]]
]); ]);
return success((new ReimbursementService())->getPage($data)); return success((new ReimbursementService())->getPage($data));
} }
@ -58,7 +54,6 @@ class Reimbursement extends BaseAdminController
["description",""], ["description",""],
["receipt_url",""], ["receipt_url",""],
["status",""], ["status",""],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\reimbursement\Reimbursement.add'); $this->validate($data, 'app\validate\reimbursement\Reimbursement.add');
@ -78,7 +73,6 @@ class Reimbursement extends BaseAdminController
["description",""], ["description",""],
["receipt_url",""], ["receipt_url",""],
["status",""], ["status",""],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\reimbursement\Reimbursement.edit'); $this->validate($data, 'app\validate\reimbursement\Reimbursement.edit');
@ -97,4 +91,8 @@ class Reimbursement extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new ReimbursementService())->getPersonnelAll());
}
} }

32
niucloud/app/adminapi/controller/salary/Salary.php

@ -29,17 +29,9 @@ class Salary extends BaseAdminController
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",""], ["staff_id",""],
["base_salary",""],
["performance_bonus",""],
["deductions",""],
["other_subsidies",""],
["net_salary",""],
["payment_status",""],
["payment_method",""],
["remarks",""],
["salary_month",""],
["department_id",""], ["department_id",""],
["process_id",""] ["payment_status",""],
["created_at",["",""]]
]); ]);
return success((new SalaryService())->getPage($data)); return success((new SalaryService())->getPage($data));
} }
@ -60,17 +52,15 @@ class Salary extends BaseAdminController
public function add(){ public function add(){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",0], ["staff_id",0],
["department_id",0],
["base_salary",0.00], ["base_salary",0.00],
["performance_bonus",0.00], ["performance_bonus",0.00],
["deductions",0.00], ["deductions",0.00],
["other_subsidies",0.00], ["other_subsidies",0.00],
["net_salary",0.00],
["payment_status",""], ["payment_status",""],
["payment_method",""], ["payment_method",""],
["remarks",""], ["remarks",""],
["salary_month","2025-05-16 17:53:32"], ["salary_month","2025-05-22 18:20:42"],
["department_id",0],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\salary\Salary.add'); $this->validate($data, 'app\validate\salary\Salary.add');
@ -86,17 +76,15 @@ class Salary extends BaseAdminController
public function edit(int $id){ public function edit(int $id){
$data = $this->request->params([ $data = $this->request->params([
["staff_id",0], ["staff_id",0],
["department_id",0],
["base_salary",0.00], ["base_salary",0.00],
["performance_bonus",0.00], ["performance_bonus",0.00],
["deductions",0.00], ["deductions",0.00],
["other_subsidies",0.00], ["other_subsidies",0.00],
["net_salary",0.00],
["payment_status",""], ["payment_status",""],
["payment_method",""], ["payment_method",""],
["remarks",""], ["remarks",""],
["salary_month","2025-05-16 17:53:32"], ["salary_month","2025-05-22 18:20:42"],
["department_id",0],
["process_id",0],
]); ]);
$this->validate($data, 'app\validate\salary\Salary.edit'); $this->validate($data, 'app\validate\salary\Salary.edit');
@ -115,4 +103,12 @@ class Salary extends BaseAdminController
} }
public function getPersonnelAll(){
return success(( new SalaryService())->getPersonnelAll());
}
public function getDepartmentsAll(){
return success(( new SalaryService())->getDepartmentsAll());
}
} }

7
niucloud/app/adminapi/controller/service/Service.php

@ -29,14 +29,7 @@ class Service extends BaseAdminController
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["service_name",""], ["service_name",""],
["preview_image_url",""],
["description",""],
["service_type",""], ["service_type",""],
["execution_rules",""],
["staff_reminder",""],
["customer_reminder",""],
["customer_confirmation",""],
["customer_feedback",""],
["status",""] ["status",""]
]); ]);
return success((new ServiceService())->getPage($data)); return success((new ServiceService())->getPage($data));

2
niucloud/app/adminapi/controller/sys/Role.php

@ -57,6 +57,7 @@ class Role extends BaseAdminController
$data = $this->request->params([ $data = $this->request->params([
['role_name', ''], ['role_name', ''],
['rules', []], ['rules', []],
['role_key',''],
['status', RoleStatusDict::ON], ['status', RoleStatusDict::ON],
]); ]);
$this->validate($data, 'app\validate\sys\Role.add'); $this->validate($data, 'app\validate\sys\Role.add');
@ -73,6 +74,7 @@ class Role extends BaseAdminController
$data = $this->request->params([ $data = $this->request->params([
['role_name', ''], ['role_name', ''],
['rules', []], ['rules', []],
['role_key',''],
['status', RoleStatusDict::ON], ['status', RoleStatusDict::ON],
]); ]);
$this->validate($data, 'app\validate\sys\Role.edit'); $this->validate($data, 'app\validate\sys\Role.edit');

8
niucloud/app/adminapi/controller/user_feedback/UserFeedback.php

@ -28,9 +28,7 @@ class UserFeedback extends BaseAdminController
*/ */
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["user_id",""], ["user_id",""]
["feedback_text",""],
["attachment_url",""]
]); ]);
return success((new UserFeedbackService())->getPage($data)); return success((new UserFeedbackService())->getPage($data));
} }
@ -88,4 +86,8 @@ class UserFeedback extends BaseAdminController
} }
public function getCustomerResourcesAll(){
return success(( new UserFeedbackService())->getCustomerResourcesAll());
}
} }

42
niucloud/app/adminapi/route/campus_pay.php

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

6
niucloud/app/adminapi/route/reimbursement.php

@ -14,6 +14,10 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- reimbursement // USER_CODE_BEGIN -- reimbursement
Route::group('reimbursement', function () { Route::group('reimbursement', function () {
@ -29,6 +33,8 @@ Route::group('reimbursement', function () {
//删除报销记录 //删除报销记录
Route::delete('reimbursement/:id', 'reimbursement.Reimbursement/del'); Route::delete('reimbursement/:id', 'reimbursement.Reimbursement/del');
Route::get('personnel_all','reimbursement.Reimbursement/getPersonnelAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

8
niucloud/app/adminapi/route/salary.php

@ -14,6 +14,10 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- salary // USER_CODE_BEGIN -- salary
Route::group('salary', function () { Route::group('salary', function () {
@ -29,6 +33,10 @@ Route::group('salary', function () {
//删除工资 //删除工资
Route::delete('salary/:id', 'salary.Salary/del'); Route::delete('salary/:id', 'salary.Salary/del');
Route::get('personnel_all','salary.Salary/getPersonnelAll');
Route::get('departments_all','salary.Salary/getDepartmentsAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

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

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

3
niucloud/app/adminapi/route/user_feedback.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- user_feedback // USER_CODE_BEGIN -- user_feedback
Route::group('user_feedback', function () { Route::group('user_feedback', function () {
@ -29,6 +30,8 @@ Route::group('user_feedback', function () {
//删除用户反馈信息 //删除用户反馈信息
Route::delete('user_feedback/:id', 'user_feedback.UserFeedback/del'); Route::delete('user_feedback/:id', 'user_feedback.UserFeedback/del');
Route::get('customer_resources_all','user_feedback.UserFeedback/getCustomerResourcesAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

28
niucloud/app/api/controller/apiController/CustomerResources.php

@ -152,5 +152,33 @@ class CustomerResources extends BaseApiService
return success([]); return success([]);
} }
//客户资源-修改记录列表
public function getEditLogList(Request $request){
//前端要传递分页(page,limit)参数
$customer_resource_id = $request->param('customer_resource_id','');
$type = $request->param('type','resource');//查询类型|resource=客户资源,six_speed=六要素
if(empty($customer_resource_id) || empty($type)){
return fail('缺少必要参数');
}
if(!in_array($type,['resource','six_speed'])){
return fail('类型不正确');
}
$where = [
'customer_resource_id' =>$customer_resource_id
];
if($type == 'resource'){
//resource=客户资源
$res =(new CustomerResourcesService())->getCustomerResourceChangesEditLog($where);
}else{
$res =(new CustomerResourcesService())->getSixSpeedModificationEditLog($where);
}
return success($res);
}
} }

3
niucloud/app/api/route/route.php

@ -208,6 +208,9 @@ Route::group(function () {
Route::post('customerResources/add', 'apiController.CustomerResources/add'); Route::post('customerResources/add', 'apiController.CustomerResources/add');
//客户资源-编辑 //客户资源-编辑
Route::post('customerResources/edit', 'apiController.CustomerResources/edit'); Route::post('customerResources/edit', 'apiController.CustomerResources/edit');
//客户资源-修改记录列表
Route::get('customerResources/getEditLogList', 'apiController.CustomerResources/getEditLogList');
//资源共享-列表 //资源共享-列表
Route::get('resourceSharing/index', 'apiController.ResourceSharing/index'); Route::get('resourceSharing/index', 'apiController.ResourceSharing/index');

8
niucloud/app/dict/common/ChannelDict.php

@ -33,10 +33,10 @@ class ChannelDict
public static function getType($type = '') public static function getType($type = '')
{ {
$data = [ $data = [
self::PC => get_lang('dict_channel.channel_pc'),//'电脑PC' // self::PC => get_lang('dict_channel.channel_pc'),//'电脑PC'
self::H5 => get_lang('dict_channel.channel_h5'),//'手机H5' // self::H5 => get_lang('dict_channel.channel_h5'),//'手机H5'
self::APP => get_lang('dict_channel.channel_app'),//'手机app' // self::APP => get_lang('dict_channel.channel_app'),//'手机app'
self::WECHAT => get_lang('dict_channel.channel_wechat'),//'微信公众号' // self::WECHAT => get_lang('dict_channel.channel_wechat'),//'微信公众号'
self::WEAPP => get_lang('dict_channel.channel_weapp'),//微信小程序 self::WEAPP => get_lang('dict_channel.channel_weapp'),//微信小程序
]; ];
if (empty($type)) { if (empty($type)) {

48
niucloud/app/dict/pay/PayDict.php

@ -64,30 +64,30 @@ class PayDict
'setting_component' => '/src/app/views/setting/components/pay-wechatpay.vue', 'setting_component' => '/src/app/views/setting/components/pay-wechatpay.vue',
'encrypt_params' => [ 'mch_public_cert_path', 'mch_secret_cert', 'mch_secret_key', 'wechat_public_cert_path' ], 'encrypt_params' => [ 'mch_public_cert_path', 'mch_secret_cert', 'mch_secret_key', 'wechat_public_cert_path' ],
], ],
// 支付宝支付 // // 支付宝支付
self::ALIPAY => [ // self::ALIPAY => [
'name' => get_lang('dict_pay.type_alipay'), // 'name' => get_lang('dict_pay.type_alipay'),
'key' => self::ALIPAY, // 'key' => self::ALIPAY,
'icon' => self::ALIPAY_ICON, // 'icon' => self::ALIPAY_ICON,
'setting_component' => '/src/app/views/setting/components/pay-alipay.vue', // 'setting_component' => '/src/app/views/setting/components/pay-alipay.vue',
'encrypt_params' => [ 'app_secret_cert', 'app_public_cert_path', 'alipay_public_cert_path', 'alipay_root_cert_path' ], // 'encrypt_params' => [ 'app_secret_cert', 'app_public_cert_path', 'alipay_public_cert_path', 'alipay_root_cert_path' ],
], // ],
// 余额支付 // // 余额支付
self::BALANCEPAY => [ // self::BALANCEPAY => [
'name' => get_lang('dict_pay.type_balancepay'), // 'name' => get_lang('dict_pay.type_balancepay'),
'key' => self::BALANCEPAY, // 'key' => self::BALANCEPAY,
'icon' => self::BALANCEPAY_ICON, // 'icon' => self::BALANCEPAY_ICON,
'setting_component' => '', // 'setting_component' => '',
'encrypt_params' => [ 'secret_key' ], // 'encrypt_params' => [ 'secret_key' ],
], // ],
// 找朋友帮忙付 // // 找朋友帮忙付
self::FRIENDSPAY => [ // self::FRIENDSPAY => [
'name' => get_lang('dict_pay.type_friendspay'), // 'name' => get_lang('dict_pay.type_friendspay'),
'key' => self::FRIENDSPAY, // 'key' => self::FRIENDSPAY,
'icon' => self::FRIENDSPAY_ICON, // 'icon' => self::FRIENDSPAY_ICON,
'setting_component' => '/src/app/views/setting/components/pay-friendspay.vue', // 'setting_component' => '/src/app/views/setting/components/pay-friendspay.vue',
'encrypt_params' => [], // 'encrypt_params' => [],
], // ],
]; ];
$list = array_merge($list, ...event('PayType')); $list = array_merge($list, ...event('PayType'));

98
niucloud/app/model/campus_pay/CampusPay.php

@ -0,0 +1,98 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\campus_pay;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\campus\Campus;
/**
* 账户及资金管理模型
* Class CampusPay
* @package app\model\campus_pay
*/
class CampusPay extends BaseModel
{
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'campus_pay';
/**
* 搜索器:账户及资金管理
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:账户及资金管理校区
* @param $value
* @param $data
*/
public function searchCampusIdAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_id", $value);
}
}
/**
* 搜索器:账户及资金管理创建时间
* @param $value
* @param $data
*/
public function searchCreatedAtAttr($query, $value, $data)
{
$start = empty($value[0]) ? 0 : strtotime($value[0]);
$end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
}
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
}

40
niucloud/app/model/customer_resources/CustomerResources.php

@ -15,6 +15,7 @@ use app\model\dict\Dict;
use app\model\resource_sharing\ResourceSharing; use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
use core\base\BaseModel; use core\base\BaseModel;
use think\db\Query;
use think\model\concern\SoftDelete; use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
@ -57,6 +58,37 @@ class CustomerResources extends BaseModel
*/ */
protected $defaultSoftDelete = 0; protected $defaultSoftDelete = 0;
protected $json = [ 'member_label' ];
protected $jsonAssoc = true;
//定义一个常量数组-字段中文映射
const FieldZh = [
'id' => '编号',
'create_year_month' => '创建年月',
'create_date' => '创建日期',
'source_channel' => '来源渠道',
'source' => '来源',
'consultant' => '顾问',
'name' => '姓名',
'age' => '年龄',
'gender' => '性别',
'phone_number' => '联系电话',
'demand' => '需求',
'purchasing_power' => '购买力',
'cognitive_idea' => '认知理念',
'optional_class_time' => '可选上课时间',
'distance' => '距离',
'decision_maker' => '决策人',
'initial_intent' => '客户初步意向度',
'campus' => '所属校区',
'trial_class_count' => '体验课次数',
'created_at' => '创建时间',
'updated_at' => '更新时间',
'deleted_at' => '逻辑删除时间',
'status' => '客户状态',
];
/** /**
* 搜索器:客户资源姓名 * 搜索器:客户资源姓名
* @param $value * @param $value
@ -69,6 +101,14 @@ class CustomerResources extends BaseModel
} }
} }
public function searchMemberLabelAttr(Query $query, $value, $data)
{
if ($value) {
$query->whereLike('member_label', '%"' . $value . '"%');
}
}
/** /**
* 搜索器:客户资源联系电话 * 搜索器:客户资源联系电话
* @param $value * @param $value

80
niucloud/app/model/reimbursement/Reimbursement.php

@ -16,6 +16,8 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
/** /**
* 报销记录模型 * 报销记录模型
* Class Reimbursement * Class Reimbursement
@ -42,66 +44,6 @@ class Reimbursement extends BaseModel
/**
* 搜索器:报销记录报销编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:报销记录申请人ID
* @param $value
* @param $data
*/
public function searchApplicantIdAttr($query, $value, $data)
{
if ($value) {
$query->where("applicant_id", $value);
}
}
/**
* 搜索器:报销记录报销金额
* @param $value
* @param $data
*/
public function searchAmountAttr($query, $value, $data)
{
if ($value) {
$query->where("amount", $value);
}
}
/**
* 搜索器:报销记录报销描述
* @param $value
* @param $data
*/
public function searchDescriptionAttr($query, $value, $data)
{
if ($value) {
$query->where("description", $value);
}
}
/**
* 搜索器:报销记录发票或收据URL
* @param $value
* @param $data
*/
public function searchReceiptUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("receipt_url", $value);
}
}
/** /**
* 搜索器:报销记录状态 * 搜索器:报销记录状态
* @param $value * @param $value
@ -115,14 +57,20 @@ class Reimbursement extends BaseModel
} }
/** /**
* 搜索器:报销记录关联的审批流程ID * 搜索器:报销记录创建时间
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchProcessIdAttr($query, $value, $data) public function searchCreatedAtAttr($query, $value, $data)
{ {
if ($value) { $start = empty($value[0]) ? 0 : strtotime($value[0]);
$query->where("process_id", $value); $end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
} }
} }
@ -131,4 +79,8 @@ class Reimbursement extends BaseModel
public function personnel(){
return $this->hasOne(Personnel::class, 'id', 'applicant_id')->joinType('left')->withField('name,id')->bind(['applicant_id_name'=>'name']);
}
} }

140
niucloud/app/model/salary/Salary.php

@ -16,6 +16,10 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\personnel\Personnel;
use app\model\departments\Departments;
/** /**
* 工资模型 * 工资模型
* Class Salary * Class Salary
@ -43,19 +47,7 @@ class Salary extends BaseModel
/** /**
* 搜索器:工资工资编号 * 搜索器:工资员工
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:工资员工ID
* @param $value * @param $value
* @param $data * @param $data
*/ */
@ -67,62 +59,14 @@ class Salary extends BaseModel
} }
/** /**
* 搜索器:工资底薪 * 搜索器:工资部门
* @param $value
* @param $data
*/
public function searchBaseSalaryAttr($query, $value, $data)
{
if ($value) {
$query->where("base_salary", $value);
}
}
/**
* 搜索器:工资绩效
* @param $value
* @param $data
*/
public function searchPerformanceBonusAttr($query, $value, $data)
{
if ($value) {
$query->where("performance_bonus", $value);
}
}
/**
* 搜索器:工资扣款
* @param $value
* @param $data
*/
public function searchDeductionsAttr($query, $value, $data)
{
if ($value) {
$query->where("deductions", $value);
}
}
/**
* 搜索器:工资其他补贴
* @param $value
* @param $data
*/
public function searchOtherSubsidiesAttr($query, $value, $data)
{
if ($value) {
$query->where("other_subsidies", $value);
}
}
/**
* 搜索器:工资实发工资
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchNetSalaryAttr($query, $value, $data) public function searchDepartmentIdAttr($query, $value, $data)
{ {
if ($value) { if ($value) {
$query->where("net_salary", $value); $query->where("department_id", $value);
} }
} }
@ -139,68 +83,34 @@ class Salary extends BaseModel
} }
/** /**
* 搜索器:工资发放方式 * 搜索器:工资创建时间
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchPaymentMethodAttr($query, $value, $data) public function searchCreatedAtAttr($query, $value, $data)
{ {
if ($value) { $start = empty($value[0]) ? 0 : strtotime($value[0]);
$query->where("payment_method", $value); $end = empty($value[1]) ? 0 : strtotime($value[1]);
if ($start > 0 && $end > 0) {
$query->where([["created_at", "between", [$start, $end]]]);
} else if ($start > 0 && $end == 0) {
$query->where([["created_at", ">=", $start]]);
} else if ($start == 0 && $end > 0) {
$query->where([["created_at", "<=", $end]]);
} }
} }
/**
* 搜索器:工资备注
* @param $value
* @param $data
*/
public function searchRemarksAttr($query, $value, $data)
{
if ($value) {
$query->where("remarks", $value);
}
}
/**
* 搜索器:工资工资月份
* @param $value
* @param $data
*/
public function searchSalaryMonthAttr($query, $value, $data)
{
if ($value) {
$query->where("salary_month", $value);
}
}
/**
* 搜索器:工资部门ID
* @param $value
* @param $data
*/
public function searchDepartmentIdAttr($query, $value, $data)
{
if ($value) {
$query->where("department_id", $value);
}
}
/** public function personnel(){
* 搜索器:工资关联的审批流程ID return $this->hasOne(Personnel::class, 'id', 'staff_id')->joinType('left')->withField('name,id')->bind(['staff_id_name'=>'name']);
* @param $value
* @param $data
*/
public function searchProcessIdAttr($query, $value, $data)
{
if ($value) {
$query->where("process_id", $value);
}
} }
public function departments(){
return $this->hasOne(Departments::class, 'id', 'department_id')->joinType('left')->withField('department_name,id')->bind(['department_id_name'=>'department_name']);
}
} }

96
niucloud/app/model/service/Service.php

@ -50,18 +50,6 @@ class Service extends BaseModel
*/ */
protected $defaultSoftDelete = 0; protected $defaultSoftDelete = 0;
/**
* 搜索器:服务服务编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/** /**
* 搜索器:服务服务名称 * 搜索器:服务服务名称
* @param $value * @param $value
@ -74,30 +62,6 @@ class Service extends BaseModel
} }
} }
/**
* 搜索器:服务服务预览图URL
* @param $value
* @param $data
*/
public function searchPreviewImageUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("preview_image_url", $value);
}
}
/**
* 搜索器:服务服务描述
* @param $value
* @param $data
*/
public function searchDescriptionAttr($query, $value, $data)
{
if ($value) {
$query->where("description", $value);
}
}
/** /**
* 搜索器:服务服务类型 * 搜索器:服务服务类型
* @param $value * @param $value
@ -110,66 +74,6 @@ class Service extends BaseModel
} }
} }
/**
* 搜索器:服务服务执行规则
* @param $value
* @param $data
*/
public function searchExecutionRulesAttr($query, $value, $data)
{
if ($value) {
$query->where("execution_rules", $value);
}
}
/**
* 搜索器:服务是否员工提醒: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchStaffReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("staff_reminder", $value);
}
}
/**
* 搜索器:服务是否客户提醒: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchCustomerReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_reminder", $value);
}
}
/**
* 搜索器:服务是否客户确认: 1-是, 0-否
* @param $value
* @param $data
*/
public function searchCustomerConfirmationAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_confirmation", $value);
}
}
/**
* 搜索器:服务客户反馈内容
* @param $value
* @param $data
*/
public function searchCustomerFeedbackAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_feedback", $value);
}
}
/** /**
* 搜索器:服务状态 * 搜索器:服务状态
* @param $value * @param $value

21
niucloud/app/model/six_speed/SixSpeed.php

@ -57,7 +57,26 @@ class SixSpeed extends BaseModel
//定义一个常量数组-字段中文映射
const FieldZh = [
'id' => '编号',
'purchase_power' => '需求购买力',
'concept_awareness' => '认知理念',
'preferred_class_time' => '可选上课时间',
'distance' => '距离',
'communication' => '沟通备注',
'promised_visit_time' => '承诺到访时间',
'actual_visit_time' => '实际到访时间',
'call_intent' => '电话后的意向程度',
'first_visit_status' => '一访情况',
'second_visit_status' => '二访情况',
'is_closed' => '是否关单',
'staff_id' => '人员ID',
'resource_id' => '资源ID',
'created_at' => '创建时间',
'updated_at' => '更新时间',
'deleted_at' => '逻辑删除时间'
];
public function personnel(){ public function personnel(){

44
niucloud/app/model/user_feedback/UserFeedback.php

@ -16,6 +16,8 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\customer_resources\CustomerResources;
/** /**
* 用户反馈信息模型 * 用户反馈信息模型
* Class UserFeedback * Class UserFeedback
@ -43,19 +45,7 @@ class UserFeedback extends BaseModel
/** /**
* 搜索器:用户反馈信息反馈编号 * 搜索器:用户反馈信息客户名称
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:用户反馈信息用户ID
* @param $value * @param $value
* @param $data * @param $data
*/ */
@ -66,33 +56,13 @@ class UserFeedback extends BaseModel
} }
} }
/**
* 搜索器:用户反馈信息反馈内容
* @param $value
* @param $data
*/
public function searchFeedbackTextAttr($query, $value, $data)
{
if ($value) {
$query->where("feedback_text", $value);
}
}
/**
* 搜索器:用户反馈信息附件URL(OSS对象存储)
* @param $value
* @param $data
*/
public function searchAttachmentUrlAttr($query, $value, $data)
{
if ($value) {
$query->where("attachment_url", $value);
}
}
public function customerResources(){
return $this->hasOne(CustomerResources::class, 'id', 'user_id')->joinType('left')->withField('name,id')->bind(['user_id_name'=>'name']);
}
} }

105
niucloud/app/service/admin/campus_pay/CampusPayService.php

@ -0,0 +1,105 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\campus_pay;
use app\model\campus_pay\CampusPay;
use app\model\campus\Campus;
use core\base\BaseAdminService;
/**
* 账户及资金管理服务层
* Class CampusPayService
* @package app\service\admin\campus_pay
*/
class CampusPayService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new CampusPay();
}
/**
* 获取账户及资金管理列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,campus_id,mchid,pay_sign_key,apiclient_key,apiclient_cert,wx_pay_key,wx_pay_key_id,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","campus_id","created_at"], $where)->with(['campus'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取账户及资金管理信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,campus_id,mchid,pay_sign_key,apiclient_key,apiclient_cert,wx_pay_key,wx_pay_key_id,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus'])->findOrEmpty()->toArray();
return $info;
}
/**
* 添加账户及资金管理
* @param array $data
* @return mixed
*/
public function add(array $data)
{
$res = $this->model->create($data);
return $res->id;
}
/**
* 账户及资金管理编辑
* @param int $id
* @param array $data
* @return bool
*/
public function edit(int $id, array $data)
{
$this->model->where([['id', '=', $id]])->update($data);
return true;
}
/**
* 删除账户及资金管理
* @param int $id
* @return bool
*/
public function del(int $id)
{
$model = $this->model->where([['id', '=', $id]])->find();
$res = $model->delete();
return $res;
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
}

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

@ -19,6 +19,7 @@ use app\model\campus\Campus;
use app\model\resource_sharing\ResourceSharing; use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
use app\model\six_speed_modification_log\SixSpeedModificationLog; use app\model\six_speed_modification_log\SixSpeedModificationLog;
use app\service\admin\member\MemberLabelService;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -66,9 +67,9 @@ class CustomerResourcesService extends BaseAdminService
$where[] = ['b.shared_by','=',0]; $where[] = ['b.shared_by','=',0];
} }
if($data['member_label']){
$where[] = ['a.member_label','like',"%".$data['member_label']."%"];
}
$search_model = $this->model $search_model = $this->model
@ -87,11 +88,9 @@ class CustomerResourcesService extends BaseAdminService
} }
$list = $this->pageQuery($search_model); return $this->pageQuery($search_model, function ($item, $key) {
$item = $this->makeUp($item);
});
return $list;
} }
/** /**
@ -101,7 +100,7 @@ class CustomerResourcesService extends BaseAdminService
*/ */
public function getInfo(int $id) public function getInfo(int $id)
{ {
$field = 'id,create_year_month,create_date,source,source_channel,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status'; $field = 'id,create_year_month,create_date,source,source_channel,member_label,consultant,name,age,gender,phone_number,demand,purchasing_power,cognitive_idea,optional_class_time,distance,decision_maker,initial_intent,campus,created_at,updated_at,deleted_at,status';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray();
@ -109,7 +108,16 @@ class CustomerResourcesService extends BaseAdminService
$data = $sixSpeed->where(['resource_id' => $id])->field("*,distance as distance_tow")->findOrEmpty()->toArray(); $data = $sixSpeed->where(['resource_id' => $id])->field("*,distance as distance_tow")->findOrEmpty()->toArray();
$info = $info+$data; $info = $info+$data;
return $info; return $this->makeUp($info);
}
public function makeUp($data){
//会员标签
if(!empty($data['member_label'])){
$data['member_label_array'] = (new MemberLabelService())->getMemberLabelListByLabelIds($data['member_label']);
}
return $data;
} }
/** /**
@ -128,6 +136,8 @@ class CustomerResourcesService extends BaseAdminService
} }
$sixSpeed = new SixSpeed(); $sixSpeed = new SixSpeed();
// $data['member_label'] = json_encode($data['member_label']);
$res = $this->model->create($data); $res = $this->model->create($data);
@ -188,7 +198,7 @@ class CustomerResourcesService extends BaseAdminService
$this->model->where([['id', '=', $id]])->update([ $this->model->where([['id', '=', $id]])->update([
'source' => $data['source'], 'source' => $data['source'],
'source_channel' => $data['source_channel'], 'source_channel' => $data['source_channel'],
// 'consultant' => $data['consultant'], 'member_label' => $data['member_label'],
'name' => $data['name'], 'name' => $data['name'],
'age' => $data['age'], 'age' => $data['age'],
'gender' => $data['gender'], 'gender' => $data['gender'],

13
niucloud/app/service/admin/departments/DepartmentsService.php

@ -65,8 +65,12 @@ class DepartmentsService extends BaseAdminService
*/ */
public function add(array $data) public function add(array $data)
{ {
if($this->model->where(['department_name' => $data['department_name']])->find()){
return fail("部门名称不能重复");
}
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id; return success("操作成功");
} }
@ -74,13 +78,14 @@ class DepartmentsService extends BaseAdminService
* 部门编辑 * 部门编辑
* @param int $id * @param int $id
* @param array $data * @param array $data
* @return bool
*/ */
public function edit(int $id, array $data) public function edit(int $id, array $data)
{ {
if($this->model->where([['id', '<>', $id]])->where(['department_name' => $data['department_name']])->find()){
return fail("部门名称不能重复");
}
$this->model->where([['id', '=', $id]])->update($data); $this->model->where([['id', '=', $id]])->update($data);
return true; return success("操作成功");
} }
/** /**

12
niucloud/app/service/admin/order_table/OrderTableService.php

@ -69,15 +69,15 @@ class OrderTableService extends BaseAdminService
public function add(array $data) public function add(array $data)
{ {
$personnel = new Personnel(); $personnel = new Personnel();
$data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id"); // $data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['staff_id']){ // if(!$data['staff_id']){
return fail("操作失败"); // return fail("操作失败");
} // }
// $data['staff_id'] = 1; $data['staff_id'] = 1;
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id; return success("操作成功");
} }

55
niucloud/app/service/admin/pay/PayChannelService.php

@ -15,6 +15,7 @@ use app\dict\common\ChannelDict;
use app\dict\common\CommonDict; use app\dict\common\CommonDict;
use app\dict\pay\PayChannelDict; use app\dict\pay\PayChannelDict;
use app\dict\pay\PayDict; use app\dict\pay\PayDict;
use app\model\campus\Campus;
use app\model\pay\PayChannel; use app\model\pay\PayChannel;
use app\service\core\pay\CorePayChannelService; use app\service\core\pay\CorePayChannelService;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -84,6 +85,7 @@ class PayChannelService extends BaseAdminService
*/ */
public function getChannelList() public function getChannelList()
{ {
$channel_list = PayChannelDict::getPayChannel(); $channel_list = PayChannelDict::getPayChannel();
$where = array ( $where = array (
['id', '>', 0] ['id', '>', 0]
@ -97,32 +99,41 @@ class PayChannelService extends BaseAdminService
$pay_type_list = PayDict::getPayType(); $pay_type_list = PayDict::getPayType();
foreach ($channel_list as $k => $v) { $campus = new Campus();
$temp_item = $pay_channel_list[ $k ] ?? []; $campus_list = $campus->select();
foreach ($v[ 'pay_type' ] as $item_k => $item_v) { $list = [];
if (isset($temp_item[ $item_k ])) { foreach ($campus_list as $key=>$val){
$temp_v_item = $temp_item[ $item_k ]; foreach ($channel_list as $k => $v) {
$encrypt_params = $pay_type_list[$item_k]['encrypt_params'] ?? []; $temp_item = $pay_channel_list[ $k ] ?? [];
foreach ($temp_v_item['config'] as $config_k => $config_v) { foreach ($v[ 'pay_type' ] as $item_k => $item_v) {
if ($config_v !== '' && in_array($config_k, $encrypt_params)) $temp_v_item['config'][$config_k] = CommonDict::ENCRYPT_STR; if (isset($temp_item[ $item_k ])) {
$temp_v_item = $temp_item[ $item_k ];
$encrypt_params = $pay_type_list[$item_k]['encrypt_params'] ?? [];
foreach ($temp_v_item['config'] as $config_k => $config_v) {
if ($config_v !== '' && in_array($config_k, $encrypt_params)) $temp_v_item['config'][$config_k] = CommonDict::ENCRYPT_STR;
}
} else {
$temp_v_item = [ 'status' => 0, 'config' => $this->getConfigByPayType([], $item_k), 'sort' => 0 ];
} }
} else { $item_v[ 'config' ] = $temp_v_item[ 'config' ];
$temp_v_item = [ 'status' => 0, 'config' => $this->getConfigByPayType([], $item_k), 'sort' => 0 ]; $item_v[ 'status' ] = $temp_v_item[ 'status' ];
} $item_v[ 'sort' ] = $temp_v_item[ 'sort' ];
$item_v[ 'config' ] = $temp_v_item[ 'config' ]; if ($item_k == PayDict::FRIENDSPAY) {
$item_v[ 'status' ] = $temp_v_item[ 'status' ]; $item_v[ 'name' ] = $temp_v_item[ 'config' ][ 'pay_type_name' ] ?? get_lang('dict_pay.type_friendspay');
$item_v[ 'sort' ] = $temp_v_item[ 'sort' ]; }
if ($item_k == PayDict::FRIENDSPAY) { $channel_list[ $k ][ 'pay_type' ][ $item_k ] = $item_v;
$item_v[ 'name' ] = $temp_v_item[ 'config' ][ 'pay_type_name' ] ?? get_lang('dict_pay.type_friendspay');
} }
$channel_list[ $k ][ 'pay_type' ][ $item_k ] = $item_v; $temp_pay_type = array_values($channel_list[ $k ][ 'pay_type' ]);
$sort = array_column($temp_pay_type, 'sort');
array_multisort($sort, SORT_ASC, $temp_pay_type);
$channel_list[ $k ][ 'pay_type' ] = $temp_pay_type;
$channel_list[$k]['campus_name'] = $val['campus_name'];
} }
$temp_pay_type = array_values($channel_list[ $k ][ 'pay_type' ]); $list[$key] = $channel_list;
$sort = array_column($temp_pay_type, 'sort');
array_multisort($sort, SORT_ASC, $temp_pay_type);
$channel_list[ $k ][ 'pay_type' ] = $temp_pay_type;
} }
return $channel_list;
return $list;
} }
/** /**

10
niucloud/app/service/admin/reimbursement/ReimbursementService.php

@ -12,6 +12,7 @@
namespace app\service\admin\reimbursement; namespace app\service\admin\reimbursement;
use app\model\reimbursement\Reimbursement; use app\model\reimbursement\Reimbursement;
use app\model\personnel\Personnel;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -39,7 +40,7 @@ class ReimbursementService extends BaseAdminService
$field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at'; $field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","applicant_id","amount","description","receipt_url","status","process_id"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["status","created_at"], $where)->with(['personnel'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +54,7 @@ class ReimbursementService extends BaseAdminService
{ {
$field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at'; $field = 'id,applicant_id,amount,description,receipt_url,status,process_id,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +96,10 @@ class ReimbursementService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
} }

20
niucloud/app/service/admin/salary/SalaryService.php

@ -12,6 +12,8 @@
namespace app\service\admin\salary; namespace app\service\admin\salary;
use app\model\salary\Salary; use app\model\salary\Salary;
use app\model\personnel\Personnel;
use app\model\departments\Departments;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -36,10 +38,10 @@ class SalaryService extends BaseAdminService
*/ */
public function getPage(array $where = []) public function getPage(array $where = [])
{ {
$field = 'id,staff_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,department_id,process_id,created_at,updated_at'; $field = 'id,staff_id,department_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,process_id,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","staff_id","base_salary","performance_bonus","deductions","other_subsidies","net_salary","payment_status","payment_method","remarks","salary_month","department_id","process_id"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["staff_id","department_id","payment_status","created_at"], $where)->with(['personnel','departments'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -51,9 +53,9 @@ class SalaryService extends BaseAdminService
*/ */
public function getInfo(int $id) public function getInfo(int $id)
{ {
$field = 'id,staff_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,department_id,process_id,created_at,updated_at'; $field = 'id,staff_id,department_id,base_salary,performance_bonus,deductions,other_subsidies,net_salary,payment_status,payment_method,remarks,salary_month,process_id,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['personnel','departments'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +97,15 @@ class SalaryService extends BaseAdminService
} }
public function getPersonnelAll(){
$personnelModel = new Personnel();
return $personnelModel->select()->toArray();
}
public function getDepartmentsAll(){
$departmentsModel = new Departments();
return $departmentsModel->select()->toArray();
}
} }

2
niucloud/app/service/admin/service/ServiceService.php

@ -39,7 +39,7 @@ class ServiceService extends BaseAdminService
$field = 'id,service_name,preview_image_url,description,service_type,execution_rules,staff_reminder,customer_reminder,customer_confirmation,customer_feedback,status,created_at,updated_at,deleted_at'; $field = 'id,service_name,preview_image_url,description,service_type,execution_rules,staff_reminder,customer_reminder,customer_confirmation,customer_feedback,status,created_at,updated_at,deleted_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","service_name","preview_image_url","description","service_type","execution_rules","staff_reminder","customer_reminder","customer_confirmation","customer_feedback","status"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["service_name","service_type","status"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }

4
niucloud/app/service/admin/sys/RoleService.php

@ -46,7 +46,7 @@ class RoleService extends BaseAdminService
if(isset($data['role_name']) && $data['role_name'] !== '') { if(isset($data['role_name']) && $data['role_name'] !== '') {
$where[] = ['role_name', 'like', "%".$this->model->handelSpecialCharacter($data['role_name'])."%"]; $where[] = ['role_name', 'like', "%".$this->model->handelSpecialCharacter($data['role_name'])."%"];
} }
$field = 'role_id,role_name,status,create_time'; $field = 'role_id,role_name,role_key,status,create_time';
$search_model = $this->model->where($where)->field($field)->order('create_time desc')->append(['status_name']); $search_model = $this->model->where($where)->field($field)->order('create_time desc')->append(['status_name']);
return $this->pageQuery($search_model); return $this->pageQuery($search_model);
} }
@ -71,7 +71,7 @@ class RoleService extends BaseAdminService
$where = array( $where = array(
['status', '=', 1] ['status', '=', 1]
); );
return $this->model->where($where)->field('role_id,role_name,status,create_time')->select()->toArray(); return $this->model->where($where)->field('role_id,role_name,role_key,status,create_time')->select()->toArray();
} }
/** /**

10
niucloud/app/service/admin/user_feedback/UserFeedbackService.php

@ -12,6 +12,7 @@
namespace app\service\admin\user_feedback; namespace app\service\admin\user_feedback;
use app\model\user_feedback\UserFeedback; use app\model\user_feedback\UserFeedback;
use app\model\customer_resources\CustomerResources;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -39,7 +40,7 @@ class UserFeedbackService extends BaseAdminService
$field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at'; $field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at';
$order = 'id desc'; $order = 'id desc';
$search_model = $this->model->withSearch(["id","user_id","feedback_text","attachment_url"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["user_id"], $where)->with(['customerResources'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +54,7 @@ class UserFeedbackService extends BaseAdminService
{ {
$field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at'; $field = 'id,user_id,feedback_text,attachment_url,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['customerResources'])->findOrEmpty()->toArray();
return $info; return $info;
} }
@ -95,5 +96,10 @@ class UserFeedbackService extends BaseAdminService
} }
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
} }

258
niucloud/app/service/api/apiService/CustomerResourcesService.php

@ -14,6 +14,7 @@ namespace app\service\api\apiService;
use app\model\campus_person_role\CampusPersonRole; use app\model\campus_person_role\CampusPersonRole;
use app\model\customer_resource_changes\CustomerResourceChanges; use app\model\customer_resource_changes\CustomerResourceChanges;
use app\model\customer_resources\CustomerResources; use app\model\customer_resources\CustomerResources;
use app\model\dict\Dict;
use app\model\personnel\Personnel; use app\model\personnel\Personnel;
use app\model\resource_sharing\ResourceSharing; use app\model\resource_sharing\ResourceSharing;
use app\model\six_speed\SixSpeed; use app\model\six_speed\SixSpeed;
@ -205,6 +206,263 @@ class CustomerResourcesService extends BaseApiService
} }
} }
//客户资源-获取客户资源修改记录列表
public function getCustomerResourceChangesEditLog(array $where)
{
$page_params = $this->getPageParam();//获取请求参数中的页码+分页数
$page = $page_params['page'];
$limit = $page_params['limit'];
//客户资源修改记录表
$data = CustomerResourceChanges::where('customer_resource_id', $where['customer_resource_id'])
->order('created_at', 'desc')
->with([
'personnel' => function ($query) {
}
])
->paginate([
'list_rows' => $limit,
'page' => $page,
])
->toArray();
$fieldZhArr = CustomerResources::FieldZh;//字段中文映射常量
//需要获取字段与字典key的映射关系数组
$fieldDictArr = [
'source_channel'=>'SourceChannel',//field=>dict_key(来源渠道)
'source'=>'source',//field=>dict_key(来源)
'gender'=>'zy_sex',//field=>dict_key(性别)
'purchasing_power'=>'customer_purchasing_power',//field=>dict_key(购买力)
'cognitive_idea'=>'cognitive_concept',//field=>dict_key(认知理念)
'initial_intent'=>'preliminarycustomerintention',//field=>dict_key(客户初步意向度)
'status'=>'kh_status',//field=>dict_key(客户状态)
];
$dict_arr = $this->getFieldDictionary($fieldDictArr);//字段与字典值列表的映射关系
$consultant_id_arr = [];
foreach ($data['data'] as $v) {
$modified_fields_arr = json_decode($v['modified_fields'], true);
$old_values_arr = json_decode($v['old_values'], true);
$new_values_arr = json_decode($v['new_values'], true);
//判断有没有修改过"顾问"字段
if(in_array('consultant',$modified_fields_arr)){
$consultant_id_arr[] = $old_values_arr['consultant'];
$consultant_id_arr[] = $new_values_arr['consultant'];
}
}
$consultant_id_arr = array_unique($consultant_id_arr);//去重
$dict_arr['consultant'] = [];//获取员工信息列表
if($consultant_id_arr){
$personnel = Personnel::whereIn('id',$consultant_id_arr)->field('id,name')->select()->toArray();
foreach($personnel as $v){
$dict_arr['consultant'][] = [
"name" => $v['name'],
"value" => $v['id'],
"sort" => 0,
"memo" => "",
];
}
}
$fieldDictKeyArr = array_keys($fieldDictArr);
$list = [];
foreach ($data['data'] as $v) {
$modified_fields_arr = json_decode($v['modified_fields'], true);
$old_values_arr = json_decode($v['old_values'], true);
$new_values_arr = json_decode($v['new_values'], true);
$update_arr = [];
foreach ($modified_fields_arr as $m_v) {
$old_value = $old_values_arr[$m_v] ?? '';
$new_value = $new_values_arr[$m_v] ?? '';
if(in_array($m_v,$fieldDictKeyArr)){
$dict = $dict_arr[$m_v];
foreach($dict as $d_v){
if($d_v['value'] == $old_value){
$old_value = $d_v['name'];
}
if($d_v['value'] == $new_value){
$new_value = $d_v['name'];
}
}
}
//一些字典和外键相关的字段值处理
$update_arr[] = [
'field_name_en' => $m_v,
'field_name_zh' => $fieldZhArr[$m_v] ?? $m_v,
'old_value' => $old_value,
'new_value' => $new_value,
];
}
$list[] = [
'id' => $v['id'],//日志id
'modification_time' => $v['modification_time'],//修改时间
'staff_id_name' => $v['staff_id_name'],//修改人的名字
'update_arr' => $update_arr,//数据变更数组
];
}
$data['data'] = $list;
return $data;
}
//客户资源-获取六要素修改记录列表
public function getSixSpeedModificationEditLog(array $where)
{
$page_params = $this->getPageParam();//获取请求参数中的页码+分页数
$page = $page_params['page'];
$limit = $page_params['limit'];
//六要素修改记录表
$data = SixSpeedModificationLog::where('operator_id', $where['customer_resource_id'])
->order('created_at', 'desc')
->with([
'personnel' => function ($query) {
}
])
->paginate([
'list_rows' => $limit,
'page' => $page,
])
->toArray();
$fieldZhArr = SixSpeed::FieldZh;//字段中文映射常量
//需要获取字段与字典key的映射关系数组
$fieldDictArr = [
'purchase_power'=>'customer_purchasing_power',//field=>dict_key(需求购买力)
'concept_awareness'=>'cognitive_concept',//field=>dict_key(认知理念)
'call_intent'=>'preliminarycustomerintention',//field=>dict_key(电话后的意向程度)
'is_closed'=>'global_true_or_false',//field=>dict_key(是否关单: 1-是, 0-否)
];
$dict_arr = $this->getFieldDictionary($fieldDictArr);//字段与字典值列表的映射关系
$consultant_id_arr = [];//顾问(人员)id数组
foreach ($data['data'] as $v) {
$modified_fields_arr = json_decode($v['modified_field'], true);
$old_values_arr = json_decode($v['old_value'], true);
$new_values_arr = json_decode($v['new_value'], true);
//判断有没有修改过"顾问(人员)"字段
if(in_array('staff_id',$modified_fields_arr)){
$consultant_id_arr[] = $old_values_arr['staff_id'];
$consultant_id_arr[] = $new_values_arr['staff_id'];
}
}
$consultant_id_arr = array_unique($consultant_id_arr);//去重
$dict_arr['consultant'] = [];//获取员工信息列表
if($consultant_id_arr){
$personnel = Personnel::whereIn('id',$consultant_id_arr)->field('id,name')->select()->toArray();
foreach($personnel as $v){
$dict_arr['consultant'][] = [
"name" => $v['name'],
"value" => $v['id'],
"sort" => 0,
"memo" => "",
];
}
}
$fieldDictKeyArr = array_keys($fieldDictArr);
$list = [];
foreach ($data['data'] as $v) {
$modified_fields_arr = json_decode($v['modified_field'], true);
$old_values_arr = json_decode($v['old_value'], true);
$new_values_arr = json_decode($v['new_value'], true);
$update_arr = [];
foreach ($modified_fields_arr as $m_v) {
$old_value = $old_values_arr[$m_v] ?? '';
$new_value = $new_values_arr[$m_v] ?? '';
if(in_array($m_v,$fieldDictKeyArr)){
$dict = $dict_arr[$m_v];
foreach($dict as $d_v){
if($d_v['value'] == $old_value){
$old_value = $d_v['name'];
}
if($d_v['value'] == $new_value){
$new_value = $d_v['name'];
}
}
}
//一些字典和外键相关的字段值处理
$update_arr[] = [
'field_name_en' => $m_v,
'field_name_zh' => $fieldZhArr[$m_v] ?? $m_v,
'old_value' => $old_value,
'new_value' => $new_value,
];
}
$list[] = [
'id' => $v['id'],//日志id
'modification_time' => $v['updated_at'],//修改时间
'staff_id_name' => $v['staff_id_name'],//修改人的名字
'update_arr' => $update_arr,//数据变更数组
];
}
$data['data'] = $list;
return $data;
}
/**
* 根据字段和字典键映射关系,获取字段对应字典项
*
* @param array $fieldDictMapping 字段 => 字典 key 映射数组
* @return array 字段 => 字典列表
*/
public function getFieldDictionary(array $fieldDictMapping): array
{
// 获取所有需要的字典 key 列表
$dictKeys = array_values($fieldDictMapping);
if (empty($dictKeys)) {
return [];
}
// 查询字典数据
$dictData = Dict::whereIn('key', $dictKeys)->select()->toArray();
//使用 array_column 构建 key => dict 的映射
$dictMap = array_column($dictData, null, 'key'); // 以 key 字段为索引
// 构建字段 => 字典项的映射
$result = [];
foreach ($fieldDictMapping as $field => $key) {
$result[$field] = $dictMap[$key]['dictionary'] ?? [];
//判断是不是获取的"来源渠道"的字典
if($field == 'source_channel'){
$append_arr = [
"name" => "线下",
"value" => "0",
"sort" => 0,
"memo" => "",
];
//插入到数组头部
array_unshift($result[$field],$append_arr);
}
}
return $result;
}
} }

47
niucloud/app/validate/campus_pay/CampusPay.php

@ -0,0 +1,47 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\validate\campus_pay;
use core\base\BaseValidate;
/**
* 账户及资金管理验证器
* Class CampusPay
* @package addon\app\validate\campus_pay
*/
class CampusPay extends BaseValidate
{
protected $rule = [
'campus_id' => 'require',
'mchid' => 'require',
'pay_sign_key' => 'require',
'apiclient_key' => 'require',
'apiclient_cert' => 'require',
'wx_pay_key' => 'require',
'wx_pay_key_id' => 'require',
];
protected $message = [
'campus_id.require' => ['common_validate.require', ['campus_id']],
'mchid.require' => ['common_validate.require', ['mchid']],
'pay_sign_key.require' => ['common_validate.require', ['pay_sign_key']],
'apiclient_key.require' => ['common_validate.require', ['apiclient_key']],
'apiclient_cert.require' => ['common_validate.require', ['apiclient_cert']],
'wx_pay_key.require' => ['common_validate.require', ['wx_pay_key']],
'wx_pay_key_id.require' => ['common_validate.require', ['wx_pay_key_id']],
];
protected $scene = [
"add" => ['campus_id', 'mchid', 'pay_sign_key', 'apiclient_key', 'apiclient_cert', 'wx_pay_key', 'wx_pay_key_id'],
"edit" => ['campus_id', 'mchid', 'pay_sign_key', 'apiclient_key', 'apiclient_cert', 'wx_pay_key', 'wx_pay_key_id']
];
}

4
niucloud/app/validate/order_table/OrderTable.php

@ -38,8 +38,8 @@ class OrderTable extends BaseValidate
]; ];
protected $scene = [ protected $scene = [
"add" => ['resource_id', 'order_status', 'payment_type', 'order_amount', 'course_id', 'class_id'], "add" => ['resource_id', 'payment_type', 'order_amount', 'course_id', 'class_id'],
"edit" => ['resource_id', 'order_status', 'payment_type', 'order_amount', 'course_id', 'class_id'] "edit" => ['resource_id', 'payment_type', 'order_amount', 'course_id', 'class_id']
]; ];
} }

6
niucloud/app/validate/reimbursement/Reimbursement.php

@ -24,7 +24,6 @@ class Reimbursement extends BaseValidate
'amount' => 'require', 'amount' => 'require',
'description' => 'require', 'description' => 'require',
'status' => 'require', 'status' => 'require',
'process_id' => 'require',
]; ];
protected $message = [ protected $message = [
@ -32,12 +31,11 @@ class Reimbursement extends BaseValidate
'amount.require' => ['common_validate.require', ['amount']], 'amount.require' => ['common_validate.require', ['amount']],
'description.require' => ['common_validate.require', ['description']], 'description.require' => ['common_validate.require', ['description']],
'status.require' => ['common_validate.require', ['status']], 'status.require' => ['common_validate.require', ['status']],
'process_id.require' => ['common_validate.require', ['process_id']],
]; ];
protected $scene = [ protected $scene = [
"add" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status', 'process_id'], "add" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status'],
"edit" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status', 'process_id'] "edit" => ['applicant_id', 'amount', 'description', 'receipt_url', 'status']
]; ];
} }

10
niucloud/app/validate/salary/Salary.php

@ -21,25 +21,31 @@ class Salary extends BaseValidate
protected $rule = [ protected $rule = [
'staff_id' => 'require', 'staff_id' => 'require',
'department_id' => 'require',
'base_salary' => 'require', 'base_salary' => 'require',
'performance_bonus' => 'require', 'performance_bonus' => 'require',
'deductions' => 'require', 'deductions' => 'require',
'other_subsidies' => 'require',
'payment_status' => 'require', 'payment_status' => 'require',
'payment_method' => 'require',
'salary_month' => 'require', 'salary_month' => 'require',
]; ];
protected $message = [ protected $message = [
'staff_id.require' => ['common_validate.require', ['staff_id']], 'staff_id.require' => ['common_validate.require', ['staff_id']],
'department_id.require' => ['common_validate.require', ['department_id']],
'base_salary.require' => ['common_validate.require', ['base_salary']], 'base_salary.require' => ['common_validate.require', ['base_salary']],
'performance_bonus.require' => ['common_validate.require', ['performance_bonus']], 'performance_bonus.require' => ['common_validate.require', ['performance_bonus']],
'deductions.require' => ['common_validate.require', ['deductions']], 'deductions.require' => ['common_validate.require', ['deductions']],
'other_subsidies.require' => ['common_validate.require', ['other_subsidies']],
'payment_status.require' => ['common_validate.require', ['payment_status']], 'payment_status.require' => ['common_validate.require', ['payment_status']],
'payment_method.require' => ['common_validate.require', ['payment_method']],
'salary_month.require' => ['common_validate.require', ['salary_month']], 'salary_month.require' => ['common_validate.require', ['salary_month']],
]; ];
protected $scene = [ protected $scene = [
"add" => ['staff_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'net_salary', 'payment_status', 'payment_method', 'remarks', 'salary_month', 'department_id', 'process_id'], "add" => ['staff_id', 'department_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'payment_status', 'payment_method', 'remarks', 'salary_month'],
"edit" => ['staff_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'net_salary', 'payment_status', 'payment_method', 'remarks', 'salary_month', 'department_id', 'process_id'] "edit" => ['staff_id', 'department_id', 'base_salary', 'performance_bonus', 'deductions', 'other_subsidies', 'payment_status', 'payment_method', 'remarks', 'salary_month']
]; ];
} }

6
niucloud/app/validate/user_feedback/UserFeedback.php

@ -20,13 +20,11 @@ class UserFeedback extends BaseValidate
{ {
protected $rule = [ protected $rule = [
'user_id' => 'require',
'feedback_text' => 'require',
]; ];
protected $message = [ protected $message = [
'user_id.require' => ['common_validate.require', ['user_id']],
'feedback_text.require' => ['common_validate.require', ['feedback_text']],
]; ];
protected $scene = [ protected $scene = [

1
niucloud/public/admin/assets/404-145f080f.css

@ -0,0 +1 @@
.error[data-v-4f4088b5]{text-align:center;height:100vh;display:flex;justify-content:center;align-items:center}.error .error-code[data-v-4f4088b5]{color:var(--el-color-primary);font-size:150px}.error .error-text[data-v-4f4088b5]{color:#0e77fd}.error .el-button[data-v-4f4088b5]{width:176px;background-color:#0e77fd;color:#fff}

1
niucloud/public/admin/assets/404-62395b03.js

@ -1 +0,0 @@
import{d as l,r as d,o as i,c as p,a as t,b as u,e as m,w as x,u as v,f,E as h,p as g,g as I,h as b,i as w,t as S}from"./index-f5d841af.js";/* empty css */import{_ as B}from"./_plugin-vue_export-helper-c27b6911.js";const k=""+new URL("error-ab7e4004.png",import.meta.url).href,o=e=>(g("data-v-c0934944"),e=e(),I(),e),y={class:"error"},C={class:"flex items-center"},E=o(()=>t("div",null,[t("img",{class:"w-[240px]",src:k})],-1)),N={class:"text-left ml-[100px]"},R=o(()=>t("div",{class:"error-text text-[28px] font-bold"},"404错误!",-1)),U=o(()=>t("div",{class:"text-[#222] text-[20px] mt-[15px]"}," 哎呀,出错了!您访问的页面不存在... ",-1)),V=o(()=>t("div",{class:"text-[#c4c2c2] text-[12px] mt-[5px]"}," 尝试检查URL的错误,然后点击浏览器刷新按钮。 ",-1)),L={class:"mt-[40px]"},$=l({__name:"404",setup(e){let s=null;const a=d(5),c=f();return s=setInterval(()=>{a.value===0?(clearInterval(s),c.go(-1)):a.value--},1e3),i(()=>{s&&clearInterval(s)}),(r,n)=>{const _=h;return b(),p("div",y,[t("div",C,[u(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[m(_,{class:"bottom",onClick:n[0]||(n[0]=D=>v(c).go(-1))},{default:x(()=>[w(S(a.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-c0934944"]]);export{z as default};

1
niucloud/public/admin/assets/404-c962cf1f.js

@ -0,0 +1 @@
import{d as l,r as d,o as i,c as p,a as t,b as u,e as m,w as x,u as v,f,E as h,p as b,g,h as I,i as w,t as S}from"./index-1dc7b228.js";/* empty css */import{_ as B}from"./_plugin-vue_export-helper-c27b6911.js";const k=""+new URL("error-ab7e4004.png",import.meta.url).href,o=e=>(b("data-v-4f4088b5"),e=e(),g(),e),y={class:"error"},C={class:"flex items-center"},E=o(()=>t("div",null,[t("img",{class:"w-[240px]",src:k})],-1)),N={class:"text-left ml-[100px]"},R=o(()=>t("div",{class:"error-text text-[28px] font-bold"},"404错误!",-1)),U=o(()=>t("div",{class:"text-[#222] text-[20px] mt-[15px]"},"哎呀,出错了!您访问的页面不存在...",-1)),V=o(()=>t("div",{class:"text-[#c4c2c2] text-[12px] mt-[5px]"},"尝试检查URL的错误,然后点击浏览器刷新按钮。",-1)),L={class:"mt-[40px]"},$=l({__name:"404",setup(e){let s=null;const a=d(5),n=f();return s=setInterval(()=>{a.value===0?(clearInterval(s),n.go(-1)):a.value--},1e3),i(()=>{s&&clearInterval(s)}),(r,c)=>{const _=h;return I(),p("div",y,[t("div",C,[u(r.$slots,"content",{},()=>[E],!0),t("div",N,[R,U,V,t("div",L,[m(_,{class:"bottom",onClick:c[0]||(c[0]=D=>v(n).go(-1))},{default:x(()=>[w(S(a.value)+" 秒后返回上一页",1)]),_:1})])])])])}}});const z=B($,[["__scopeId","data-v-4f4088b5"]]);export{z as default};

1
niucloud/public/admin/assets/404-e4083eb7.css

@ -1 +0,0 @@
.error[data-v-c0934944]{text-align:center;height:100vh;display:flex;justify-content:center;align-items:center}.error .error-code[data-v-c0934944]{color:var(--el-color-primary);font-size:150px}.error .error-text[data-v-c0934944]{color:#0e77fd}.error .el-button[data-v-c0934944]{width:176px;background-color:#0e77fd;color:#fff}

1
niucloud/public/admin/assets/App-0882181b.js

@ -1 +0,0 @@
import{c5 as f}from"./index-f5d841af.js";export{f as default};

1
niucloud/public/admin/assets/App-16d4b42a.js

@ -0,0 +1 @@
import{c2 as f}from"./index-1dc7b228.js";export{f as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-306ddab0.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a658c3b6.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";import"./future_ontent-5dabe1b5.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-aa05ac94.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a1f23d9d.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";import"./future_ontent-5dabe1b5.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-b8059124.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-0fbc701d.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";import"./instructional_material-aec0964c.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-cf13a734.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-91677b3b.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";import"./future_ontent-5dabe1b5.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-e2131f72.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-9c5c9cc4.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit-ee5b45e9.js

@ -1 +0,0 @@
import{_ as o}from"./Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-5df4a241.js";import"./index-f5d841af.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-bd01ed10.js";import"./index.vue_vue_type_style_index_0_lang-7d665fb9.js";import"./attachment-740d9717.js";import"./index.vue_vue_type_script_setup_true_lang-f45dcca3.js";/* empty css */import"./el-form-item-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./el-tooltip-4ed993c7.js";/* empty css *//* empty css *//* empty css *//* empty css *//* empty css */import"./index.vue_vue_type_script_setup_true_lang-1f394a8b.js";/* empty css */import"./index.vue_vue_type_script_setup_true_lang-30796a48.js";import"./sys-4eb1a831.js";import"./_plugin-vue_export-helper-c27b6911.js";import"./index.vue_vue_type_style_index_0_lang-b7271466.js";import"./index.vue_vue_type_style_index_0_lang-3c1b8cd7.js";import"./index-21a2ccda.js";import"./sortable.esm-be94e56d.js";import"./dict-f88a0e26.js";import"./lesson_course_teaching-fdaaef77.js";import"./future_ontent-5dabe1b5.js";export{o as default};

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-0fbc701d.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-5df4a241.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-91677b3b.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-9c5c9cc4.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a1f23d9d.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/Jump-lesson-library-edit.vue_vue_type_style_index_0_lang-a658c3b6.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/TencentMapPicker-59c0503c.js

File diff suppressed because one or more lines are too long

1
niucloud/public/admin/assets/TencentMapPicker-96eea39a.css

@ -1 +0,0 @@
.map-picker[data-v-fcaa04a3]{display:flex;flex-direction:column;gap:16px}.map-container[data-v-fcaa04a3]{width:100%;height:400px;border:1px solid #dcdfe6;border-radius:4px;position:relative}.map-placeholder[data-v-fcaa04a3]{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#909399;font-size:14px}.address-search[data-v-fcaa04a3]{display:flex;gap:8px;margin-top:20px}

1
niucloud/public/admin/assets/Verify-3982a86a.css

File diff suppressed because one or more lines are too long

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

Loading…
Cancel
Save