Browse Source

1

yuhongzhe
于宏哲PHP 11 months ago
parent
commit
fedcd1f4cd
  1. 2
      admin/components.d.ts
  2. 26
      admin/src/app/api/communication_records.ts
  3. 29
      admin/src/app/api/student_courses.ts
  4. 11
      admin/src/app/api/sys.ts
  5. 48
      admin/src/app/lang/zh-cn/communication_records.communication_records.json
  6. 36
      admin/src/app/lang/zh-cn/student_courses.student_courses.json
  7. 4
      admin/src/app/views/campus_person_role/campus_person_role.vue
  8. 464
      admin/src/app/views/communication_records/communication_records.vue
  9. 440
      admin/src/app/views/communication_records/components/communication-records-edit.vue
  10. 329
      admin/src/app/views/student_courses/components/student-courses-edit.vue
  11. 350
      admin/src/app/views/student_courses/student_courses.vue
  12. 212
      admin/src/app/views/xsyj/xsyj.vue
  13. 35
      niucloud/app/adminapi/controller/communication_records/CommunicationRecords.php
  14. 22
      niucloud/app/adminapi/controller/student_courses/StudentCourses.php
  15. 14
      niucloud/app/adminapi/controller/sys/System.php
  16. 3
      niucloud/app/adminapi/route/communication_records.php
  17. 6
      niucloud/app/adminapi/route/student_courses.php
  18. 5
      niucloud/app/adminapi/route/sys.php
  19. 126
      niucloud/app/model/communication_records/CommunicationRecords.php
  20. 8
      niucloud/app/model/course/Course.php
  21. 55
      niucloud/app/model/student/Student.php
  22. 72
      niucloud/app/model/student_courses/StudentCourses.php
  23. 27
      niucloud/app/service/admin/communication_records/CommunicationRecordsService.php
  24. 45
      niucloud/app/service/admin/student_courses/StudentCoursesService.php
  25. 20
      niucloud/app/service/admin/sys/SystemService.php
  26. 6
      niucloud/app/validate/communication_records/CommunicationRecords.php

2
admin/components.d.ts

@ -19,6 +19,8 @@ declare module '@vue/runtime-core' {
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']
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']

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

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

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

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

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

@ -732,3 +732,14 @@ export function getYjpzConfig() {
export function yjpzConfig(params: Record<string, any>) { export function yjpzConfig(params: Record<string, any>) {
return request.post(`sys/yjpz_config`, params) 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')
}

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

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

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

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

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

@ -184,7 +184,9 @@ import Edit from '@/app/views/campus_person_role/components/campus-person-role-e
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title
// ?dept_id=1
const dept_id = pageName == '市场人员列表' ? 1 : 2;
let campusPersonRoleTable = reactive({ let campusPersonRoleTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
@ -195,7 +197,7 @@ let campusPersonRoleTable = reactive({
campus_id: '', campus_id: '',
person_id: '', person_id: '',
role_id: '', role_id: '',
dept_id: '', dept_id: dept_id,
}, },
}) })

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

@ -1,268 +1,127 @@
<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('addCommunicationRecords') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addCommunicationRecords') }}
</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="communicationRecordsTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('resourceId')" prop="resource_id">
:inline="true" <el-select class="w-[280px]" v-model="communicationRecordsTable.searchParam.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
:model="communicationRecordsTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in resourceIdList"
> :key="index"
<el-form-item :label="t('staffId')" prop="staff_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="communicationRecordsTable.searchParam.staff_id" />
:placeholder="t('staffIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('resourceId')" prop="resource_id">
<el-input <el-form-item :label="t('communicationType')" prop="communication_type">
v-model="communicationRecordsTable.searchParam.resource_id" <el-select class="w-[280px]" v-model="communicationRecordsTable.searchParam.communication_type" clearable :placeholder="t('communicationTypePlaceholder')">
:placeholder="t('resourceIdPlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in communication_typeList"
<el-form-item :label="t('resourceType')" prop="resource_type"> :key="index"
<el-input :label="item.name"
v-model="communicationRecordsTable.searchParam.resource_type" :value="item.value"
:placeholder="t('resourceTypePlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item
:label="t('communicationType')" <el-form-item>
prop="communication_type" <el-button type="primary" @click="loadCommunicationRecordsList()">{{ t('search') }}</el-button>
> <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
<el-input </el-form-item>
v-model="communicationRecordsTable.searchParam.communication_type" </el-form>
:placeholder="t('communicationTypePlaceholder')" </el-card>
/>
</el-form-item> <div class="mt-[10px]">
<el-form-item <el-table :data="communicationRecordsTable.data" size="large" v-loading="communicationRecordsTable.loading">
:label="t('communicationResult')" <template #empty>
prop="communication_result" <span>{{ !communicationRecordsTable.loading ? t('emptyData') : '' }}</span>
> </template>
<el-input <el-table-column prop="resource_id_name" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
v-model="
communicationRecordsTable.searchParam.communication_result <el-table-column prop="resource_type" :label="t('resourceType')" min-width="120" :show-overflow-tooltip="true"/>
"
:placeholder="t('communicationResultPlaceholder')" <el-table-column :label="t('communicationType')" min-width="180" align="center" :show-overflow-tooltip="true">
/> <template #default="{ row }">
</el-form-item> <div v-for="(item, index) in communication_typeList">
<el-form-item <div v-if="item.value == row.communication_type">{{ item.name }}</div>
:label="t('communicationTime')" </div>
prop="communication_time" </template>
> </el-table-column>
<el-input
v-model="communicationRecordsTable.searchParam.communication_time" <el-table-column :label="t('communicationResult')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('communicationTimePlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in communication_resultList">
</el-form-item> <div v-if="item.value == row.communication_result">{{ item.name }}</div>
<el-form-item :label="t('remarks')" prop="remarks"> </div>
<el-input </template>
v-model="communicationRecordsTable.searchParam.remarks" </el-table-column>
:placeholder="t('remarksPlaceholder')"
/> <el-table-column prop="communication_time" :label="t('communicationTime')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-form-item :label="t('tag')" prop="tag"> <el-table-column prop="remarks" :label="t('remarks')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="communicationRecordsTable.searchParam.tag" <el-table-column :label="t('tag')" min-width="180" align="center" :show-overflow-tooltip="true">
:placeholder="t('tagPlaceholder')" <template #default="{ row }">
/> <div v-for="(item, index) in tagList">
</el-form-item> <div v-if="item.value == row.tag">{{ item.name }}</div>
<el-form-item :label="t('businessId')" prop="business_id"> </div>
<el-input </template>
v-model="communicationRecordsTable.searchParam.business_id" </el-table-column>
:placeholder="t('businessIdPlaceholder')"
/> <el-table-column :label="t('operation')" fixed="right" min-width="120">
</el-form-item> <template #default="{ row }">
<el-form-item :label="t('createdAt')" prop="created_at"> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-input <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
v-model="communicationRecordsTable.searchParam.created_at" </template>
:placeholder="t('createdAtPlaceholder')" </el-table-column>
/>
</el-form-item> </el-table>
<el-form-item :label="t('updatedAt')" prop="updated_at"> <div class="mt-[16px] flex justify-end">
<el-input <el-pagination v-model:current-page="communicationRecordsTable.page" v-model:page-size="communicationRecordsTable.limit"
v-model="communicationRecordsTable.searchParam.updated_at" layout="total, sizes, prev, pager, next, jumper" :total="communicationRecordsTable.total"
:placeholder="t('updatedAtPlaceholder')" @size-change="loadCommunicationRecordsList()" @current-change="loadCommunicationRecordsList" />
/> </div>
</el-form-item> </div>
<el-form-item> <edit ref="editCommunicationRecordsDialog" @complete="loadCommunicationRecordsList" />
<el-button type="primary" @click="loadCommunicationRecordsList()">{{ </el-card>
t('search') </div>
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table
:data="communicationRecordsTable.data"
size="large"
v-loading="communicationRecordsTable.loading"
>
<template #empty>
<span>{{
!communicationRecordsTable.loading ? t('emptyData') : ''
}}</span>
</template>
<el-table-column
prop="staff_id"
:label="t('staffId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="resource_id"
:label="t('resourceId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="resource_type"
:label="t('resourceType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication_type"
:label="t('communicationType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication_result"
:label="t('communicationResult')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="communication_time"
:label="t('communicationTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="remarks"
:label="t('remarks')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="tag"
:label="t('tag')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="business_id"
:label="t('businessId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="created_at"
:label="t('createdAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="updated_at"
:label="t('updatedAt')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="communicationRecordsTable.page"
v-model:page-size="communicationRecordsTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="communicationRecordsTable.total"
@size-change="loadCommunicationRecordsList()"
@current-change="loadCommunicationRecordsList"
/>
</div>
</div>
<edit
ref="editCommunicationRecordsDialog"
@complete="loadCommunicationRecordsList"
/>
</el-card>
</div>
</template> </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 { getCommunicationRecordsList, deleteCommunicationRecords, getWithCustomerResourcesList } from '@/app/api/communication_records'
getCommunicationRecordsList,
deleteCommunicationRecords,
} from '@/app/api/communication_records'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/communication_records/components/communication-records-edit.vue' import Edit from '@/app/views/communication_records/components/communication-records-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let communicationRecordsTable = reactive({ let communicationRecordsTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
staff_id: '', "resource_id":"",
resource_id: '', "communication_type":""
resource_type: '', }
communication_type: '',
communication_result: '',
communication_time: '',
remarks: '',
tag: '',
business_id: '',
created_at: '',
updated_at: '',
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -271,26 +130,39 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) 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();
/** /**
* 获取沟通记录列表 * 获取沟通记录列表
*/ */
const loadCommunicationRecordsList = (page: number = 1) => { const loadCommunicationRecordsList = (page: number = 1) => {
communicationRecordsTable.loading = true communicationRecordsTable.loading = true
communicationRecordsTable.page = page communicationRecordsTable.page = page
getCommunicationRecordsList({ getCommunicationRecordsList({
page: communicationRecordsTable.page, page: communicationRecordsTable.page,
limit: communicationRecordsTable.limit, limit: communicationRecordsTable.limit,
...communicationRecordsTable.searchParam, ...communicationRecordsTable.searchParam
}) }).then(res => {
.then((res) => { communicationRecordsTable.loading = false
communicationRecordsTable.loading = false communicationRecordsTable.data = res.data.data
communicationRecordsTable.data = res.data.data communicationRecordsTable.total = res.data.total
communicationRecordsTable.total = res.data.total }).catch(() => {
}) communicationRecordsTable.loading = false
.catch(() => {
communicationRecordsTable.loading = false
}) })
} }
loadCommunicationRecordsList() loadCommunicationRecordsList()
@ -301,8 +173,8 @@ const editCommunicationRecordsDialog: Record<string, any> | null = ref(null)
* 添加沟通记录 * 添加沟通记录
*/ */
const addEvent = () => { const addEvent = () => {
editCommunicationRecordsDialog.value.setFormData() editCommunicationRecordsDialog.value.setFormData()
editCommunicationRecordsDialog.value.showDialog = true editCommunicationRecordsDialog.value.showDialog = true
} }
/** /**
@ -310,42 +182,50 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editCommunicationRecordsDialog.value.setFormData(data) editCommunicationRecordsDialog.value.setFormData(data)
editCommunicationRecordsDialog.value.showDialog = true editCommunicationRecordsDialog.value.showDialog = true
} }
/** /**
* 删除沟通记录 * 删除沟通记录
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('communicationRecordsDeleteTips'), t('warning'), { ElMessageBox.confirm(t('communicationRecordsDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteCommunicationRecords(id) }
.then(() => { ).then(() => {
loadCommunicationRecordsList() deleteCommunicationRecords(id).then(() => {
}) loadCommunicationRecordsList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const resourceIdList = ref([])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadCommunicationRecordsList() loadCommunicationRecordsList()
} }
</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>

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

@ -1,138 +1,82 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateCommunicationRecords') : t('addCommunicationRecords')" 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=" <el-form-item :label="t('resourceId')" prop="resource_id">
formData.id <el-select class="input-width" v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
? t('updateCommunicationRecords') <el-option label="请选择" value=""></el-option>
: t('addCommunicationRecords') <el-option
" v-for="(item, index) in resourceIdList"
width="50%" :key="index"
class="diy-dialog-wrap" :label="item['name']"
:destroy-on-close="true" :value="item['id']"
> />
<el-form </el-select>
:model="formData" </el-form-item>
label-width="120px"
ref="formRef" <el-form-item :label="t('resourceType')" prop="resource_type">
:rules="formRules" <el-input v-model="formData.resource_type" clearable :placeholder="t('resourceTypePlaceholder')" class="input-width" />
class="page-form" </el-form-item>
v-loading="loading"
> <el-form-item :label="t('communicationType')" prop="communication_type">
<el-form-item :label="t('staffId')" prop="staff_id"> <el-select class="input-width" v-model="formData.communication_type" clearable :placeholder="t('communicationTypePlaceholder')">
<el-input <el-option label="请选择" value=""></el-option>
v-model="formData.staff_id" <el-option
clearable v-for="(item, index) in communication_typeList"
:placeholder="t('staffIdPlaceholder')" :key="index"
class="input-width" :label="item.name"
/> :value="item.value"
</el-form-item> />
</el-select>
<el-form-item :label="t('resourceId')" prop="resource_id"> </el-form-item>
<el-input
v-model="formData.resource_id" <el-form-item :label="t('communicationResult')" prop="communication_result">
clearable <el-select class="input-width" v-model="formData.communication_result" clearable :placeholder="t('communicationResultPlaceholder')">
:placeholder="t('resourceIdPlaceholder')" <el-option label="请选择" value=""></el-option>
class="input-width" <el-option
/> v-for="(item, index) in communication_resultList"
</el-form-item> :key="index"
:label="item.name"
<el-form-item :label="t('resourceType')" prop="resource_type"> :value="item.value"
<el-input />
v-model="formData.resource_type" </el-select>
clearable </el-form-item>
:placeholder="t('resourceTypePlaceholder')"
class="input-width" <el-form-item :label="t('communicationTime')" prop="communication_time" class="input-width">
/> <el-date-picker
</el-form-item> class="flex-1 !flex"
v-model="formData.communication_time"
<el-form-item :label="t('communicationType')" prop="communication_type"> clearable
<el-input type="datetime"
v-model="formData.communication_type" value-format="YYYY-MM-DD HH:mm:ss"
clearable :placeholder="t('communicationTimePlaceholder')">
:placeholder="t('communicationTypePlaceholder')" </el-date-picker>
class="input-width" </el-form-item>
/> <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 <el-form-item :label="t('tag')" >
:label="t('communicationResult')" <el-select class="input-width" v-model="formData.tag" clearable :placeholder="t('tagPlaceholder')">
prop="communication_result" <el-option label="请选择" value=""></el-option>
> <el-option
<el-input v-for="(item, index) in tagList"
v-model="formData.communication_result" :key="index"
clearable :label="item.name"
:placeholder="t('communicationResultPlaceholder')" :value="item.value"
class="input-width" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('communicationTime')" prop="communication_time"> </el-form>
<el-input
v-model="formData.communication_time" <template #footer>
clearable <span class="dialog-footer">
:placeholder="t('communicationTimePlaceholder')" <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
class="input-width" <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
/> t('confirm')
</el-form-item> }}</el-button>
</span>
<el-form-item :label="t('remarks')"> </template>
<el-input </el-dialog>
v-model="formData.remarks"
clearable
:placeholder="t('remarksPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('tag')">
<el-input
v-model="formData.tag"
clearable
:placeholder="t('tagPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('businessId')">
<el-input
v-model="formData.business_id"
clearable
:placeholder="t('businessIdPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('createdAt')">
<el-input
v-model="formData.created_at"
clearable
:placeholder="t('createdAtPlaceholder')"
class="input-width"
/>
</el-form-item>
<el-form-item :label="t('updatedAt')">
<el-input
v-model="formData.updated_at"
clearable
:placeholder="t('updatedAtPlaceholder')"
class="input-width"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -140,11 +84,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 { import { addCommunicationRecords, editCommunicationRecords, getCommunicationRecordsInfo, getWithCustomerResourcesList } from '@/app/api/communication_records'
addCommunicationRecords,
editCommunicationRecords,
getCommunicationRecordsInfo,
} from '@/app/api/communication_records'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -153,18 +93,14 @@ const loading = ref(false)
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
staff_id: '', resource_id: '',
resource_id: '', resource_type: '',
resource_type: '', communication_type: '',
communication_type: '', communication_result: '',
communication_result: '', communication_time: '',
communication_time: '', remarks: '',
remarks: '', tag: '',
tag: '',
business_id: '',
created_at: '',
updated_at: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -172,55 +108,43 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
staff_id: [
{ required: true, message: t('staffIdPlaceholder'), trigger: 'blur' },
],
resource_id: [ resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
],
]
,
resource_type: [ resource_type: [
{ { required: true, message: t('resourceTypePlaceholder'), trigger: 'blur' },
required: true,
message: t('resourceTypePlaceholder'), ]
trigger: 'blur', ,
},
],
communication_type: [ communication_type: [
{ { required: true, message: t('communicationTypePlaceholder'), trigger: 'blur' },
required: true,
message: t('communicationTypePlaceholder'), ]
trigger: 'blur', ,
},
],
communication_result: [ communication_result: [
{ { required: true, message: t('communicationResultPlaceholder'), trigger: 'blur' },
required: true,
message: t('communicationResultPlaceholder'), ]
trigger: 'blur', ,
},
],
communication_time: [ communication_time: [
{ { required: true, message: t('communicationTimePlaceholder'), trigger: 'blur' },
required: true,
message: t('communicationTimePlaceholder'), ]
trigger: 'blur', ,
},
],
remarks: [ remarks: [
{ required: true, message: t('remarksPlaceholder'), trigger: 'blur' }, { required: true, message: t('remarksPlaceholder'), trigger: 'blur' },
],
tag: [{ required: true, message: t('tagPlaceholder'), trigger: 'blur' }], ]
business_id: [ ,
{ required: true, message: t('businessIdPlaceholder'), trigger: 'blur' }, tag: [
], { required: true, message: t('tagPlaceholder'), trigger: 'blur' },
created_at: [
{ required: true, message: t('createdAtPlaceholder'), trigger: 'blur' }, ]
], ,
updated_at: [ }
{ required: true, message: t('updatedAtPlaceholder'), trigger: 'blur' },
],
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -230,93 +154,109 @@ 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 ? editCommunicationRecords : addCommunicationRecords let save = formData.id ? editCommunicationRecords : addCommunicationRecords
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 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) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if (row) { if(row){
const data = await (await getCommunicationRecordsInfo(row.id)).data const data = await (await getCommunicationRecordsInfo(row.id)).data
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] })
}) }
} 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>

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

@ -1,86 +1,69 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateStudentCourses') : t('addStudentCourses')" 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('updateStudentCourses') : t('addStudentCourses')" <el-form-item :label="t('studentId')" prop="student_id">
width="50%" <el-select class="input-width" v-model="formData.student_id" clearable :placeholder="t('studentIdPlaceholder')">
class="diy-dialog-wrap" <el-option label="请选择" value=""></el-option>
:destroy-on-close="true" <el-option
> v-for="(item, index) in studentIdList"
<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('courseId')" prop="course_id">
<el-form-item :label="t('studentId')" prop="student_id"> <el-select class="input-width" v-model="formData.course_id" clearable :placeholder="t('courseIdPlaceholder')">
<el-input <el-option label="请选择" value=""></el-option>
v-model="formData.student_id" <el-option
clearable v-for="(item, index) in courseIdList"
:placeholder="t('studentIdPlaceholder')" :key="index"
class="input-width" :label="item['course_name']"
/> :value="item['id']"
</el-form-item> />
</el-select>
<el-form-item :label="t('courseId')" prop="course_id"> </el-form-item>
<el-input
v-model="formData.course_id" <el-form-item :label="t('totalHours')" prop="total_hours">
clearable <el-input v-model="formData.total_hours" clearable :placeholder="t('totalHoursPlaceholder')" class="input-width" />
:placeholder="t('courseIdPlaceholder')" </el-form-item>
class="input-width"
/> <el-form-item :label="t('giftHours')" >
</el-form-item> <el-input v-model="formData.gift_hours" clearable :placeholder="t('giftHoursPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('totalHours')" prop="total_hours">
<el-input <el-form-item :label="t('startDate')" prop="start_date" class="input-width">
v-model="formData.total_hours" <el-date-picker
clearable class="flex-1 !flex"
:placeholder="t('totalHoursPlaceholder')" v-model="formData.start_date"
class="input-width" clearable
/> type="datetime"
</el-form-item> value-format="YYYY-MM-DD HH:mm:ss"
:placeholder="t('startDatePlaceholder')">
<el-form-item :label="t('giftHours')"> </el-date-picker>
<el-input </el-form-item>
v-model="formData.gift_hours" <el-form-item :label="t('endDate')" prop="end_date" class="input-width">
clearable <el-date-picker
:placeholder="t('giftHoursPlaceholder')" class="flex-1 !flex"
class="input-width" v-model="formData.end_date"
/> clearable
</el-form-item> type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
<el-form-item :label="t('startDate')" prop="start_date"> :placeholder="t('endDatePlaceholder')">
<el-input </el-date-picker>
v-model="formData.start_date" </el-form-item>
clearable </el-form>
:placeholder="t('startDatePlaceholder')"
class="input-width" <template #footer>
/> <span class="dialog-footer">
</el-form-item> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
<el-form-item :label="t('endDate')" prop="end_date"> t('confirm')
<el-input }}</el-button>
v-model="formData.end_date" </span>
clearable </template>
:placeholder="t('endDatePlaceholder')" </el-dialog>
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> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -88,11 +71,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 { import { addStudentCourses, editStudentCourses, getStudentCoursesInfo, getWithStudentList, getWithCourseList } from '@/app/api/student_courses'
addStudentCourses,
editStudentCourses,
getStudentCoursesInfo,
} from '@/app/api/student_courses'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -101,13 +80,13 @@ const loading = ref(false)
* 表单数据 * 表单数据
*/ */
const initialFormData = { const initialFormData = {
id: '', id: '',
student_id: '', student_id: '',
course_id: '', course_id: '',
total_hours: '', total_hours: '',
gift_hours: '', gift_hours: '',
start_date: '', start_date: '',
end_date: '', end_date: '',
} }
const formData: Record<string, any> = reactive({ ...initialFormData }) const formData: Record<string, any> = reactive({ ...initialFormData })
@ -115,26 +94,38 @@ const formRef = ref<FormInstance>()
// //
const formRules = computed(() => { const formRules = computed(() => {
return { return {
student_id: [ student_id: [
{ required: true, message: t('studentIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('studentIdPlaceholder'), trigger: 'blur' },
],
]
,
course_id: [ course_id: [
{ required: true, message: t('courseIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('courseIdPlaceholder'), trigger: 'blur' },
],
]
,
total_hours: [ total_hours: [
{ required: true, message: t('totalHoursPlaceholder'), trigger: 'blur' }, { required: true, message: t('totalHoursPlaceholder'), trigger: 'blur' },
],
]
,
gift_hours: [ gift_hours: [
{ required: true, message: t('giftHoursPlaceholder'), trigger: 'blur' }, { required: true, message: t('giftHoursPlaceholder'), trigger: 'blur' },
],
]
,
start_date: [ start_date: [
{ required: true, message: t('startDatePlaceholder'), trigger: 'blur' }, { required: true, message: t('startDatePlaceholder'), trigger: 'blur' },
],
]
,
end_date: [ end_date: [
{ required: true, message: t('endDatePlaceholder'), trigger: 'blur' }, { required: true, message: t('endDatePlaceholder'), trigger: 'blur' },
],
} ]
,
}
}) })
const emit = defineEmits(['complete']) const emit = defineEmits(['complete'])
@ -144,93 +135,97 @@ 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 ? editStudentCourses : addStudentCourses let save = formData.id ? editStudentCourses : addStudentCourses
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 }
}) })
}
})
} }
// //
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) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if (row) { if(row){
const data = await (await getStudentCoursesInfo(row.id)).data const data = await (await getStudentCoursesInfo(row.id)).data
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] })
}) }
} 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>

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

@ -1,184 +1,106 @@
<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('addStudentCourses') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addStudentCourses') }}
</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="studentCoursesTable.searchParam" ref="searchFormRef">
>
<el-form <el-form-item :label="t('studentId')" prop="student_id">
:inline="true" <el-select class="w-[280px]" v-model="studentCoursesTable.searchParam.student_id" clearable :placeholder="t('studentIdPlaceholder')">
:model="studentCoursesTable.searchParam" <el-option
ref="searchFormRef" v-for="(item, index) in studentIdList"
> :key="index"
<el-form-item :label="t('studentId')" prop="student_id"> :label="item['name']"
<el-input :value="item['id']"
v-model="studentCoursesTable.searchParam.student_id" />
:placeholder="t('studentIdPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('courseId')" prop="course_id">
<el-input <el-form-item :label="t('courseId')" prop="course_id">
v-model="studentCoursesTable.searchParam.course_id" <el-select class="w-[280px]" v-model="studentCoursesTable.searchParam.course_id" clearable :placeholder="t('courseIdPlaceholder')">
:placeholder="t('courseIdPlaceholder')" <el-option
/> v-for="(item, index) in courseIdList"
</el-form-item> :key="index"
<el-form-item :label="t('totalHours')" prop="total_hours"> :label="item['course_name']"
<el-input :value="item['id']"
v-model="studentCoursesTable.searchParam.total_hours" />
:placeholder="t('totalHoursPlaceholder')" </el-select>
/> </el-form-item>
</el-form-item>
<el-form-item :label="t('giftHours')" prop="gift_hours"> <el-form-item>
<el-input <el-button type="primary" @click="loadStudentCoursesList()">{{ t('search') }}</el-button>
v-model="studentCoursesTable.searchParam.gift_hours" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
:placeholder="t('giftHoursPlaceholder')" </el-form-item>
/> </el-form>
</el-form-item> </el-card>
<el-form-item :label="t('startDate')" prop="start_date">
<el-input <div class="mt-[10px]">
v-model="studentCoursesTable.searchParam.start_date" <el-table :data="studentCoursesTable.data" size="large" v-loading="studentCoursesTable.loading">
:placeholder="t('startDatePlaceholder')" <template #empty>
/> <span>{{ !studentCoursesTable.loading ? t('emptyData') : '' }}</span>
</el-form-item> </template>
<el-form-item :label="t('endDate')" prop="end_date"> <el-table-column prop="student_id_name" :label="t('studentId')" min-width="120" :show-overflow-tooltip="true"/>
<el-input
v-model="studentCoursesTable.searchParam.end_date" <el-table-column prop="course_id_name" :label="t('courseId')" min-width="120" :show-overflow-tooltip="true"/>
:placeholder="t('endDatePlaceholder')"
/> <el-table-column prop="total_hours" :label="t('totalHours')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-table-column prop="gift_hours" :label="t('giftHours')" min-width="120" :show-overflow-tooltip="true"/>
<el-form-item>
<el-button type="primary" @click="loadStudentCoursesList()">{{ <el-table-column prop="start_date" :label="t('startDate')" min-width="120" :show-overflow-tooltip="true"/>
t('search')
}}</el-button> <el-table-column prop="end_date" :label="t('endDate')" 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="studentCoursesTable.data" <div class="mt-[16px] flex justify-end">
size="large" <el-pagination v-model:current-page="studentCoursesTable.page" v-model:page-size="studentCoursesTable.limit"
v-loading="studentCoursesTable.loading" layout="total, sizes, prev, pager, next, jumper" :total="studentCoursesTable.total"
> @size-change="loadStudentCoursesList()" @current-change="loadStudentCoursesList" />
<template #empty> </div>
<span>{{ </div>
!studentCoursesTable.loading ? t('emptyData') : ''
}}</span> <edit ref="editStudentCoursesDialog" @complete="loadStudentCoursesList" />
</template> </el-card>
<el-table-column </div>
prop="student_id"
: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="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="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
: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="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>
<edit ref="editStudentCoursesDialog" @complete="loadStudentCoursesList" />
</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 { getStudentCoursesList, deleteStudentCourses, getWithStudentList, getWithCourseList } from '@/app/api/student_courses'
getStudentCoursesList,
deleteStudentCourses,
} from '@/app/api/student_courses'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox, FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/student_courses/components/student-courses-edit.vue' import Edit from '@/app/views/student_courses/components/student-courses-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let studentCoursesTable = reactive({ let studentCoursesTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
student_id: '', "student_id":"",
course_id: '', "course_id":""
total_hours: '', }
gift_hours: '',
start_date: '',
end_date: '',
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -188,25 +110,24 @@ const selectData = ref<any[]>([])
// //
/** /**
* 获取学员课程列表 * 获取学员课程列表
*/ */
const loadStudentCoursesList = (page: number = 1) => { const loadStudentCoursesList = (page: number = 1) => {
studentCoursesTable.loading = true studentCoursesTable.loading = true
studentCoursesTable.page = page studentCoursesTable.page = page
getStudentCoursesList({ getStudentCoursesList({
page: studentCoursesTable.page, page: studentCoursesTable.page,
limit: studentCoursesTable.limit, limit: studentCoursesTable.limit,
...studentCoursesTable.searchParam, ...studentCoursesTable.searchParam
}) }).then(res => {
.then((res) => { studentCoursesTable.loading = false
studentCoursesTable.loading = false studentCoursesTable.data = res.data.data
studentCoursesTable.data = res.data.data studentCoursesTable.total = res.data.total
studentCoursesTable.total = res.data.total }).catch(() => {
}) studentCoursesTable.loading = false
.catch(() => {
studentCoursesTable.loading = false
}) })
} }
loadStudentCoursesList() loadStudentCoursesList()
@ -217,8 +138,8 @@ const editStudentCoursesDialog: Record<string, any> | null = ref(null)
* 添加学员课程 * 添加学员课程
*/ */
const addEvent = () => { const addEvent = () => {
editStudentCoursesDialog.value.setFormData() editStudentCoursesDialog.value.setFormData()
editStudentCoursesDialog.value.showDialog = true editStudentCoursesDialog.value.showDialog = true
} }
/** /**
@ -226,42 +147,55 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editStudentCoursesDialog.value.setFormData(data) editStudentCoursesDialog.value.setFormData(data)
editStudentCoursesDialog.value.showDialog = true editStudentCoursesDialog.value.showDialog = true
} }
/** /**
* 删除学员课程 * 删除学员课程
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('studentCoursesDeleteTips'), t('warning'), { ElMessageBox.confirm(t('studentCoursesDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteStudentCourses(id) }
.then(() => { ).then(() => {
loadStudentCoursesList() 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) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadStudentCoursesList() loadStudentCoursesList()
} }
</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>

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

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

@ -29,11 +29,7 @@ class StudentCourses extends BaseAdminController
public function lists(){ public function lists(){
$data = $this->request->params([ $data = $this->request->params([
["student_id",""], ["student_id",""],
["course_id",""], ["course_id",""]
["total_hours",""],
["gift_hours",""],
["start_date",""],
["end_date",""]
]); ]);
return success((new StudentCoursesService())->getPage($data)); return success((new StudentCoursesService())->getPage($data));
} }
@ -57,8 +53,8 @@ class StudentCourses extends BaseAdminController
["course_id",0], ["course_id",0],
["total_hours",0], ["total_hours",0],
["gift_hours",0], ["gift_hours",0],
["start_date","2025-05-16 18:02:13"], ["start_date","2025-05-19 15:41:16"],
["end_date","2025-05-16 18:02:13"], ["end_date","2025-05-19 15:41:16"],
]); ]);
$this->validate($data, 'app\validate\student_courses\StudentCourses.add'); $this->validate($data, 'app\validate\student_courses\StudentCourses.add');
@ -77,8 +73,8 @@ class StudentCourses extends BaseAdminController
["course_id",0], ["course_id",0],
["total_hours",0], ["total_hours",0],
["gift_hours",0], ["gift_hours",0],
["start_date","2025-05-16 18:02:13"], ["start_date","2025-05-19 15:41:16"],
["end_date","2025-05-16 18:02:13"], ["end_date","2025-05-19 15:41:16"],
]); ]);
$this->validate($data, 'app\validate\student_courses\StudentCourses.edit'); $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\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- communication_records // USER_CODE_BEGIN -- communication_records
Route::group('communication_records', function () { Route::group('communication_records', function () {
@ -29,6 +30,8 @@ Route::group('communication_records', function () {
//删除沟通记录 //删除沟通记录
Route::delete('communication_records/:id', 'communication_records.CommunicationRecords/del'); Route::delete('communication_records/:id', 'communication_records.CommunicationRecords/del');
Route::get('customer_resources_all','communication_records.CommunicationRecords/getCustomerResourcesAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::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\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- student_courses // USER_CODE_BEGIN -- student_courses
Route::group('student_courses', function () { Route::group('student_courses', function () {
@ -29,6 +31,10 @@ Route::group('student_courses', function () {
//删除学员课程 //删除学员课程
Route::delete('student_courses/:id', 'student_courses.StudentCourses/del'); 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([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::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::get('get_yjpz_config', 'sys.System/get_yjpz_config');
Route::post('yjpz_config', 'sys.System/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([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::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\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\customer_resources\CustomerResources;
/** /**
* 沟通记录模型 * 沟通记录模型
* Class CommunicationRecords * 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 $value
* @param $data * @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 $value
* @param $data * @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);
}
}
/** public function customerResources(){
* 搜索器:沟通记录修改时间 return $this->hasOne(CustomerResources::class, 'id', 'resource_id')->joinType('left')->withField('name,id')->bind(['resource_id_name'=>'name']);
* @param $value
* @param $data
*/
public function searchUpdatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("updated_at", $value);
}
} }
} }

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

@ -9,7 +9,7 @@
// | Author: Niucloud Team // | Author: Niucloud Team
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\model\campus; namespace app\model\course;
use core\base\BaseModel; use core\base\BaseModel;
use think\model\concern\SoftDelete; use think\model\concern\SoftDelete;
@ -21,7 +21,7 @@ use think\model\relation\HasOne;
* Class Campus * Class Campus
* @package app\model\campus * @package app\model\campus
*/ */
class Campus extends BaseModel class Course extends BaseModel
{ {
use SoftDelete; use SoftDelete;
@ -36,13 +36,13 @@ class Campus extends BaseModel
* 模型名称 * 模型名称
* @var string * @var string
*/ */
protected $name = 'campus'; protected $name = 'course';
/** /**
* 定义软删除标记字段. * 定义软删除标记字段.
* @var string * @var string
*/ */
protected $deleteTime = 'delete_time'; protected $deleteTime = 'deleted_at';
/** /**
* 定义软删除字段的默认值. * 定义软删除字段的默认值.

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\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\student\Student;
use app\model\course\Course;
/** /**
* 学员课程模型 * 学员课程模型
* Class StudentCourses * 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 $value
* @param $data * @param $data
*/ */
@ -67,7 +59,7 @@ class StudentCourses extends BaseModel
} }
/** /**
* 搜索器:学员课程课程ID * 搜索器:学员课程课程
* @param $value * @param $value
* @param $data * @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; namespace app\service\admin\communication_records;
use app\model\communication_records\CommunicationRecords; use app\model\communication_records\CommunicationRecords;
use app\model\customer_resources\CustomerResources;
use app\model\personnel\Personnel;
use core\base\BaseAdminService; 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'; $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'; $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); $list = $this->pageQuery($search_model);
return $list; 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'; $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; return $info;
} }
@ -64,8 +66,15 @@ class CommunicationRecordsService extends BaseAdminService
*/ */
public function add(array $data) 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); $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) 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); $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 // | 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; use core\base\BaseAdminService;
/** /**
* 校区服务层 * 学员课程服务层
* Class CampusService * Class StudentCoursesService
* @package app\service\admin\campus * @package app\service\admin\student_courses
*/ */
class StudentCoursesService extends BaseAdminService class StudentCoursesService extends BaseAdminService
{ {
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$this->model = new Campus(); $this->model = new StudentCourses();
} }
/** /**
* 获取校区列表 * 获取学员课程列表
* @param array $where * @param array $where
* @return array * @return array
*/ */
public function getPage(array $where = []) 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'; $field = 'id,student_id,course_id,total_hours,gift_hours,start_date,end_date,created_at,updated_at';
$order = ''; $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); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
/** /**
* 获取校区信息 * 获取学员课程信息
* @param int $id * @param int $id
* @return array * @return array
*/ */
public function getInfo(int $id) 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 = $this->model->field($field)->where([['id', "=", $id]])->with(['student','course'])->findOrEmpty()->toArray();
$info['campus_status'] = strval($info['campus_status']);
return $info; return $info;
} }
/** /**
* 添加校区 * 添加学员课程
* @param array $data * @param array $data
* @return mixed * @return mixed
*/ */
@ -71,7 +72,7 @@ class StudentCoursesService extends BaseAdminService
} }
/** /**
* 校区编辑 * 学员课程编辑
* @param int $id * @param int $id
* @param array $data * @param array $data
* @return bool * @return bool
@ -84,7 +85,7 @@ class StudentCoursesService extends BaseAdminService
} }
/** /**
* 删除校区 * 删除学员课程
* @param int $id * @param int $id
* @return bool * @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; 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 = [ protected $rule = [
'staff_id' => 'require',
'resource_id' => 'require', 'resource_id' => 'require',
'resource_type' => 'require', 'resource_type' => 'require',
'communication_type' => 'require', 'communication_type' => 'require',
@ -29,7 +28,6 @@ class CommunicationRecords extends BaseValidate
]; ];
protected $message = [ protected $message = [
'staff_id.require' => ['common_validate.require', ['staff_id']],
'resource_id.require' => ['common_validate.require', ['resource_id']], 'resource_id.require' => ['common_validate.require', ['resource_id']],
'resource_type.require' => ['common_validate.require', ['resource_type']], 'resource_type.require' => ['common_validate.require', ['resource_type']],
'communication_type.require' => ['common_validate.require', ['communication_type']], 'communication_type.require' => ['common_validate.require', ['communication_type']],
@ -38,8 +36,8 @@ class CommunicationRecords extends BaseValidate
]; ];
protected $scene = [ protected $scene = [
"add" => ['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" => ['staff_id', 'resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag', 'business_id', 'created_at', 'updated_at'] "edit" => ['resource_id', 'resource_type', 'communication_type', 'communication_result', 'communication_time', 'remarks', 'tag']
]; ];
} }

Loading…
Cancel
Save