Browse Source

Merge remote-tracking branch 'origin/master'

master
liutong 10 months ago
parent
commit
3cc97f3a90
  1. 81
      admin/components.d.ts
  2. 24
      admin/src/app/api/communication_records.ts
  3. 27
      admin/src/app/api/student_courses.ts
  4. 11
      admin/src/app/api/sys.ts
  5. 30
      admin/src/app/lang/zh-cn/communication_records.communication_records.json
  6. 4
      admin/src/app/lang/zh-cn/course.course.json
  7. 10
      admin/src/app/lang/zh-cn/student_courses.student_courses.json
  8. 69
      admin/src/app/views/campus_person_role/campus_person_role.vue
  9. 312
      admin/src/app/views/communication_records/communication_records.vue
  10. 268
      admin/src/app/views/communication_records/components/communication-records-edit.vue
  11. 20
      admin/src/app/views/course/components/course-edit.vue
  12. 11
      admin/src/app/views/course/course.vue
  13. 111
      admin/src/app/views/setting/pay.vue
  14. 151
      admin/src/app/views/student_courses/components/student-courses-edit.vue
  15. 194
      admin/src/app/views/student_courses/student_courses.vue
  16. 259
      admin/src/app/views/timetables/timetables.vue
  17. 212
      admin/src/app/views/xsyj/xsyj.vue
  18. 35
      niucloud/app/adminapi/controller/communication_records/CommunicationRecords.php
  19. 1
      niucloud/app/adminapi/controller/course/Course.php
  20. 22
      niucloud/app/adminapi/controller/student_courses/StudentCourses.php
  21. 14
      niucloud/app/adminapi/controller/sys/System.php
  22. 3
      niucloud/app/adminapi/route/communication_records.php
  23. 6
      niucloud/app/adminapi/route/student_courses.php
  24. 5
      niucloud/app/adminapi/route/sys.php
  25. 126
      niucloud/app/model/communication_records/CommunicationRecords.php
  26. 116
      niucloud/app/model/course/Course.php
  27. 55
      niucloud/app/model/student/Student.php
  28. 72
      niucloud/app/model/student_courses/StudentCourses.php
  29. 27
      niucloud/app/service/admin/communication_records/CommunicationRecordsService.php
  30. 45
      niucloud/app/service/admin/student_courses/StudentCoursesService.php
  31. 20
      niucloud/app/service/admin/sys/SystemService.php
  32. 6
      niucloud/app/validate/communication_records/CommunicationRecords.php

81
admin/components.d.ts

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

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

@ -1,5 +1,7 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- communication_records
/**
*
@ -16,7 +18,7 @@ export function getCommunicationRecordsList(params: Record<string, any>) {
* @returns
*/
export function getCommunicationRecordsInfo(id: number) {
return request.get(`communication_records/communication_records/${id}`)
return request.get(`communication_records/communication_records/${id}`);
}
/**
@ -25,10 +27,7 @@ export function getCommunicationRecordsInfo(id: number) {
* @returns
*/
export function addCommunicationRecords(params: Record<string, any>) {
return request.post('communication_records/communication_records', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('communication_records/communication_records', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,11 +37,7 @@ export function addCommunicationRecords(params: Record<string, any>) {
* @returns
*/
export function editCommunicationRecords(params: Record<string, any>) {
return request.put(
`communication_records/communication_records/${params.id}`,
params,
{ showErrorMessage: true, showSuccessMessage: true }
)
return request.put(`communication_records/communication_records/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -51,10 +46,11 @@ export function editCommunicationRecords(params: Record<string, any>) {
* @returns
*/
export function deleteCommunicationRecords(id: number) {
return request.delete(`communication_records/communication_records/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`communication_records/communication_records/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('communication_records/customer_resources_all', {params})
}
// USER_CODE_END -- communication_records

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

@ -1,5 +1,9 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- student_courses
/**
*
@ -16,7 +20,7 @@ export function getStudentCoursesList(params: Record<string, any>) {
* @returns
*/
export function getStudentCoursesInfo(id: number) {
return request.get(`student_courses/student_courses/${id}`)
return request.get(`student_courses/student_courses/${id}`);
}
/**
@ -25,10 +29,7 @@ export function getStudentCoursesInfo(id: number) {
* @returns
*/
export function addStudentCourses(params: Record<string, any>) {
return request.post('student_courses/student_courses', params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.post('student_courses/student_courses', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -38,10 +39,7 @@ export function addStudentCourses(params: Record<string, any>) {
* @returns
*/
export function editStudentCourses(params: Record<string, any>) {
return request.put(`student_courses/student_courses/${params.id}`, params, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.put(`student_courses/student_courses/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -50,10 +48,13 @@ export function editStudentCourses(params: Record<string, any>) {
* @returns
*/
export function deleteStudentCourses(id: number) {
return request.delete(`student_courses/student_courses/${id}`, {
showErrorMessage: true,
showSuccessMessage: true,
})
return request.delete(`student_courses/student_courses/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithStudentList(params: Record<string,any>){
return request.get('student_courses/student_all', {params})
}export function getWithCourseList(params: Record<string,any>){
return request.get('student_courses/course_all', {params})
}
// USER_CODE_END -- student_courses

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

@ -764,3 +764,14 @@ export function getYjpzConfig() {
export function yjpzConfig(params: Record<string, any>) {
return request.post(`sys/yjpz_config`, params)
}
export function xsyjConfig(params: Record<string, any>) {
return request.post(`sys/xsyj_config`, params)
}
export function getXsyjConfig() {
return request.get('sys/get_xsyj_config')
}

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

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

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

@ -9,8 +9,8 @@
"durationPlaceholder": "请输入课程时长",
"sessionCount": "课时数量",
"sessionCountPlaceholder": "请输入课时数量",
"singleSessionCount": "单次逍客数量",
"singleSessionCountPlaceholder": "请输入单次逍客数量",
"singleSessionCount": "单次消课数量",
"singleSessionCountPlaceholder": "请输入单次消课数量",
"price": "课程价格",
"pricePlaceholder": "请输入课程价格",
"internalReminder": "内部提醒课时",

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

@ -1,10 +1,8 @@
{
"id": "记录编号",
"idPlaceholder": "请输入记录编号",
"studentId": "学员ID",
"studentIdPlaceholder": "请输入学员ID",
"courseId": "课程ID",
"courseIdPlaceholder": "请输入课程ID",
"studentId":"学员",
"studentIdPlaceholder":"全部",
"courseId":"课程",
"courseIdPlaceholder":"全部",
"totalHours":"总正式课时数",
"totalHoursPlaceholder":"请输入总正式课时数",
"giftHours":"赠送课时数",

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

@ -65,29 +65,29 @@
</el-select>
</el-form-item>
<!-- <el-form-item :label="t('deptId')" prop="dept_id">-->
<!-- <el-select-->
<!-- class="w-[280px]"-->
<!-- v-model="campusPersonRoleTable.searchParam.dept_id"-->
<!-- clearable-->
<!-- :placeholder="t('deptIdPlaceholder')"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="(item, index) in deptIdList"-->
<!-- :key="index"-->
<!-- :label="item['department_name']"-->
<!-- :value="item['id']"-->
<!-- />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item :label="t('deptId')" prop="dept_id">
<el-select
class="w-[280px]"
v-model="campusPersonRoleTable.searchParam.dept_id"
clearable
:placeholder="t('deptIdPlaceholder')"
>
<el-option
v-for="(item, index) in deptIdList"
:key="index"
:label="item['department_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCampusPersonRoleList()"
>{{ t('search') }}
</el-button>
<el-button @click="resetForm(searchFormRef)"
>{{ t('reset') }}
</el-button>
<el-button type="primary" @click="loadCampusPersonRoleList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
</el-form-item>
</el-form>
</el-card>
@ -137,12 +137,12 @@
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)"
>{{ t('edit') }}
</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)"
>{{ t('delete') }}
</el-button>
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
@ -169,7 +169,7 @@
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import {
getCampusPersonRoleList,
deleteCampusPersonRole,
@ -178,14 +178,15 @@ import {
getWithSysRoleList,
getWithDepartmentsList,
} from '@/app/api/campus_person_role'
import { getQueryString } from '@/utils/common'
import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus'
import Edit from '@/app/views/campus_person_role/components/campus-person-role-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
// ?dept_id=1
const dept_id = pageName == '市场人员列表' ? 1 : 2;
let campusPersonRoleTable = reactive({
page: 1,
limit: 10,
@ -196,7 +197,7 @@ let campusPersonRoleTable = reactive({
campus_id: '',
person_id: '',
role_id: '',
dept_id: getQueryString(route.path, 'dept_id'),
dept_id: dept_id,
},
})
@ -205,6 +206,8 @@ const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
/**
* 获取角色关系列表
*/
@ -234,9 +237,7 @@ const editCampusPersonRoleDialog: Record<string, any> | null = ref(null)
* 添加角色关系
*/
const addEvent = () => {
editCampusPersonRoleDialog.value.setFormData({
dept_id: campusPersonRoleTable.searchParam.dept_id,
})
editCampusPersonRoleDialog.value.setFormData()
editCampusPersonRoleDialog.value.showDialog = true
}

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

@ -1,6 +1,7 @@
<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">
@ -8,223 +9,93 @@
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="communicationRecordsTable.searchParam"
ref="searchFormRef"
>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="communicationRecordsTable.searchParam.staff_id"
:placeholder="t('staffIdPlaceholder')"
/>
</el-form-item>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="communicationRecordsTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="communicationRecordsTable.searchParam.resource_id"
:placeholder="t('resourceIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('resourceType')" prop="resource_type">
<el-input
v-model="communicationRecordsTable.searchParam.resource_type"
:placeholder="t('resourceTypePlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('communicationType')"
prop="communication_type"
>
<el-input
v-model="communicationRecordsTable.searchParam.communication_type"
:placeholder="t('communicationTypePlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('communicationResult')"
prop="communication_result"
>
<el-input
v-model="
communicationRecordsTable.searchParam.communication_result
"
:placeholder="t('communicationResultPlaceholder')"
/>
</el-form-item>
<el-form-item
:label="t('communicationTime')"
prop="communication_time"
>
<el-input
v-model="communicationRecordsTable.searchParam.communication_time"
:placeholder="t('communicationTimePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('remarks')" prop="remarks">
<el-input
v-model="communicationRecordsTable.searchParam.remarks"
:placeholder="t('remarksPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('tag')" prop="tag">
<el-input
v-model="communicationRecordsTable.searchParam.tag"
:placeholder="t('tagPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('businessId')" prop="business_id">
<el-input
v-model="communicationRecordsTable.searchParam.business_id"
:placeholder="t('businessIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('createdAt')" prop="created_at">
<el-input
v-model="communicationRecordsTable.searchParam.created_at"
:placeholder="t('createdAtPlaceholder')"
/>
<el-select class="w-[280px]" v-model="communicationRecordsTable.searchParam.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
<el-option
v-for="(item, index) in resourceIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('updatedAt')" prop="updated_at">
<el-input
v-model="communicationRecordsTable.searchParam.updated_at"
:placeholder="t('updatedAtPlaceholder')"
<el-form-item :label="t('communicationType')" prop="communication_type">
<el-select class="w-[280px]" v-model="communicationRecordsTable.searchParam.communication_type" clearable :placeholder="t('communicationTypePlaceholder')">
<el-option label="全部" value=""></el-option>
<el-option
v-for="(item, index) in communication_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadCommunicationRecordsList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadCommunicationRecordsList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="communicationRecordsTable.data"
size="large"
v-loading="communicationRecordsTable.loading"
>
<el-table :data="communicationRecordsTable.data" size="large" v-loading="communicationRecordsTable.loading">
<template #empty>
<span>{{
!communicationRecordsTable.loading ? t('emptyData') : ''
}}</span>
<span>{{ !communicationRecordsTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="resource_id_name" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="resource_id"
:label="t('resourceId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="resource_type"
:label="t('resourceType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication_type"
:label="t('communicationType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication_result"
:label="t('communicationResult')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="resource_type" :label="t('resourceType')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="communication_time"
:label="t('communicationTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('communicationType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in communication_typeList">
<div v-if="item.value == row.communication_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="tag"
:label="t('tag')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('communicationResult')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in communication_resultList">
<div v-if="item.value == row.communication_result">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="business_id"
:label="t('businessId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="communication_time" :label="t('communicationTime')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="created_at"
:label="t('createdAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="remarks" :label="t('remarks')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="updated_at"
:label="t('updatedAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column :label="t('tag')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in tagList">
<div v-if="item.value == row.tag">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="communicationRecordsTable.page"
v-model:page-size="communicationRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="communicationRecordsTable.total"
@size-change="loadCommunicationRecordsList()"
@current-change="loadCommunicationRecordsList"
/>
<el-pagination v-model:current-page="communicationRecordsTable.page" v-model:page-size="communicationRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="communicationRecordsTable.total"
@size-change="loadCommunicationRecordsList()" @current-change="loadCommunicationRecordsList" />
</div>
</div>
<edit
ref="editCommunicationRecordsDialog"
@complete="loadCommunicationRecordsList"
/>
<edit ref="editCommunicationRecordsDialog" @complete="loadCommunicationRecordsList" />
</el-card>
</div>
</template>
@ -233,16 +104,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import {
getCommunicationRecordsList,
deleteCommunicationRecords,
} from '@/app/api/communication_records'
import { getCommunicationRecordsList, deleteCommunicationRecords, getWithCustomerResourcesList } from '@/app/api/communication_records'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/communication_records/components/communication-records-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let communicationRecordsTable = reactive({
page: 1,
@ -251,18 +119,9 @@ let communicationRecordsTable = reactive({
loading: true,
data: [],
searchParam:{
staff_id: '',
resource_id: '',
resource_type: '',
communication_type: '',
communication_result: '',
communication_time: '',
remarks: '',
tag: '',
business_id: '',
created_at: '',
updated_at: '',
},
"resource_id":"",
"communication_type":""
}
})
const searchFormRef = ref<FormInstance>()
@ -271,6 +130,21 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([])
//
const communication_typeList = ref([] as any[])
const communication_typeDictList = async () => {
communication_typeList.value = await (await useDictionary('communication_type')).data.dictionary
}
communication_typeDictList();
const communication_resultList = ref([] as any[])
const communication_resultDictList = async () => {
communication_resultList.value = await (await useDictionary('communication_result')).data.dictionary
}
communication_resultDictList();
const tagList = ref([] as any[])
const tagDictList = async () => {
tagList.value = await (await useDictionary('tag')).data.dictionary
}
tagDictList();
/**
* 获取沟通记录列表
@ -282,14 +156,12 @@ const loadCommunicationRecordsList = (page: number = 1) => {
getCommunicationRecordsList({
page: communicationRecordsTable.page,
limit: communicationRecordsTable.limit,
...communicationRecordsTable.searchParam,
})
.then((res) => {
...communicationRecordsTable.searchParam
}).then(res => {
communicationRecordsTable.loading = false
communicationRecordsTable.data = res.data.data
communicationRecordsTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
communicationRecordsTable.loading = false
})
}
@ -318,19 +190,27 @@ const editEvent = (data: any) => {
* 删除沟通记录
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('communicationRecordsDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('communicationRecordsDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteCommunicationRecords(id)
.then(() => {
}
).then(() => {
deleteCommunicationRecords(id).then(() => {
loadCommunicationRecordsList()
}).catch(() => {
})
.catch(() => {})
})
}
const resourceIdList = ref([])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()

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

@ -1,135 +1,79 @@
<template>
<el-dialog
v-model="showDialog"
:title="
formData.id
? t('updateCommunicationRecords')
: t('addCommunicationRecords')
"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-form-item :label="t('staffId')" prop="staff_id">
<el-input
v-model="formData.staff_id"
clearable
:placeholder="t('staffIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateCommunicationRecords') : t('addCommunicationRecords')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input
v-model="formData.resource_id"
clearable
:placeholder="t('resourceIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in resourceIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('resourceType')" prop="resource_type">
<el-input
v-model="formData.resource_type"
clearable
:placeholder="t('resourceTypePlaceholder')"
class="input-width"
/>
<el-input v-model="formData.resource_type" clearable :placeholder="t('resourceTypePlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('communicationType')" prop="communication_type">
<el-input
v-model="formData.communication_type"
clearable
:placeholder="t('communicationTypePlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.communication_type" clearable :placeholder="t('communicationTypePlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in communication_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
:label="t('communicationResult')"
prop="communication_result"
>
<el-input
v-model="formData.communication_result"
clearable
:placeholder="t('communicationResultPlaceholder')"
class="input-width"
<el-form-item :label="t('communicationResult')" prop="communication_result">
<el-select class="input-width" v-model="formData.communication_result" clearable :placeholder="t('communicationResultPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in communication_resultList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('communicationTime')" prop="communication_time">
<el-input
<el-form-item :label="t('communicationTime')" prop="communication_time" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.communication_time"
clearable
:placeholder="t('communicationTimePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('communicationTimePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('remarks')" >
<el-input
v-model="formData.remarks"
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
/>
<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('tag')" >
<el-input
v-model="formData.tag"
clearable
:placeholder="t('tagPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.tag" clearable :placeholder="t('tagPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in tagList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('businessId')">
<el-input
v-model="formData.business_id"
clearable
:placeholder="t('businessIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('createdAt')">
<el-input
v-model="formData.created_at"
clearable
:placeholder="t('createdAtPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('updatedAt')">
<el-input
v-model="formData.updated_at"
clearable
:placeholder="t('updatedAtPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -140,11 +84,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addCommunicationRecords,
editCommunicationRecords,
getCommunicationRecordsInfo,
} from '@/app/api/communication_records'
import { addCommunicationRecords, editCommunicationRecords, getCommunicationRecordsInfo, getWithCustomerResourcesList } from '@/app/api/communication_records'
let showDialog = ref(false)
const loading = ref(false)
@ -154,7 +94,6 @@ const loading = ref(false)
*/
const initialFormData = {
id: '',
staff_id: '',
resource_id: '',
resource_type: '',
communication_type: '',
@ -162,9 +101,6 @@ const initialFormData = {
communication_time: '',
remarks: '',
tag: '',
business_id: '',
created_at: '',
updated_at: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
@ -173,53 +109,41 @@ const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
],
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
],
]
,
resource_type: [
{
required: true,
message: t('resourceTypePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('resourceTypePlaceholder'), trigger: 'blur' },
]
,
communication_type: [
{
required: true,
message: t('communicationTypePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('communicationTypePlaceholder'), trigger: 'blur' },
]
,
communication_result: [
{
required: true,
message: t('communicationResultPlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('communicationResultPlaceholder'), trigger: 'blur' },
]
,
communication_time: [
{
required: true,
message: t('communicationTimePlaceholder'),
trigger: 'blur',
},
],
{ required: true, message: t('communicationTimePlaceholder'), trigger: 'blur' },
]
,
remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
tag: [{ required: true, message: t('tagPlaceholder'), trigger: 'blur' }],
business_id: [
{ required: true, message: t('businessIdPlaceholder'), trigger: 'blur' },
],
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' },
],
updated_at: [
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
],
]
,
tag: [
{ required: true, message: t('tagPlaceholder'), trigger: 'blur' },
]
,
}
})
@ -239,13 +163,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -253,14 +175,37 @@ const confirm = async (formEl: FormInstance | undefined) => {
}
//
let communication_typeList = ref([])
const communication_typeDictList = async () => {
communication_typeList.value = await (await useDictionary('communication_type')).data.dictionary
}
communication_typeDictList();
watch(() => communication_typeList.value, () => { formData.communication_type = communication_typeList.value[0].value })
let communication_resultList = ref([])
const communication_resultDictList = async () => {
communication_resultList.value = await (await useDictionary('communication_result')).data.dictionary
}
communication_resultDictList();
watch(() => communication_resultList.value, () => { formData.communication_result = communication_resultList.value[0].value })
let tagList = ref([])
const tagDictList = async () => {
tagList.value = await (await useDictionary('tag')).data.dictionary
}
tagDictList();
watch(() => tagList.value, () => { formData.tag = tagList.value[0].value })
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getCommunicationRecordsInfo(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]
})
}
@ -278,12 +223,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -310,7 +250,7 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>

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

@ -24,14 +24,19 @@
</el-form-item>
<el-form-item :label="t('courseType')" prop="course_type">
<el-input
<el-select
class="input-width"
v-model="formData.course_type"
clearable
:placeholder="t('courseTypePlaceholder')"
class="input-width"
>
<el-option
v-for="(item, index) in courseTypeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('duration')" prop="duration">
<el-input
v-model="formData.duration"
@ -193,6 +198,13 @@ const formRules = computed(() => {
const emit = defineEmits(['complete'])
const courseTypeList = ref([])
const getcourseTypeList = async () => {
courseTypeList.value = await (
await useDictionary('course_type')
).data.dictionary
}
getcourseTypeList()
/**
* 确认
* @param formEl

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

@ -24,10 +24,17 @@
/>
</el-form-item>
<el-form-item :label="t('courseType')" prop="course_type">
<el-input
<el-select
v-model="courseTable.searchParam.course_type"
:placeholder="t('courseTypePlaceholder')"
>
<el-option
v-for="item in courseTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('duration')" prop="duration">
<el-input
@ -220,7 +227,7 @@ let courseTable = reactive({
remarks: '',
},
})
const courseTypeList = useDictionary('course_type')
const searchFormRef = ref<FormInstance>()
//

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

@ -1,89 +1,44 @@
<template>
<!--支付设置-->
<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>
<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"
>
<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"
>
<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>
<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">
<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 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>
<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>
<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)"
/>
<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>
<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>
<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>
@ -93,23 +48,15 @@
<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>
<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">
<component
:is="item.setting_component"
:ref="(el) => setPayTypeRefs(el, item.key)"
v-if="item.setting_component"
@complete="setConfigInfo"
/>
<component :is="item.setting_component" :ref="(el) => setPayTypeRefs(el, item.key)" v-if="item.setting_component" @complete="setConfigInfo"/>
</template>
</div>
</template>
@ -133,16 +80,13 @@ const modules: any = import.meta.glob('@/**/*.vue')
getAllPayType().then(({ data }) => {
Object.keys(data).forEach((key: string) => {
data[key].setting_component &&
(data[key].setting_component = defineAsyncComponent(
modules[data[key].setting_component]
))
data[key].setting_component && (data[key].setting_component = defineAsyncComponent(modules[data[key].setting_component]))
})
payTypeList.value = data
})
const setPayTypeRefs = (el: any, index: string) => {
payTypeRefs.value[index] = el
payTypeRefs.value[index] = (el)
}
const payLoading = ref(true)
@ -153,7 +97,7 @@ const setConfigBtn = ref()
//
const payConfigData = ref([])
const checkPayConfigList = () => {
getPayConfigList().then((res) => {
getPayConfigList().then(res => {
const payData = res.data
for (const i in payData) {
const payType = payData[i].pay_type
@ -185,7 +129,7 @@ checkPayConfigList()
//
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) {
element.config = data.config
}
@ -201,10 +145,7 @@ const configPayFn = (data: any) => {
//
const enablePaymentMode = async (data: any) => {
if (
payTypeRefs.value[data.key] &&
typeof payTypeRefs.value[data.key].enableVerify == 'function'
) {
if (payTypeRefs.value[data.key] && typeof payTypeRefs.value[data.key].enableVerify == 'function') {
payTypeRefs.value[data.key].setFormData(data)
const verify = payTypeRefs.value[data.key].enableVerify()
@ -236,7 +177,7 @@ watch(isEdit, (newValue, oldValue) => {
const sortableFn = (item, index) => {
const sortable = Sortable.create(item, {
group: {
put: false, //
put: false //
},
handle: '.handle',
animation: 200,
@ -245,7 +186,7 @@ const sortableFn = (item, index) => {
const key = evt.target.getAttribute('data-key')
const data = payConfigData.value[key].pay_type
data.splice(evt.newIndex, 0, ...data.splice(evt.oldIndex, 1))
},
}
})
}
@ -259,7 +200,7 @@ const saveFn = () => {
})
})
setPatConfig({ config: data }).then((res) => {
setPatConfig({ config: data }).then(res => {
checkPayConfigList()
isEdit.value = false
payLoading.value = false

151
admin/src/app/views/student_courses/components/student-courses-edit.vue

@ -1,83 +1,66 @@
<template>
<el-dialog
v-model="showDialog"
:title="formData.id ? t('updateStudentCourses') : t('addStudentCourses')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateStudentCourses') : t('addStudentCourses')" 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('studentId')" prop="student_id">
<el-input
v-model="formData.student_id"
clearable
:placeholder="t('studentIdPlaceholder')"
class="input-width"
<el-select class="input-width" v-model="formData.student_id" clearable :placeholder="t('studentIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in studentIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input
v-model="formData.course_id"
clearable
:placeholder="t('courseIdPlaceholder')"
class="input-width"
<el-select class="input-width" 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('totalHours')" prop="total_hours">
<el-input
v-model="formData.total_hours"
clearable
:placeholder="t('totalHoursPlaceholder')"
class="input-width"
/>
<el-input v-model="formData.total_hours" clearable :placeholder="t('totalHoursPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('giftHours')" >
<el-input
v-model="formData.gift_hours"
clearable
:placeholder="t('giftHoursPlaceholder')"
class="input-width"
/>
<el-input v-model="formData.gift_hours" clearable :placeholder="t('giftHoursPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('startDate')" prop="start_date">
<el-input
<el-form-item :label="t('startDate')" prop="start_date" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.start_date"
clearable
:placeholder="t('startDatePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('startDatePlaceholder')">
</el-date-picker>
</el-form-item>
<el-form-item :label="t('endDate')" prop="end_date">
<el-input
<el-form-item :label="t('endDate')" prop="end_date" class="input-width">
<el-date-picker
class="flex-1 !flex"
v-model="formData.end_date"
clearable
:placeholder="t('endDatePlaceholder')"
class="input-width"
/>
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('endDatePlaceholder')">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
@ -88,11 +71,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import {
addStudentCourses,
editStudentCourses,
getStudentCoursesInfo,
} from '@/app/api/student_courses'
import { addStudentCourses, editStudentCourses, getStudentCoursesInfo, getWithStudentList, getWithCourseList } from '@/app/api/student_courses'
let showDialog = ref(false)
const loading = ref(false)
@ -118,22 +97,34 @@ const formRules = computed(() => {
return {
student_id: [
{ required: true, message: t('studentIdPlaceholder'), trigger: 'blur' },
],
]
,
course_id: [
{ required: true, message: t('courseIdPlaceholder'), trigger: 'blur' },
],
]
,
total_hours: [
{ required: true, message: t('totalHoursPlaceholder'), trigger: 'blur' },
],
]
,
gift_hours: [
{ required: true, message: t('giftHoursPlaceholder'), trigger: 'blur' },
],
]
,
start_date: [
{ required: true, message: t('startDatePlaceholder'), trigger: 'blur' },
],
]
,
end_date: [
{ required: true, message: t('endDatePlaceholder'), trigger: 'blur' },
],
]
,
}
})
@ -153,13 +144,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData
save(data)
.then((res) => {
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
})
.catch((err) => {
}).catch(err => {
loading.value = false
})
}
@ -168,13 +157,24 @@ const confirm = async (formEl: FormInstance | undefined) => {
//
const studentIdList = ref([] as any[])
const setStudentIdList = async () => {
studentIdList.value = await (await getWithStudentList({})).data
}
setStudentIdList()
const courseIdList = ref([] as any[])
const setCourseIdList = async () => {
courseIdList.value = await (await getWithCourseList({})).data
}
setCourseIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getStudentCoursesInfo(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]
})
}
@ -192,12 +192,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
@ -224,7 +219,7 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({
showDialog,
setFormData,
setFormData
})
</script>

194
admin/src/app/views/student_courses/student_courses.vue

@ -1,6 +1,7 @@
<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">
@ -8,140 +9,68 @@
</el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap"
shadow="never"
>
<el-form
:inline="true"
:model="studentCoursesTable.searchParam"
ref="searchFormRef"
>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="studentCoursesTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('studentId')" prop="student_id">
<el-input
v-model="studentCoursesTable.searchParam.student_id"
:placeholder="t('studentIdPlaceholder')"
<el-select class="w-[280px]" v-model="studentCoursesTable.searchParam.student_id" clearable :placeholder="t('studentIdPlaceholder')">
<el-option
v-for="(item, index) in studentIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input
v-model="studentCoursesTable.searchParam.course_id"
:placeholder="t('courseIdPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('totalHours')" prop="total_hours">
<el-input
v-model="studentCoursesTable.searchParam.total_hours"
:placeholder="t('totalHoursPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('giftHours')" prop="gift_hours">
<el-input
v-model="studentCoursesTable.searchParam.gift_hours"
:placeholder="t('giftHoursPlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('startDate')" prop="start_date">
<el-input
v-model="studentCoursesTable.searchParam.start_date"
:placeholder="t('startDatePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('endDate')" prop="end_date">
<el-input
v-model="studentCoursesTable.searchParam.end_date"
:placeholder="t('endDatePlaceholder')"
<el-select class="w-[280px]" v-model="studentCoursesTable.searchParam.course_id" clearable :placeholder="t('courseIdPlaceholder')">
<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>
<el-button type="primary" @click="loadStudentCoursesList()">{{
t('search')
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
<el-button type="primary" @click="loadStudentCoursesList()">{{ 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="studentCoursesTable.data"
size="large"
v-loading="studentCoursesTable.loading"
>
<el-table :data="studentCoursesTable.data" size="large" v-loading="studentCoursesTable.loading">
<template #empty>
<span>{{
!studentCoursesTable.loading ? t('emptyData') : ''
}}</span>
<span>{{ !studentCoursesTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column
prop="student_id"
:label="t('studentId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="student_id_name" :label="t('studentId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="course_id"
:label="t('courseId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="course_id_name" :label="t('courseId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="total_hours"
:label="t('totalHours')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="total_hours" :label="t('totalHours')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="gift_hours"
:label="t('giftHours')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="gift_hours" :label="t('giftHours')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="start_date"
:label="t('startDate')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="start_date" :label="t('startDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
prop="end_date"
:label="t('endDate')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column prop="end_date" :label="t('endDate')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="studentCoursesTable.page"
v-model:page-size="studentCoursesTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="studentCoursesTable.total"
@size-change="loadStudentCoursesList()"
@current-change="loadStudentCoursesList"
/>
<el-pagination v-model:current-page="studentCoursesTable.page" v-model:page-size="studentCoursesTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="studentCoursesTable.total"
@size-change="loadStudentCoursesList()" @current-change="loadStudentCoursesList" />
</div>
</div>
@ -154,16 +83,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import {
getStudentCoursesList,
deleteStudentCourses,
} from '@/app/api/student_courses'
import { getStudentCoursesList, deleteStudentCourses, getWithStudentList, getWithCourseList } from '@/app/api/student_courses'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/student_courses/components/student-courses-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const pageName = route.meta.title;
let studentCoursesTable = reactive({
page: 1,
@ -172,13 +98,9 @@ let studentCoursesTable = reactive({
loading: true,
data: [],
searchParam:{
student_id: '',
course_id: '',
total_hours: '',
gift_hours: '',
start_date: '',
end_date: '',
},
"student_id":"",
"course_id":""
}
})
const searchFormRef = ref<FormInstance>()
@ -188,6 +110,7 @@ const selectData = ref<any[]>([])
//
/**
* 获取学员课程列表
*/
@ -198,14 +121,12 @@ const loadStudentCoursesList = (page: number = 1) => {
getStudentCoursesList({
page: studentCoursesTable.page,
limit: studentCoursesTable.limit,
...studentCoursesTable.searchParam,
})
.then((res) => {
...studentCoursesTable.searchParam
}).then(res => {
studentCoursesTable.loading = false
studentCoursesTable.data = res.data.data
studentCoursesTable.total = res.data.total
})
.catch(() => {
}).catch(() => {
studentCoursesTable.loading = false
})
}
@ -234,19 +155,32 @@ const editEvent = (data: any) => {
* 删除学员课程
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('studentCoursesDeleteTips'), t('warning'), {
ElMessageBox.confirm(t('studentCoursesDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}).then(() => {
deleteStudentCourses(id)
.then(() => {
}
).then(() => {
deleteStudentCourses(id).then(() => {
loadStudentCoursesList()
}).catch(() => {
})
.catch(() => {})
})
}
const studentIdList = ref([])
const setStudentIdList = async () => {
studentIdList.value = await (await getWithStudentList({})).data
}
setStudentIdList()
const courseIdList = ref([])
const setCourseIdList = async () => {
courseIdList.value = await (await getWithCourseList({})).data
}
setCourseIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()

259
admin/src/app/views/timetables/timetables.vue

@ -1,125 +1,198 @@
<template>
<el-card class="box-card !border-none" shadow="never">
<el-button @click="addDict">添加</el-button>
<div class="schedule-container">
<!-- 周视图日历 -->
<FullCalendar
:options="calendarOptions"
ref="fullCalendar"
class="calendar"
/>
<!-- 课程详情弹窗 -->
<el-dialog
v-model="dialogVisible"
title="课程人员安排"
width="30%"
:before-close="handleClose"
<!-- 周一到周日的布局 -->
<div v-for="(day, index) in days" :key="index" class="day-column">
<div class="day-header">{{ day.date }}</div>
<el-table
:data="day.timeSlots"
border
:span-method="(data) => objectSpanMethod(day.timeSlots, data)"
style="width: 100%"
@cell-click="handleCellClick"
>
<div v-if="selectedEvent">
<h3>{{ selectedEvent.title }}</h3>
<p>时间{{ selectedEvent.time }}</p>
<h4>参与人员</h4>
<ul>
<li v-for="person in selectedEvent.people" :key="person.id">
{{ person.name }} - {{ person.role }}
</li>
</ul>
<!-- 时间列 -->
<el-table-column
prop="timeRange"
label="时间"
width="80"
align="center"
>
<template #default="{ row }">
<div :style="{ backgroundColor: row.color }">
{{ row.timeRange }}
</div>
</template>
</el-table-column>
<!-- 教室列 -->
<el-table-column
v-for="(classroom, idx) in day.classrooms"
:key="idx"
:label="`教室${idx + 1}`"
:prop="`classroom${idx + 1}`"
align="center"
>
<template #default="{ row }">
<div v-if="row.course && row.course.classroom === classroom">
<div class="teacher-name">{{ row.course.teacher }}</div>
<div class="student-list">
<el-tag
v-for="student in row.course.students"
:key="student"
size="small"
effect="plain"
>
{{ student }}
</el-tag>
</div>
<div class="classroom-name">
剩余空位{{ row.course.hasnumber }}
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 详情弹窗 -->
<el-dialog v-model="dialogVisible" title="课程详情">
<p><strong>教师:</strong> {{ selectedCourse?.teacher }}</p>
<p><strong>学员:</strong> {{ selectedCourse?.students.join(', ') }}</p>
</el-dialog>
</div>
</el-card>
</template>
<script setup>
import { ref } from 'vue'
import FullCalendar from '@fullcalendar/vue3'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction' //
import zhLocale from '@fullcalendar/core/locales/zh-cn'
//
const courses = ref([
const days = [
//
{
date: '周一',
timeSlots: [
{
id: 1,
title: '数学课',
start: '2025-05-18 08:00:00',
end: '2025-05-18 09:00:00',
people: [
{ id: 1, name: '张老师', role: '主讲' },
{ id: 2, name: '李同学', role: '学生' },
timeRange: '9:00-10:00',
color: '#FFA07A',
course: {
teacher: '',
students: [],
classroom: '教室1',
hasnumber: 5,
},
},
// ...
],
classrooms: ['教室1'], //
},
{
id: 2,
title: '英语课',
start: '2025-05-18 10:00:00',
end: '2025-05-18 11:00:00',
people: [{ id: 3, name: '王老师', role: '主讲' }],
date: '周二',
timeSlots: [
{
timeRange: '9:00-10:00',
color: '#FFA07A',
course: {
teacher: '张老师',
students: ['小明', '小红'],
classroom: '教室1',
hasnumber: 5,
},
])
//
const dialogVisible = ref(false)
const selectedEvent = ref(null)
// FullCalendar
const calendarOptions = ref({
locale: zhLocale,
plugins: [
dayGridPlugin,
timeGridPlugin,
interactionPlugin, //
],
initialView: 'timeGridWeek', //
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'timeGridWeek,timeGridDay', //
},
events: courses.value,
eventClick: (info) => {
selectedEvent.value = {
title: info.event.title,
time: `${info.event.start.toLocaleTimeString()} - ${info.event.end.toLocaleTimeString()}`,
people: info.event.extendedProps.people,
}
dialogVisible.value = true
{
timeRange: '11:00-12:00',
color: '#712e13',
course: {
teacher: '张老师',
students: ['小明', '小红'],
classroom: '教室2',
hasnumber: 5,
},
eventContent: (arg) => {
//
return { html: `<div class="fc-event-title">${arg.event.title}</div>` }
},
allDaySlot: false, //
slotDuration: '01:00', // 1
slotLabelFormat: {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: false,
meridiem: 'short',
// ...
],
classrooms: ['教室1', '教室2'], //
},
})
]
const dialogVisible = ref(false)
const selectedCourse = ref(null)
//
const objectSpanMethod = (timeSlots, { row, column, rowIndex }) => {
if (column.property === 'timeRange') {
//
const current = timeSlots[rowIndex]
//
if (!current || !current.timeRange) return { rowspan: 0, colspan: 0 }
let spanCount = 1
//
while (timeSlots[rowIndex + spanCount]?.timeRange === current.timeRange) {
spanCount++
}
//
if (
spanCount > 1 &&
rowIndex > 0 &&
timeSlots[rowIndex - 1]?.timeRange === current.timeRange
) {
return { rowspan: 0, colspan: 0 }
}
return { rowspan: spanCount, colspan: 1 }
}
return { rowspan: 1, colspan: 1 }
}
//
const handleClose = () => {
dialogVisible.value = false
selectedEvent.value = null
//
const handleCellClick = (row, column, cell, event) => {
console.log(row, column, cell, event)
if (column.property.startsWith('classroom')) {
selectedCourse.value = row.course
dialogVisible.value = true
}
}
</script>
<style>
<style scoped>
.schedule-container {
padding: 20px;
display: flex;
gap: 10px;
}
.day-column {
flex: 1;
min-width: 200px;
}
.day-header {
text-align: center;
font-weight: bold;
padding: 8px;
background-color: #f0f0f0;
}
.teacher-name {
font-weight: bold;
margin-bottom: 5px;
}
.calendar {
margin-bottom: 20px;
.student-list {
margin-top: 5px;
}
.fc-event-title {
white-space: normal !important;
font-size: 14px;
.el-table__cell {
display: flex;
align-items: center;
}
.fc-timegrid-event {
cursor: pointer;
.classroom-name {
margin-bottom: 5px;
}
</style>

212
admin/src/app/views/xsyj/xsyj.vue

@ -0,0 +1,212 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never" v-loading="loading">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<el-button type="primary" @click="addStage">
新增阶段
</el-button>
</div>
</el-card>
<el-card class="box-card !border-none" shadow="never" >
<div class="flex items-center justify-between p-[10px] table-item-border bg">
<span class="text-base w-[230px]">阶段名称</span>
<span class="text-base w-[110px] text-center">底薪</span>
</div>
<el-collapse v-model="activeNames" accordion >
<el-collapse-item v-for="(stage, index) in stages" :key="stage.id" :name="stage.id">
<template #title>
<div class="collapse-title">
<span class="title-name">{{ stage.name }}</span>
<span class="arrow">{{ stage.price }} </span>
<!-- <span class="arrow">&gt;</span> -->
</div>
</template>
<el-form label-width="100px" style="margin-bottom: 10px">
<el-form-item label="阶段名称">
<el-input v-model="stage.name" placeholder="请输入阶段名称" />
</el-form-item>
</el-form>
<el-form label-width="100px" style="margin-bottom: 10px">
<el-form-item label="阶段底薪">
<el-input v-model="stage.price" placeholder="请输入阶段底薪" />
</el-form-item>
</el-form>
<el-button type="success" size="small" @click="addRule(stage)">新增规则</el-button>
<el-table :data="stage.rules" border style="margin-top: 10px">
<el-table-column prop="renewal_standard_min" label="续费上限">
<template #default="{ row }">
<el-input v-model="row.renewal_standard_min" placeholder="请输入续费上限" />
</template>
</el-table-column>
<el-table-column prop="renewal_standard_max" label="续费下限">
<template #default="{ row }">
<el-input v-model="row.renewal_standard_max" placeholder="请输入续费下限" />
</template>
</el-table-column>
<el-table-column prop="renewal_commission" label="续费提成">
<template #default="{ row }">
<el-input v-model="row.renewal_commission" placeholder="%" />
</template>
</el-table-column>
<el-table-column prop="new_count_min" label="新单成交数上限">
<template #default="{ row }">
<el-input v-model="row.new_count_min" />
</template>
</el-table-column>
<el-table-column prop="new_count_max" label="新单成交数下限">
<template #default="{ row }">
<el-input v-model="row.new_count_max" />
</template>
</el-table-column>
<el-table-column prop="new_move_5" label="新招(5+1)x3">
<template #default="{ row }">
<el-input v-model="row.new_move_5" />
</template>
</el-table-column>
<el-table-column prop="new_move_7" label="新招(7+1)x3">
<template #default="{ row }">
<el-input v-model="row.new_move_7" />
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{ $index }">
<el-button type="danger" size="small" @click="removeRule(stage, $index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-button type="danger" size="small" style="margin-top: 10px"
@click="removeStage(index)">删除该阶段</el-button>
</el-collapse-item>
</el-collapse>
<div style="text-align: right; margin-top: 20px;">
<el-button type="primary" @click="onSave">提交保存</el-button>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { xsyjConfig, getXsyjConfig } from '@/app/api/sys'
import { reactive, ref } from 'vue'
import {ElMessage} from 'element-plus'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const loading = ref(true)
const stages = ref([])
const activeNames = ref(null)
function addStage() {
const newStage = {
name: '默认阶段',
price:0,
rules: [{
renewal_standard_min: '',
renewal_standard_max: '',
renewal_commission: '',
new_count_min: '',
new_count_max: '',
new_move_5: '',
new_move_7: ''
}]
}
stages.value.push(newStage)
activeNames.value = newStage.name
}
function removeStage(index) {
stages.value.splice(index, 1)
}
function addRule(stage) {
stage.rules.push({
renewal_standard_min: '',
renewal_standard_max: '',
renewal_commission: '',
new_count_min: '',
new_count_max: '',
new_move_5: '',
new_move_7: ''
})
}
function removeRule(stage, ruleIndex) {
if (stage.rules.length === 1) {
ElMessage.warning('至少保留一条规则')
return
}
stage.rules.splice(ruleIndex, 1)
}
const setFormData = async () => {
const data = await (await getXsyjConfig()).data
stages.value = data
loading.value = false
}
setFormData();
const onSave = async () => {
xsyjConfig(stages.value)
.then(() => {
loading.value = true
setFormData()
})
.catch(() => {
loading.value = false
})
}
</script>
<style lang="scss" scoped>
.collapse-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
font-size: 14px;
font-weight: 500;
padding-right: 10px;
color: #333;
padding: 10px;
}
.title-name {
width: 230px;
}
.title-salary {
width: 110px;
text-align: center;
color: #7438D5;
}
.arrow {
margin-left: auto;
color: #999;
font-size: 14px;
}
</style>

35
niucloud/app/adminapi/controller/communication_records/CommunicationRecords.php

@ -28,17 +28,8 @@ class CommunicationRecords extends BaseAdminController
*/
public function lists(){
$data = $this->request->params([
["staff_id",""],
["resource_id",""],
["resource_type",""],
["communication_type",""],
["communication_result",""],
["communication_time",""],
["remarks",""],
["tag",""],
["business_id",""],
["created_at",""],
["updated_at",""]
["communication_type",""]
]);
return success((new CommunicationRecordsService())->getPage($data));
}
@ -58,21 +49,17 @@ class CommunicationRecords extends BaseAdminController
*/
public function add(){
$data = $this->request->params([
["staff_id",0],
["resource_id",0],
["resource_type",""],
["communication_type",""],
["communication_result",""],
["communication_time","2025-05-16 17:20:44"],
["communication_time","2025-05-19 13:11:39"],
["remarks",""],
["tag",""],
["business_id",0],
["created_at",1747387244],
["updated_at",1747387244]
]);
$this->validate($data, 'app\validate\communication_records\CommunicationRecords.add');
$id = (new CommunicationRecordsService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
return (new CommunicationRecordsService())->add($data);
}
/**
@ -82,21 +69,17 @@ class CommunicationRecords extends BaseAdminController
*/
public function edit(int $id){
$data = $this->request->params([
["staff_id",0],
["resource_id",0],
["resource_type",""],
["communication_type",""],
["communication_result",""],
["communication_time","2025-05-16 17:20:44"],
["communication_time","2025-05-19 13:11:39"],
["remarks",""],
["tag",""],
["business_id",0],
["created_at",1747387244],
["updated_at",1747387244]
]);
$this->validate($data, 'app\validate\communication_records\CommunicationRecords.edit');
(new CommunicationRecordsService())->edit($id, $data);
return success('EDIT_SUCCESS');
return (new CommunicationRecordsService())->edit($id, $data);
}
/**
@ -110,4 +93,8 @@ class CommunicationRecords extends BaseAdminController
}
public function getCustomerResourcesAll(){
return success(( new CommunicationRecordsService())->getCustomerResourcesAll());
}
}

1
niucloud/app/adminapi/controller/course/Course.php

@ -105,5 +105,4 @@ class Course extends BaseAdminController
return success('DELETE_SUCCESS');
}
}

22
niucloud/app/adminapi/controller/student_courses/StudentCourses.php

@ -29,11 +29,7 @@ class StudentCourses extends BaseAdminController
public function lists(){
$data = $this->request->params([
["student_id",""],
["course_id",""],
["total_hours",""],
["gift_hours",""],
["start_date",""],
["end_date",""]
["course_id",""]
]);
return success((new StudentCoursesService())->getPage($data));
}
@ -57,8 +53,8 @@ class StudentCourses extends BaseAdminController
["course_id",0],
["total_hours",0],
["gift_hours",0],
["start_date","2025-05-16 18:02:13"],
["end_date","2025-05-16 18:02:13"],
["start_date","2025-05-19 15:41:16"],
["end_date","2025-05-19 15:41:16"],
]);
$this->validate($data, 'app\validate\student_courses\StudentCourses.add');
@ -77,8 +73,8 @@ class StudentCourses extends BaseAdminController
["course_id",0],
["total_hours",0],
["gift_hours",0],
["start_date","2025-05-16 18:02:13"],
["end_date","2025-05-16 18:02:13"],
["start_date","2025-05-19 15:41:16"],
["end_date","2025-05-19 15:41:16"],
]);
$this->validate($data, 'app\validate\student_courses\StudentCourses.edit');
@ -97,4 +93,12 @@ class StudentCourses extends BaseAdminController
}
public function getStudentAll(){
return success(( new StudentCoursesService())->getStudentAll());
}
public function getCourseAll(){
return success(( new StudentCoursesService())->getCourseAll());
}
}

14
niucloud/app/adminapi/controller/sys/System.php

@ -124,4 +124,18 @@ class System extends BaseAdminController
}
public function xsyj_config(){
$data = $this->request->post();
return success(data: (new SystemService())->xsyj_config($data));
}
public function get_xsyj_config(){
return success(data: (new SystemService())->get_xsyj_config());
}
}

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

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- communication_records
Route::group('communication_records', function () {
@ -29,6 +30,8 @@ Route::group('communication_records', function () {
//删除沟通记录
Route::delete('communication_records/:id', 'communication_records.CommunicationRecords/del');
Route::get('customer_resources_all','communication_records.CommunicationRecords/getCustomerResourcesAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

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

@ -14,6 +14,8 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- student_courses
Route::group('student_courses', function () {
@ -29,6 +31,10 @@ Route::group('student_courses', function () {
//删除学员课程
Route::delete('student_courses/:id', 'student_courses.StudentCourses/del');
Route::get('student_all','student_courses.StudentCourses/getStudentAll');
Route::get('course_all','student_courses.StudentCourses/getCourseAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

5
niucloud/app/adminapi/route/sys.php

@ -330,6 +330,11 @@ Route::group('sys', function() {
Route::get('get_yjpz_config', 'sys.System/get_yjpz_config');
Route::post('yjpz_config', 'sys.System/yjpz_config');
//销售业绩配置
Route::post('xsyj_config', 'sys.System/xsyj_config');
Route::get('get_xsyj_config', 'sys.System/get_xsyj_config');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,

126
niucloud/app/model/communication_records/CommunicationRecords.php

@ -16,6 +16,8 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\customer_resources\CustomerResources;
/**
* 沟通记录模型
* Class CommunicationRecords
@ -43,31 +45,7 @@ class CommunicationRecords 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 searchStaffIdAttr($query, $value, $data)
{
if ($value) {
$query->where("staff_id", $value);
}
}
/**
* 搜索器:沟通记录资源ID
* 搜索器:沟通记录资源
* @param $value
* @param $data
*/
@ -79,19 +57,7 @@ class CommunicationRecords extends BaseModel
}
/**
* 搜索器:沟通记录资源类型(如设备、文件、系统等)
* @param $value
* @param $data
*/
public function searchResourceTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("resource_type", $value);
}
}
/**
* 搜索器:沟通记录沟通类型: phone-电话, email-邮件, meeting-会议, other-其他
* 搜索器:沟通记录沟通类型
* @param $value
* @param $data
*/
@ -102,93 +68,13 @@ class CommunicationRecords extends BaseModel
}
}
/**
* 搜索器:沟通记录沟通结果: success-成功, failure-失败, pending-待定
* @param $value
* @param $data
*/
public function searchCommunicationResultAttr($query, $value, $data)
{
if ($value) {
$query->where("communication_result", $value);
}
}
/**
* 搜索器:沟通记录沟通时间
* @param $value
* @param $data
*/
public function searchCommunicationTimeAttr($query, $value, $data)
{
if ($value) {
$query->where("communication_time", $value);
}
}
/**
* 搜索器:沟通记录备注
* @param $value
* @param $data
*/
public function searchRemarksAttr($query, $value, $data)
{
if ($value) {
$query->where("remarks", $value);
}
}
/**
* 搜索器:沟通记录标签: high-高, medium-中, low-低
* @param $value
* @param $data
*/
public function searchTagAttr($query, $value, $data)
{
if ($value) {
$query->where("tag", $value);
}
}
/**
* 搜索器:沟通记录关联的业务ID
* @param $value
* @param $data
*/
public function searchBusinessIdAttr($query, $value, $data)
{
if ($value) {
$query->where("business_id", $value);
}
}
/**
* 搜索器:沟通记录创建时间
* @param $value
* @param $data
*/
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("created_at", $value);
}
}
/**
* 搜索器:沟通记录修改时间
* @param $value
* @param $data
*/
public function searchUpdatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("updated_at", $value);
}
public function customerResources(){
return $this->hasOne(CustomerResources::class, 'id', 'resource_id')->joinType('left')->withField('name,id')->bind(['resource_id_name'=>'name']);
}
}

116
niucloud/app/model/course/Course.php

@ -9,7 +9,7 @@
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\campus;
namespace app\model\course;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
@ -17,11 +17,11 @@ use think\model\relation\HasMany;
use think\model\relation\HasOne;
/**
* 校区模型
* Class Campus
* @package app\model\campus
* 课程模型
* Class Course
* @package app\model\course
*/
class Campus extends BaseModel
class Course extends BaseModel
{
use SoftDelete;
@ -36,13 +36,13 @@ class Campus extends BaseModel
* 模型名称
* @var string
*/
protected $name = 'campus';
protected $name = 'course';
/**
* 定义软删除标记字段.
* @var string
*/
protected $deleteTime = 'delete_time';
protected $deleteTime = 'deleted_at';
/**
* 定义软删除字段的默认值.
@ -51,38 +51,122 @@ class Campus extends BaseModel
protected $defaultSoftDelete = 0;
/**
* 搜索器:校区校区名称
* 搜索器:课程课程编号
* @param $value
* @param $data
*/
public function searchCampusNameAttr($query, $value, $data)
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_name", "like", "%".$value."%");
$query->where("id", $value);
}
}
/**
* 搜索器:校区校区地址
* 搜索器:课程课程名称
* @param $value
* @param $data
*/
public function searchCampusAddressAttr($query, $value, $data)
public function searchCourseNameAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_address", $value);
$query->where("course_name", $value);
}
}
/**
* 搜索器:校区校区状态
* 搜索器:课程课程类型
* @param $value
* @param $data
*/
public function searchCampusStatusAttr($query, $value, $data)
public function searchCourseTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_status", $value);
$query->where("course_type", $value);
}
}
/**
* 搜索器:课程课程时长
* @param $value
* @param $data
*/
public function searchDurationAttr($query, $value, $data)
{
if ($value) {
$query->where("duration", $value);
}
}
/**
* 搜索器:课程课时数量
* @param $value
* @param $data
*/
public function searchSessionCountAttr($query, $value, $data)
{
if ($value) {
$query->where("session_count", $value);
}
}
/**
* 搜索器:课程单次逍客数量
* @param $value
* @param $data
*/
public function searchSingleSessionCountAttr($query, $value, $data)
{
if ($value) {
$query->where("single_session_count", $value);
}
}
/**
* 搜索器:课程课程价格
* @param $value
* @param $data
*/
public function searchPriceAttr($query, $value, $data)
{
if ($value) {
$query->where("price", $value);
}
}
/**
* 搜索器:课程内部提醒课时
* @param $value
* @param $data
*/
public function searchInternalReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("internal_reminder", $value);
}
}
/**
* 搜索器:课程客户提醒课时
* @param $value
* @param $data
*/
public function searchCustomerReminderAttr($query, $value, $data)
{
if ($value) {
$query->where("customer_reminder", $value);
}
}
/**
* 搜索器:课程课程备注
* @param $value
* @param $data
*/
public function searchRemarksAttr($query, $value, $data)
{
if ($value) {
$query->where("remarks", $value);
}
}

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

@ -0,0 +1,55 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\student;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
class Student extends BaseModel
{
use SoftDelete;
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'student';
/**
* 定义软删除标记字段
* @var string
*/
protected $deleteTime = 'deleted_at';
/**
* 定义软删除字段的默认值
* @var int
*/
protected $defaultSoftDelete = 0;
}

72
niucloud/app/model/student_courses/StudentCourses.php

@ -16,6 +16,10 @@ use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\student\Student;
use app\model\course\Course;
/**
* 学员课程模型
* Class StudentCourses
@ -43,19 +47,7 @@ class StudentCourses extends BaseModel
/**
* 搜索器:学员课程记录编号
* @param $value
* @param $data
*/
public function searchIdAttr($query, $value, $data)
{
if ($value) {
$query->where("id", $value);
}
}
/**
* 搜索器:学员课程学员ID
* 搜索器:学员课程学员
* @param $value
* @param $data
*/
@ -67,7 +59,7 @@ class StudentCourses extends BaseModel
}
/**
* 搜索器:学员课程课程ID
* 搜索器:学员课程课程
* @param $value
* @param $data
*/
@ -78,57 +70,17 @@ class StudentCourses extends BaseModel
}
}
/**
* 搜索器:学员课程总正式课时数
* @param $value
* @param $data
*/
public function searchTotalHoursAttr($query, $value, $data)
{
if ($value) {
$query->where("total_hours", $value);
}
}
/**
* 搜索器:学员课程赠送课时数
* @param $value
* @param $data
*/
public function searchGiftHoursAttr($query, $value, $data)
{
if ($value) {
$query->where("gift_hours", $value);
}
}
/**
* 搜索器:学员课程课程开始日期
* @param $value
* @param $data
*/
public function searchStartDateAttr($query, $value, $data)
{
if ($value) {
$query->where("start_date", $value);
}
}
/**
* 搜索器:学员课程课程结束日期
* @param $value
* @param $data
*/
public function searchEndDateAttr($query, $value, $data)
{
if ($value) {
$query->where("end_date", $value);
}
}
public function student(){
return $this->hasOne(Student::class, 'id', 'student_id')->joinType('left')->withField('name,id')->bind(['student_id_name'=>'name']);
}
public function course(){
return $this->hasOne(Course::class, 'id', 'course_id')->joinType('left')->withField('course_name,id')->bind(['course_id_name'=>'course_name']);
}
}

27
niucloud/app/service/admin/communication_records/CommunicationRecordsService.php

@ -12,7 +12,9 @@
namespace app\service\admin\communication_records;
use app\model\communication_records\CommunicationRecords;
use app\model\customer_resources\CustomerResources;
use app\model\personnel\Personnel;
use core\base\BaseAdminService;
@ -39,7 +41,7 @@ class CommunicationRecordsService extends BaseAdminService
$field = 'id,staff_id,resource_id,resource_type,communication_type,communication_result,communication_time,remarks,tag,business_id,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["id","staff_id","resource_id","resource_type","communication_type","communication_result","communication_time","remarks","tag","business_id","created_at","updated_at"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["resource_id","communication_type"], $where)->with(['customerResources'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
@ -53,7 +55,7 @@ class CommunicationRecordsService extends BaseAdminService
{
$field = 'id,staff_id,resource_id,resource_type,communication_type,communication_result,communication_time,remarks,tag,business_id,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;
}
@ -64,8 +66,15 @@ class CommunicationRecordsService extends BaseAdminService
*/
public function add(array $data)
{
$personnel = new Personnel();
$data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['staff_id']){
return fail("操作失败");
}
$res = $this->model->create($data);
return $res->id;
return success("操作成功");
}
@ -77,9 +86,14 @@ class CommunicationRecordsService extends BaseAdminService
*/
public function edit(int $id, array $data)
{
$personnel = new Personnel();
$data['staff_id'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['staff_id']){
return fail("操作失败");
}
$this->model->where([['id', '=', $id]])->update($data);
return true;
return success("操作成功");
}
/**
@ -95,5 +109,10 @@ class CommunicationRecordsService extends BaseAdminService
}
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
}

45
niucloud/app/service/admin/student_courses/StudentCoursesService.php

@ -9,57 +9,58 @@
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\campus;
namespace app\service\admin\student_courses;
use app\model\campus\Campus;
use app\model\student_courses\StudentCourses;
use app\model\student\Student;
use app\model\course\Course;
use core\base\BaseAdminService;
/**
* 校区服务层
* Class CampusService
* @package app\service\admin\campus
* 学员课程服务层
* Class StudentCoursesService
* @package app\service\admin\student_courses
*/
class StudentCoursesService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new Campus();
$this->model = new StudentCourses();
}
/**
* 获取校区列表
* 获取学员课程列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,campus_name,campus_address,campus_preview_image,campus_coordinates,campus_introduction,campus_status,create_time,update_time,delete_time';
$order = '';
$field = 'id,student_id,course_id,total_hours,gift_hours,start_date,end_date,created_at,updated_at';
$order = 'id desc';
$search_model = $this->model->withSearch(["campus_name","campus_address","campus_status"], $where)->field($field)->order($order);
$search_model = $this->model->withSearch(["student_id","course_id"], $where)->with(['student','course'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取校区信息
* 获取学员课程信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,campus_name,campus_address,campus_preview_image,campus_coordinates,campus_introduction,campus_status,create_time,update_time,delete_time';
$field = 'id,student_id,course_id,total_hours,gift_hours,start_date,end_date,created_at,updated_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info['campus_status'] = strval($info['campus_status']);
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['student','course'])->findOrEmpty()->toArray();
return $info;
}
/**
* 添加校区
* 添加学员课程
* @param array $data
* @return mixed
*/
@ -71,7 +72,7 @@ class StudentCoursesService extends BaseAdminService
}
/**
* 校区编辑
* 学员课程编辑
* @param int $id
* @param array $data
* @return bool
@ -84,7 +85,7 @@ class StudentCoursesService extends BaseAdminService
}
/**
* 删除校区
* 删除学员课程
* @param int $id
* @return bool
*/
@ -96,5 +97,15 @@ class StudentCoursesService extends BaseAdminService
}
public function getStudentAll(){
$studentModel = new Student();
return $studentModel->select()->toArray();
}
public function getCourseAll(){
$courseModel = new Course();
return $courseModel->select()->toArray();
}
}

20
niucloud/app/service/admin/sys/SystemService.php

@ -188,4 +188,24 @@ class SystemService extends BaseAdminService
return true;
}
public function xsyj_config(array $data){
$config = new SysConfig();
$config->where(['config_key' => 'XSYJ'])->update([
'value' => json_encode($data)
]);
return true;
}
public function get_xsyj_config(){
$config = new SysConfig();
$data = $config->where(['config_key' => 'XSYJ'])->value("value");
return $data;
}
}

6
niucloud/app/validate/communication_records/CommunicationRecords.php

@ -20,7 +20,6 @@ class CommunicationRecords extends BaseValidate
{
protected $rule = [
'staff_id' => 'require',
'resource_id' => 'require',
'resource_type' => 'require',
'communication_type' => 'require',
@ -29,7 +28,6 @@ class CommunicationRecords extends BaseValidate
];
protected $message = [
'staff_id.require' => ['common_validate.require', ['staff_id']],
'resource_id.require' => ['common_validate.require', ['resource_id']],
'resource_type.require' => ['common_validate.require', ['resource_type']],
'communication_type.require' => ['common_validate.require', ['communication_type']],
@ -38,8 +36,8 @@ class CommunicationRecords extends BaseValidate
];
protected $scene = [
"add" => ['staff_id', 'resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag', 'business_id', 'created_at', 'updated_at'],
"edit" => ['staff_id', 'resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag', 'business_id', 'created_at', 'updated_at']
"add" => ['resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag'],
"edit" => ['resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag']
];
}

Loading…
Cancel
Save