于宏哲PHP 6 months ago
parent
commit
15b1f5674b
  1. 24
      niucloud/app/api/controller/apiController/CustomerResources.php
  2. 1
      niucloud/app/api/controller/member/Member.php
  3. 32
      niucloud/app/api/controller/student/StudentController.php
  4. 2
      niucloud/app/api/route/member.php
  5. 4
      niucloud/app/api/route/student.php
  6. 4
      niucloud/app/listener/personnel/Student.php
  7. 2
      niucloud/app/service/admin/customer_resources/CustomerResourcesService.php
  8. 13
      niucloud/app/service/admin/person_course_schedule/PersonCourseScheduleService.php
  9. 4
      niucloud/app/service/admin/physical_test/PhysicalTestService.php
  10. 36
      niucloud/app/service/api/apiService/PersonnelService.php
  11. 66
      niucloud/app/service/api/student/StudentService.php
  12. 6
      uniapp/api/member.js
  13. 34
      uniapp/pages-coach/coach/my/teaching_management_info.vue
  14. 16
      uniapp/pages-market/clue/add_clues.vue
  15. 1
      uniapp/pages-market/clue/class_arrangement_detail.vue
  16. 550
      uniapp/pages-market/clue/clue_info.vue
  17. 10
      uniapp/pages-market/clue/edit_clues.vue
  18. 26
      uniapp/pages-market/clue/index.vue
  19. 1
      uniapp/pages-student/schedule/index.vue

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

@ -66,15 +66,15 @@ class CustomerResources extends BaseApiService
$date = date('Y-m-d');
$param = $request->param();
$promised_visit_time = $request->param('promised_visit_time', '');
if ($promised_visit_time) {
$promised_visit_time = date('Y-m-d H:i:s', strtotime($promised_visit_time));
}
// if ($promised_visit_time) {
// $promised_visit_time = date('Y-m-d H:i:s', strtotime($promised_visit_time));
// }
$optional_class_time = $request->param('optional_class_time', '');
if ($optional_class_time) {
$optional_class_time = date('Y-m-d H:i:s', strtotime($optional_class_time));
}
// if ($optional_class_time) {
// $optional_class_time = date('Y-m-d H:i:s', strtotime($optional_class_time));
// }
$personnel = new Personnel();
$role_id = $personnel->alias("a")
->join(['school_campus_person_role' => 'b'], 'a.id = b.person_id', 'left')
@ -157,15 +157,15 @@ class CustomerResources extends BaseApiService
$customer_resources_id = $request->param('id', '');//客户资源表id
$promised_visit_time = $request->param('promised_visit_time', '');
if ($promised_visit_time) {
$promised_visit_time = date('Y-m-d H:i:s', strtotime($promised_visit_time));
}
// if ($promised_visit_time) {
// $promised_visit_time = date('Y-m-d H:i:s', strtotime($promised_visit_time));
// }
$optional_class_time = $request->param('optional_class_time', '');
if ($optional_class_time) {
$optional_class_time = date('Y-m-d H:i:s', strtotime($optional_class_time));
}
// if ($optional_class_time) {
// $optional_class_time = date('Y-m-d H:i:s', strtotime($optional_class_time));
// }
if (empty($customer_resources_id)) {

1
niucloud/app/api/controller/member/Member.php

@ -212,4 +212,5 @@ class Member extends BaseApiController
public function get_classes_list(){
return success(( new MemberService() )->get_classes_list());
}
}

32
niucloud/app/api/controller/student/StudentController.php

@ -9,6 +9,8 @@
namespace app\api\controller\student;
use app\Request;
use app\service\api\apiService\PersonnelService;
use app\service\api\parent\ParentService;
use app\service\api\student\StudentService;
use core\base\BaseController;
@ -342,4 +344,34 @@ class StudentController extends BaseController
return fail($e->getMessage());
}
}
public function is_pass(Request $request){
//获取员工信息
$old_password = $request->param('password','');
if(empty($old_password)){
return fail('请输入旧密码');
}
$res = (new StudentService())->checkMemberOldPwd($old_password);
if(!$res['code']){
return fail('旧密码不正确');
}
return success($res['data']);
}
public function set_pass(Request $request){
$new_password = $request->param('old_password','');
$password = $request->param('password','');
if($new_password != $password){
return fail('二次密码输入不正确');
}
$res = (new StudentService())->updatePassword($new_password);
if(!$res['code']){
return fail('旧密码不正确');
}
return success($res['data']);
}
}

2
niucloud/app/api/route/member.php

@ -131,6 +131,8 @@ Route::group('member', function () {
//员工工资详情
Route::get('salary/info/:id', 'member.Salary/info');
})->middleware(ApiChannel::class)
->middleware(ApiPersonnelCheckToken::class, true)
->middleware(ApiLog::class);

4
niucloud/app/api/route/student.php

@ -35,6 +35,10 @@ Route::group('student', function () {
Route::get('contract/download', 'student.StudentContract/downloadContract');
Route::get('contract/download-file', 'student.StudentContract/downloadFile');
Route::get('student-info', 'student.StudentContract/getStudentInfo');
Route::post('is_pass', 'app\api\controller\student\StudentController@is_pass');
Route::post('set_pass', 'app\api\controller\student\StudentController@set_pass');
})->middleware(['ApiCheckToken']);
// 体测数据管理

4
niucloud/app/listener/personnel/Student.php

@ -49,13 +49,17 @@ class Student
$studentCourses = new StudentCourses();
$student_course_usage = new StudentCourseUsage();
$schedule_info = $courseSchedule->where(['id' => $data['schedule_id']])->find();
$studentCourses_info = $studentCourses->where(['student_id' => $data['student_id'], 'course_id' => $schedule_info['course_id']])->find();
if($studentCourses_info){
$student_course_usage->insert([
'student_course_id' => $studentCourses_info['id'],
'used_hours' => $studentCourses_info['single_session_count'],
'usage_date' => date("Y-m-d")
]);
}
}

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

@ -232,7 +232,7 @@ class CustomerResourcesService extends BaseAdminService
$personnel = new Personnel();
$data['consultant'] = $personnel->where(['sys_user_id' => $this->uid])->value("id");
if(!$data['consultant']){
return fail("操作失败");
return fail("超级管理员不允许修改资源");
}
if ($this->model->where([

13
niucloud/app/service/admin/person_course_schedule/PersonCourseScheduleService.php

@ -236,4 +236,17 @@ class PersonCourseScheduleService extends BaseAdminService
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
public function xk(int $id)
{
$data = $this->model->where([['id', '=', $id]])->find()->toArray();
event('Student', [
'event_type' => 'xiaoke',
'data' => $data
]);
return true;
}
}

4
niucloud/app/service/admin/physical_test/PhysicalTestService.php

@ -39,7 +39,7 @@ class PhysicalTestService extends BaseAdminService
*/
public function getPage(array $where = [])
{
$field = 'id,resource_id,student_id,height,weight,coach_id,created_at,updated_at,seated_forward_bend,sit_ups,push_ups,flamingo_balance,thirty_sec_jump,standing_long_jump,agility_run,balance_beam,tennis_throw,ten_meter_shuttle_run,physical_test_report';
$field = '*';
$order = 'id desc';
$search_model = $this->model->withSearch(["resource_id","student_id"], $where)->with(['customerResources','student','personnel'])->field($field)->order($order);
@ -55,7 +55,7 @@ class PhysicalTestService extends BaseAdminService
*/
public function getInfo(int $id)
{
$field = 'id,resource_id,student_id,height,weight,coach_id,created_at,updated_at,seated_forward_bend,sit_ups,push_ups,flamingo_balance,thirty_sec_jump,standing_long_jump,agility_run,balance_beam,tennis_throw,ten_meter_shuttle_run,physical_test_report';
$field = '*';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['customerResources','student','personnel'])->findOrEmpty()->toArray();
return $info;

36
niucloud/app/service/api/apiService/PersonnelService.php

@ -12,6 +12,7 @@
namespace app\service\api\apiService;
use app\model\campus_person_role\CampusPersonRole;
use app\model\customer_resources\CustomerResources;
use app\model\departments\Departments;
use app\model\member\Member;
use app\model\personnel\Personnel;
@ -263,6 +264,9 @@ class PersonnelService extends BaseApiService
return $res;
}
//设置新密码
public function edidPassword($phone, $new_password, $key_value)
{
@ -922,22 +926,22 @@ class PersonnelService extends BaseApiService
$where = [];
// 查询销售部门(dept_id=3)下的所有角色ID
// $salesRoleIds = SysRole::where('dept_id', 3)
// ->where('status', 1)
// ->column('role_id');
//
// if (empty($salesRoleIds)) {
// return [
// 'code' => 1,
// 'msg' => '暂无销售部门角色',
// 'data' => []
// ];
// }
//
// // 构建校区人员角色关系查询条件
// $campusPersonWhere = [
// ['role_id', 'in', $salesRoleIds]
// ];
$salesRoleIds = SysRole::where('dept_id', 3)
->where('status', 1)
->column('role_id');
if (empty($salesRoleIds)) {
return [
'code' => 1,
'msg' => '暂无销售部门角色',
'data' => []
];
}
// 构建校区人员角色关系查询条件
$campusPersonWhere = [
['role_id', 'in', $salesRoleIds]
];
// 根据传入的校区进行筛选
if (!empty($campus)) {

66
niucloud/app/service/api/student/StudentService.php

@ -9,6 +9,8 @@ use app\model\customer_resources\CustomerResources;
use app\model\student\Student;
use app\model\member\Member;
use app\model\student_label\StudentLabel;
use app\model\sys\SysUser;
use think\facade\Cache;
use think\facade\Db;
use core\base\BaseService;
use core\exception\CommonException;
@ -805,4 +807,68 @@ class StudentService extends BaseService
'cancelled_courses' => $cancelledCourses
];
}
public function checkMemberOldPwd(string $old_passowrd)
{
$res = [
'code' => 0,
'msg' => '操作失败',
'data' => []
];
$customerResources = new CustomerResources();
$personnel_id = $this->getUserId();
$member = new Member();
$phone = $customerResources->where('id', $personnel_id)->value('phone_number');
$password = $customerResources->where('id', $personnel_id)->value('password');
if (!check_password($old_passowrd, $password)) {
$res['msg'] = '旧密码错误';
return $res;
}
$res['code'] = 1;
$res['msg'] = '密码正确';
$res['data'] = [
'key_value' => $this->setEditPasswordKey($phone)
];
return $res;
}
public function updatePassword($new_password){
$customerResources = new CustomerResources();
$personnel_id = $this->getUserId();
$update = $customerResources->where('id', $personnel_id)->update([
'password' => create_password($new_password)
]);
if (!$update) {
$res = [
'code' => 0,
'msg' => '操作失败',
'data' => []
];
} else {
$res = [
'code' => 1,
'msg' => '操作成功',
'data' => []
];
}
return $res;
}
public function setEditPasswordKey(string $phone)
{
$key_name = 'edit_password_' . $phone;
//生成字符串,存入cache中
//check_password()//验证
//create_password()//创建
$key_value = create_password($key_name);
// 缓存在3600秒之后过期
Cache::set($key_name, $key_value, 3600);
return $key_value;
}
}

6
uniapp/api/member.js

@ -149,4 +149,10 @@ export default {
async getSalaryInfo(data = {}) {
return await http.get(`/member/salary/info/${data.id}`);
},
async is_pass(data = {}) {
return await http.post('/student/is_pass', data)
},
async set_pass(data = {}) {
return await http.post('/student/set_pass', data)
},
}

34
uniapp/pages-coach/coach/my/teaching_management_info.vue

@ -191,8 +191,9 @@ export default {
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
// URL
return 'http://localhost:20080' + (url.startsWith('/') ? url : '/' + url);
return 'https://api.hnhbty.cn' + (url.startsWith('/') ? url : '/' + url);
},
//
@ -204,22 +205,38 @@ export default {
},
//
downloadFile(url) {
downloadFile(url) {
uni.showLoading({
title: '下载中...'
});
//
// #ifdef H5
// H5
const link = document.createElement('a');
link.href = url;
link.download = this.getFileName(url); //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
uni.hideLoading();
uni.showToast({
title: '开始下载',
icon: 'success'
});
// #endif
// #ifndef H5
// / App uni.downloadFile
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
//
const extension = this.getFileExtension(url);
const fileName = this.getFileName(url);
//
if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(extension.toLowerCase())) {
//
//
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
@ -237,7 +254,7 @@ export default {
}
});
} else {
//
//
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true,
@ -271,7 +288,8 @@ export default {
uni.hideLoading();
}
});
},
// #endif
},
//
getFileName(url) {

16
uniapp/pages-market/clue/add_clues.vue

@ -390,12 +390,24 @@
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="填写承诺到访时间"
v-model="formData.promised_visit_time"
backgroundColor="#434544"
size="26"
color="#fff"
></fui-input>
<!-- <view
class="input-title"
style="margin-right:14rpx;"
@click="openDateTime(`promised_visit_time`)">
{{ (formData.promised_visit_time) ? formData.promised_visit_time : '点击选择' }}
</view>
</view> -->
</view>
</fui-form-item>
<!--距离-->

1
uniapp/pages-market/clue/class_arrangement_detail.vue

@ -486,6 +486,7 @@
return;
}
console.log(this.selectedStudent);
// 2.
if (!this.selectedStudent.name || !this.selectedStudent.phone) {
uni.showToast({

550
uniapp/pages-market/clue/clue_info.vue

@ -4,20 +4,12 @@
<!-- 主要内容区域 -->
<view class="content">
<!-- 客户信息卡片 -->
<ClientInfoCard
:client-info="clientInfo"
:actions="[]"
@call="handleMakeCall"
@message="handleSendMessage"
/>
<ClientInfoCard :client-info="clientInfo" :actions="[]" @call="handleMakeCall"
@message="handleSendMessage" />
<!-- 标签切换器 -->
<view class="tab-switcher-container">
<TabSwitcher
:tabs="tabs"
:active-tab-id="switch_tags_type"
@tab-change="handleTabChange"
/>
<TabSwitcher :tabs="tabs" :active-tab-id="switch_tags_type" @tab-change="handleTabChange" />
</view>
<!-- 学生信息卡片区域 -->
@ -32,22 +24,14 @@
<!-- 学生信息滑动卡片 -->
<view class="student-cards">
<swiper
class="student-swiper"
:indicator-dots="studentList.length > 1"
:circular="studentList.length > 1"
indicator-color="rgba(255, 255, 255, 0.3)"
indicator-active-color="#29D3B4"
previous-margin="20"
next-margin="20"
<swiper class="student-swiper" :indicator-dots="studentList.length > 1"
:circular="studentList.length > 1" indicator-color="rgba(255, 255, 255, 0.3)"
indicator-active-color="#29D3B4" previous-margin="20" next-margin="20"
@change="onStudentSwiperChange">
<swiper-item v-for="(student, index) in studentList" :key="student.id">
<view class="student-swiper-content">
<StudentInfoCard
:student="student"
:show-details="true"
@action="handleStudentAction"
/>
<StudentInfoCard :student="student" :show-details="true"
@action="handleStudentAction" />
</view>
</swiper-item>
</swiper>
@ -55,12 +39,8 @@
<!-- 操作按钮区域 - 移到Swiper外部独立滑动 -->
<view class="action-buttons-section" v-if="currentStudent">
<view
class="action-item"
v-for="action in actionButtons"
:key="action.key"
@click.stop="handleStudentActionClick(action, currentStudent)"
>
<view class="action-item" v-for="action in actionButtons" :key="action.key"
@click.stop="handleStudentActionClick(action, currentStudent)">
<view class="action-icon">
<text>{{ action.icon }}</text>
</view>
@ -80,11 +60,8 @@
<!-- 课程信息标签内容 -->
<view class="course-section" v-if="switch_tags_type == 2">
<CourseInfoCard
v-if="courseInfo && courseInfo.length > 0"
:course-list="courseInfo"
@view-detail="viewCourseDetail"
/>
<CourseInfoCard v-if="courseInfo && courseInfo.length > 0" :course-list="courseInfo"
@view-detail="viewCourseDetail" />
<view v-else class="empty-state">
<text class="empty-icon">📚</text>
<text class="empty-text">暂无课程信息</text>
@ -97,12 +74,8 @@
<text class="empty-icon">📞</text>
<text class="empty-text">暂无通话记录</text>
</view>
<CallRecordCard
v-for="record in listCallUp"
:key="record.id"
:record="record"
@remark="openAddRemark"
/>
<CallRecordCard v-for="record in listCallUp" :key="record.id" :record="record"
@remark="openAddRemark" />
</view>
<!-- 体测记录标签内容 -->
@ -119,12 +92,8 @@
<text class="empty-icon">📊</text>
<text class="empty-text">暂无体测记录</text>
</view>
<FitnessRecordCard
v-for="record in currentStudentFitnessRecords"
:key="record.id"
:record="record"
@edit="openEditFitnessRecord"
/>
<FitnessRecordCard v-for="record in currentStudentFitnessRecords" :key="record.id" :record="record"
@edit="openEditFitnessRecord" />
</view>
<!-- 学习计划标签内容 -->
@ -141,34 +110,19 @@
<text class="empty-icon">🎁</text>
<text class="empty-text">暂无赠品记录</text>
</view>
<GiftRecordCard
v-for="record in giftRecords"
:key="record.id"
:record="record"
/>
<GiftRecordCard v-for="record in giftRecords" :key="record.id" :record="record" />
</view>
</view>
<!-- 底部弹窗组件 -->
<BottomPopup
:visible="currentPopup !== null"
:title="popupTitle"
:has-footer="needsFooter"
@close="closePopup"
@click.stop
>
<BottomPopup :visible="currentPopup !== null" :title="popupTitle" :has-footer="needsFooter" @close="closePopup"
@click.stop>
<!-- 课程信息弹窗 -->
<CourseInfoCard
v-if="currentPopup === 'course_info'"
:course-list="courseInfo"
@view-detail="viewCourseDetail"
/>
<CourseInfoCard v-if="currentPopup === 'course_info'" :course-list="courseInfo"
@view-detail="viewCourseDetail" />
<!-- 体测记录弹窗 -->
<view
class="fitness-records-container"
v-if="currentPopup === 'fitness_record'"
>
<view class="fitness-records-container" v-if="currentPopup === 'fitness_record'">
<!-- 空状态提示 -->
<view v-if="currentStudentFitnessRecords.length === 0" class="empty-state">
<view class="empty-icon">📊</view>
@ -177,45 +131,25 @@
</view>
<!-- 体测记录列表 -->
<FitnessRecordCard
v-for="record in currentStudentFitnessRecords"
:key="record.id"
:record="record"
@edit="openEditFitnessRecord"
/>
<FitnessRecordCard v-for="record in currentStudentFitnessRecords" :key="record.id" :record="record"
@edit="openEditFitnessRecord" />
</view>
<!-- 学习计划弹窗 -->
<StudyPlanCard
v-if="currentPopup === 'study_plan'"
:plan-list="studyPlanList"
@edit="openEditStudyPlan"
/>
<StudyPlanCard v-if="currentPopup === 'study_plan'" :plan-list="studyPlanList" @edit="openEditStudyPlan" />
<!-- 订单列表弹窗 -->
<OrderListCard
v-if="currentPopup === 'order_list'"
:order-list="orderList"
@add-order="openAddOrderDialog"
@pay-order="handlePayOrder"
@view-detail="viewOrderDetail"
/>
<OrderListCard v-if="currentPopup === 'order_list'" :order-list="orderList" @add-order="openAddOrderDialog"
@pay-order="handlePayOrder" @view-detail="viewOrderDetail" />
<!-- 服务列表弹窗 -->
<ServiceListCard
v-if="currentPopup === 'service_list'"
:service-list="serviceList"
/>
<ServiceListCard v-if="currentPopup === 'service_list'" :service-list="serviceList" />
<!-- 底部操作按钮 -->
<template #footer>
<view class="popup-footer-btns">
<view class="footer-btn cancel-btn" @click.stop="closePopup">关闭</view>
<view
class="footer-btn confirm-btn"
v-if="showAddButton"
@click.stop="handleAddAction"
>新增</view>
<view class="footer-btn confirm-btn" v-if="showAddButton" @click.stop="handleAddAction">新增</view>
</view>
</template>
</BottomPopup>
@ -223,11 +157,7 @@
<!-- 保留原有的编辑弹窗 -->
<uni-popup ref="remarkPopup" type="dialog">
<view class="remark-dialog">
<textarea
v-model="remark_content"
placeholder="请输入备注内容"
maxlength="200"
></textarea>
<textarea v-model="remark_content" placeholder="请输入备注内容" maxlength="200"></textarea>
<view class="dialog-btns">
<view class="btn cancel" @click="closeRemark">取消</view>
<view class="btn confirm" @click="confirmRemark">确定</view>
@ -235,19 +165,17 @@
</view>
</uni-popup>
<FitnessRecordPopup ref="fitnessRecordPopup" :resource-id="String(clientInfo.resource_id)" :student-id="currentStudent && currentStudent.id" @confirm="handleFitnessRecordConfirm" />
<StudentEditPopup ref="studentEditPopup" :resource-id="clientInfo.resource_id" @confirm="handleStudentEditConfirm" />
<StudyPlanPopup ref="studyPlanPopup" :student-id="currentStudent && currentStudent.id" @confirm="handleStudyPlanConfirm" />
<FitnessRecordPopup ref="fitnessRecordPopup" :resource-id="String(clientInfo.resource_id)"
:student-id="currentStudent && currentStudent.id" @confirm="handleFitnessRecordConfirm" />
<StudentEditPopup ref="studentEditPopup" :resource-id="clientInfo.resource_id"
@confirm="handleStudentEditConfirm" />
<StudyPlanPopup ref="studyPlanPopup" :student-id="currentStudent && currentStudent.id"
@confirm="handleStudyPlanConfirm" />
<!-- 新增订单弹窗 -->
<uni-popup ref="orderFormPopup" type="bottom">
<OrderFormPopup
:visible="showOrderForm"
:student-info="currentStudent"
:resource-id="clientInfo.resource_id"
@cancel="closeOrderForm"
@confirm="handleOrderFormConfirm"
/>
<OrderFormPopup :visible="showOrderForm" :student-info="currentStudent"
:resource-id="clientInfo.resource_id" @cancel="closeOrderForm" @confirm="handleOrderFormConfirm" />
</uni-popup>
<!-- 二维码支付弹窗 -->
@ -275,12 +203,8 @@
<!-- 二维码区域 -->
<view class="qrcode-container">
<image
v-if="qrCodePaymentData.qrcodeImage"
:src="qrCodePaymentData.qrcodeImage"
class="qrcode-image"
mode="aspectFit"
/>
<image v-if="qrCodePaymentData.qrcodeImage" :src="qrCodePaymentData.qrcodeImage"
class="qrcode-image" mode="aspectFit" />
<text v-else class="qrcode-placeholder">二维码加载中...</text>
<text class="qrcode-tip">请使用微信扫码完成支付</text>
</view>
@ -296,27 +220,27 @@
</template>
<script>
import apiRoute from '@/api/apiRoute.js'
//
import ClientInfoCard from '@/components/client-info-card/client-info-card.vue'
import StudentInfoCard from '@/components/student-info-card/student-info-card.vue'
import TabSwitcher from '@/components/tab-switcher/tab-switcher.vue'
import CallRecordCard from '@/components/call-record-card/call-record-card.vue'
import FitnessRecordCard from '@/components/fitness-record-card/fitness-record-card.vue'
import GiftRecordCard from '@/components/gift-record-card/gift-record-card.vue'
//
import BottomPopup from '@/components/bottom-popup/index.vue'
import StudyPlanCard from '@/components/study-plan-card/index.vue'
import CourseInfoCard from '@/components/course-info-card/index.vue'
import OrderListCard from '@/components/order-list-card/index.vue'
import ServiceListCard from '@/components/service-list-card/index.vue'
import OrderFormPopup from '@/components/order-form-popup/index.vue'
//
import StudentEditPopup from '@/components/student-edit-popup/student-edit-popup.vue'
import FitnessRecordPopup from '@/components/fitness-record-popup/fitness-record-popup.vue'
import StudyPlanPopup from '@/components/study-plan-popup/study-plan-popup.vue'
export default {
import apiRoute from '@/api/apiRoute.js'
//
import ClientInfoCard from '@/components/client-info-card/client-info-card.vue'
import StudentInfoCard from '@/components/student-info-card/student-info-card.vue'
import TabSwitcher from '@/components/tab-switcher/tab-switcher.vue'
import CallRecordCard from '@/components/call-record-card/call-record-card.vue'
import FitnessRecordCard from '@/components/fitness-record-card/fitness-record-card.vue'
import GiftRecordCard from '@/components/gift-record-card/gift-record-card.vue'
//
import BottomPopup from '@/components/bottom-popup/index.vue'
import StudyPlanCard from '@/components/study-plan-card/index.vue'
import CourseInfoCard from '@/components/course-info-card/index.vue'
import OrderListCard from '@/components/order-list-card/index.vue'
import ServiceListCard from '@/components/service-list-card/index.vue'
import OrderFormPopup from '@/components/order-form-popup/index.vue'
//
import StudentEditPopup from '@/components/student-edit-popup/student-edit-popup.vue'
import FitnessRecordPopup from '@/components/fitness-record-popup/fitness-record-popup.vue'
import StudyPlanPopup from '@/components/study-plan-popup/study-plan-popup.vue'
export default {
components: {
ClientInfoCard,
StudentInfoCard,
@ -341,7 +265,11 @@ export default {
//
clientInfo: { id: '', resource_id: '', customerResource: {} },
clientInfo: {
id: '',
resource_id: '',
customerResource: {}
},
userInfo: {},
listCallUp: [],
courseInfo: [],
@ -368,21 +296,58 @@ export default {
currentRecord: null,
//
tabs: [
{ id: 1, name: '基本资料' },
{ id: 3, name: '通话记录' },
{ id: 7, name: '修改资料' },
{ id: 6, name: '修改记录' },
{ id: 8, name: '赠品记录' }
tabs: [{
id: 1,
name: '基本资料'
},
{
id: 3,
name: '通话记录'
},
{
id: 7,
name: '修改资料'
},
{
id: 6,
name: '修改记录'
},
{
id: 8,
name: '赠品记录'
}
],
actionButtons: [
{ key: 'course_arrangement', text: '课程安排', icon: '📅' },
{ key: 'order_list', text: '订单列表', icon: '📋' },
{ key: 'service_list', text: '服务列表', icon: '🔧' },
{ key: 'course_info', text: '课程信息', icon: '📚' },
{ key: 'fitness_record', text: '体测记录', icon: '📊' },
{ key: 'study_plan', text: '学习计划', icon: '📝' }
actionButtons: [{
key: 'course_arrangement',
text: '课程安排',
icon: '📅'
},
{
key: 'order_list',
text: '订单列表',
icon: '📋'
},
{
key: 'service_list',
text: '服务列表',
icon: '🔧'
},
{
key: 'course_info',
text: '课程信息',
icon: '📚'
},
{
key: 'fitness_record',
text: '体测记录',
icon: '📊'
},
{
key: 'study_plan',
text: '学习计划',
icon: '📝'
}
]
}
},
@ -429,7 +394,10 @@ export default {
},
onLoad(options) {
if (!options?.resource_sharing_id) {
uni.showToast({ title: '缺少必要参数', icon: 'none' })
uni.showToast({
title: '缺少必要参数',
icon: 'none'
})
setTimeout(() => uni.navigateBack(), 1500)
return
}
@ -470,7 +438,9 @@ export default {
async getInfo() {
if (!this.resource_sharing_id) return
try {
const res = await apiRoute.xs_resourceSharingInfo({ resource_sharing_id: this.resource_sharing_id })
const res = await apiRoute.xs_resourceSharingInfo({
resource_sharing_id: this.resource_sharing_id
})
if (res.code === 1) {
this.clientInfo = res.data
}
@ -482,7 +452,9 @@ export default {
async getListCallUp() {
if (!this.clientInfo?.resource_id) return
try {
const res = await apiRoute.listCallUp({ resource_id: this.clientInfo.resource_id })
const res = await apiRoute.listCallUp({
resource_id: this.clientInfo.resource_id
})
if (res.code === 1) {
this.listCallUp = res.data || []
}
@ -490,15 +462,39 @@ export default {
console.error('获取通话记录失败:', error)
}
},
handleMakeCall() {
async handleMakeCall() {
const phone = this.clientInfo?.customerResource?.phone_number
if (phone) {
uni.makePhoneCall({ phoneNumber: phone })
let param = {
staff_id: this.userInfo.id, //id
resource_id: this.clientInfo?.resource_id, //ID
resource_type: '', //
communication_type: 'phone', //: phone-, email-, meeting-, other-
communication_result: 'success', //: success-, failure-, pending-
remarks: null, //
tag: null, //
}
let res = await apiRoute.xs_communicationRecordsAdd(param) //
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none',
})
return
}
uni.makePhoneCall({
phoneNumber: phone
})
}
},
handleSendMessage() {
uni.showToast({ title: '发送消息功能待实现', icon: 'none' })
uni.showToast({
title: '发送消息功能待实现',
icon: 'none'
})
},
openAddRemark(record) {
@ -509,7 +505,10 @@ export default {
async confirmRemark() {
if (!this.remark_content.trim() || !this.currentRecord?.id) {
uni.showToast({ title: '请输入备注内容', icon: 'none' })
uni.showToast({
title: '请输入备注内容',
icon: 'none'
})
return
}
@ -520,11 +519,17 @@ export default {
})
if (res.code === 1) {
uni.showToast({ title: '备注更新成功', icon: 'success' })
uni.showToast({
title: '备注更新成功',
icon: 'success'
})
await this.getListCallUp()
}
} catch (error) {
uni.showToast({ title: '更新失败', icon: 'none' })
uni.showToast({
title: '更新失败',
icon: 'none'
})
}
this.closeRemark()
@ -625,7 +630,10 @@ export default {
viewCourseDetail(course) {
if (!course?.id) {
uni.showToast({ title: '课程信息不完整', icon: 'none' })
uni.showToast({
title: '课程信息不完整',
icon: 'none'
})
return
}
this.$navigateToPage(`/pages-market/course/course_detail`, {
@ -634,15 +642,18 @@ export default {
})
},
async handleTabChange({ tabId }) {
async handleTabChange({
tabId
}) {
this.switch_tags_type = tabId
if (tabId === 2) await this.getCourseInfo()
if (tabId === 3) await this.getListCallUp()
if (tabId === 4) await this.getFitnessRecords()
if (tabId === 6) {
this.$navigateToPage(`/pages-market/clue/edit_clues_log`, {
resource_id: this.clientInfo.id
resource_id: this.clientInfo.resource_id
})
}
console.log('切换标签页:', this.clientInfo)
@ -652,7 +663,10 @@ export default {
if (tabId === 8) await this.getGiftRecords()
},
handleStudentAction({ action, student }) {
handleStudentAction({
action,
student
}) {
// this.setCurrentStudent(student)
console.log('学生操作:', action, student)
@ -762,7 +776,9 @@ export default {
}
// URL
const { img_domian } = require('@/common/config.js')
const {
img_domian
} = require('@/common/config.js')
//
let cleanPath = relativePath
@ -791,39 +807,60 @@ export default {
async handleFitnessRecordConfirm(result) {
try {
const { isEditing, data } = result
const {
isEditing,
data
} = result
if (isEditing) {
//
const response = await apiRoute.xy_physicalTestEdit(data)
if (response.code === 1) {
uni.showToast({ title: '编辑成功', icon: 'success' })
uni.showToast({
title: '编辑成功',
icon: 'success'
})
//
await this.getFitnessRecords()
} else {
uni.showToast({ title: response.msg || '编辑失败', icon: 'none' })
uni.showToast({
title: response.msg || '编辑失败',
icon: 'none'
})
}
} else {
//
const response = await apiRoute.xy_physicalTestAdd(data)
if (response.code === 1) {
uni.showToast({ title: '新增成功', icon: 'success' })
uni.showToast({
title: '新增成功',
icon: 'success'
})
//
await this.getFitnessRecords()
} else {
uni.showToast({ title: response.msg || '新增失败', icon: 'none' })
uni.showToast({
title: response.msg || '新增失败',
icon: 'none'
})
}
}
} catch (error) {
console.error('保存体测记录失败:', error)
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
})
}
},
//
openAddStudyPlan() {
if (!this.currentStudent) {
uni.showToast({ title: '请先选择学生', icon: 'none' })
uni.showToast({
title: '请先选择学生',
icon: 'none'
})
return
}
this.$refs.studyPlanPopup.openAdd()
@ -835,32 +872,50 @@ export default {
async handleStudyPlanConfirm(result) {
try {
const { isEditing, data } = result
const {
isEditing,
data
} = result
if (isEditing) {
//
const response = await apiRoute.editStudyPlan(data)
if (response.code === 1) {
uni.showToast({ title: '编辑成功', icon: 'success' })
uni.showToast({
title: '编辑成功',
icon: 'success'
})
//
await this.getStudyPlanList()
} else {
uni.showToast({ title: response.msg || '编辑失败', icon: 'none' })
uni.showToast({
title: response.msg || '编辑失败',
icon: 'none'
})
}
} else {
//
const response = await apiRoute.addStudyPlan(data)
if (response.code === 1) {
uni.showToast({ title: '新增成功', icon: 'success' })
uni.showToast({
title: '新增成功',
icon: 'success'
})
//
await this.getStudyPlanList()
} else {
uni.showToast({ title: response.msg || '新增失败', icon: 'none' })
uni.showToast({
title: response.msg || '新增失败',
icon: 'none'
})
}
}
} catch (error) {
console.error('保存学习计划失败:', error)
uni.showToast({ title: '保存失败,请重试', icon: 'none' })
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
})
}
},
@ -868,7 +923,9 @@ export default {
async getStudentList() {
try {
if (this.clientInfo?.resource_id) {
const res = await apiRoute.xs_getStudentList({ parent_resource_id: this.clientInfo.resource_id })
const res = await apiRoute.xs_getStudentList({
parent_resource_id: this.clientInfo.resource_id
})
if (res.code === 1) {
//
this.studentList = await this.processStudentData(res.data || [])
@ -876,8 +933,7 @@ export default {
}
}
// 使
const mockData = [
{
const mockData = [{
id: 1,
name: '张小明',
gender: 1, // 1=, 2=
@ -889,8 +945,7 @@ export default {
trial_class_count: 3,
//
age: 9
}
]
}]
//
this.studentList = await this.processStudentData(mockData)
@ -914,7 +969,8 @@ export default {
academic_affairs: await this.getPersonnelName(student.consultant_id),
trial_course_count: student.trial_class_count || 0,
// 使API访
course_visit_status: this.formatVisitStatus(student.first_visit_status, student.second_visit_status)
course_visit_status: this.formatVisitStatus(student.first_visit_status, student
.second_visit_status)
}
processedStudents.push(processedStudent)
}
@ -928,7 +984,9 @@ export default {
try {
// school_student_label
const res = await apiRoute.getStudentLabel({ id: labelId })
const res = await apiRoute.getStudentLabel({
id: labelId
})
if (res.code === 1) {
return res.data ? [res.data.label_name] : []
}
@ -1075,7 +1133,10 @@ export default {
// API
// const res = await apiRoute.deleteStudent({ student_id: student.id })
// if (res.code === 1) {
uni.showToast({ title: '删除成功', icon: 'success' })
uni.showToast({
title: '删除成功',
icon: 'success'
})
//
await this.getStudentList()
// } else {
@ -1083,7 +1144,10 @@ export default {
// }
} catch (error) {
console.error('删除学员失败:', error)
uni.showToast({ title: '删除失败', icon: 'none' })
uni.showToast({
title: '删除失败',
icon: 'none'
})
}
},
@ -1112,11 +1176,17 @@ export default {
//
await this.getStudentList()
} else {
uni.showToast({ title: res.msg || '保存失败', icon: 'none' })
uni.showToast({
title: res.msg || '保存失败',
icon: 'none'
})
}
} catch (error) {
console.error('保存学生信息失败:', error)
uni.showToast({ title: '保存失败', icon: 'none' })
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
},
@ -1236,7 +1306,10 @@ export default {
const targetStudentId = studentId || this.currentStudent?.id
if (!targetStudentId) {
uni.showToast({ title: '请先选择学生', icon: 'none' })
uni.showToast({
title: '请先选择学生',
icon: 'none'
})
return
}
@ -1297,7 +1370,10 @@ export default {
//
await this.getOrderList()
uni.showToast({ title: '订单创建成功', icon: 'success' })
uni.showToast({
title: '订单创建成功',
icon: 'success'
})
} catch (error) {
console.error('处理订单确认失败:', error)
}
@ -1317,7 +1393,7 @@ export default {
const paymentType = order._raw?.payment_type || order.payment_type
console.log('paymentType', paymentType)
try {
switch(paymentType) {
switch (paymentType) {
case 'cash':
// -
await this.confirmCashPayment(order)
@ -1335,11 +1411,17 @@ export default {
this.showWechatPayment(order)
break
default:
uni.showToast({ title: '不支持的支付方式', icon: 'none' })
uni.showToast({
title: '不支持的支付方式',
icon: 'none'
})
}
} catch (error) {
console.error('支付处理失败:', error)
uni.showToast({ title: '支付处理失败', icon: 'none' })
uni.showToast({
title: '支付处理失败',
icon: 'none'
})
}
},
@ -1361,15 +1443,24 @@ export default {
const result = await apiRoute.xs_orderTableUpdatePaymentStatus(updateData)
if (result.code === 1) {
uni.showToast({ title: '支付确认成功', icon: 'success' })
uni.showToast({
title: '支付确认成功',
icon: 'success'
})
//
await this.getOrderList()
} else {
uni.showToast({ title: result.msg || '支付确认失败', icon: 'none' })
uni.showToast({
title: result.msg || '支付确认失败',
icon: 'none'
})
}
} catch (error) {
console.error('现金支付确认失败:', error)
uni.showToast({ title: '支付确认失败', icon: 'none' })
uni.showToast({
title: '支付确认失败',
icon: 'none'
})
}
}
}
@ -1381,7 +1472,9 @@ export default {
console.log('扫码支付:', order)
try {
uni.showLoading({ title: '生成支付二维码...' })
uni.showLoading({
title: '生成支付二维码...'
})
//
const res = await apiRoute.getOrderPayQrcode({
@ -1445,7 +1538,10 @@ export default {
this.closeQRCodeModal()
} catch (error) {
console.error('支付确认失败:', error)
uni.showToast({ title: '支付确认失败', icon: 'none' })
uni.showToast({
title: '支付确认失败',
icon: 'none'
})
}
}
}
@ -1464,7 +1560,8 @@ export default {
success: async (modalRes) => {
if (modalRes.confirm) {
//
await this.updateOrderStatus(order, 'partial', `SUB${Date.now()}`)
await this.updateOrderStatus(order, 'partial',
`SUB${Date.now()}`)
}
}
})
@ -1483,7 +1580,9 @@ export default {
success: async (res) => {
if (res.confirm) {
//
uni.showLoading({ title: '正在调用微信支付...' })
uni.showLoading({
title: '正在调用微信支付...'
})
//
setTimeout(async () => {
@ -1495,7 +1594,8 @@ export default {
content: '微信支付完成,请确认是否已收到款项?',
success: async (confirmRes) => {
if (confirmRes.confirm) {
await this.updateOrderStatus(order, 'paid', `WX${Date.now()}`)
await this.updateOrderStatus(order, 'paid',
`WX${Date.now()}`)
}
}
})
@ -1529,11 +1629,17 @@ export default {
//
await this.getOrderList()
} else {
uni.showToast({ title: result.msg || '状态更新失败', icon: 'none' })
uni.showToast({
title: result.msg || '状态更新失败',
icon: 'none'
})
}
} catch (error) {
console.error('更新订单状态失败:', error)
uni.showToast({ title: '状态更新失败', icon: 'none' })
uni.showToast({
title: '状态更新失败',
icon: 'none'
})
}
},
@ -1558,7 +1664,7 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
const isOrderPaid = order.status === 'paid'
const buttons = isOrderPaid ? ['知道了', '合同签署'] : ['知道了']
console.log('订单数据',order)
console.log('订单数据', order)
uni.showModal({
title: '订单详情',
content: detailText,
@ -1596,7 +1702,8 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
}
//
let url = `/pages-student/contracts/sign?contract_id=${contractId}&student_id=${studentId}&contract_name=${encodeURIComponent(order.product_name + '合同')}&user_role=staff`
let url =
`/pages-student/contracts/sign?contract_id=${contractId}&student_id=${studentId}&contract_name=${encodeURIComponent(order.product_name + '合同')}&user_role=staff`
// ID
if (contractSignId) {
@ -1612,7 +1719,9 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
//
async getContractByOrder(order, studentId) {
try {
uni.showLoading({ title: '获取合同信息...' })
uni.showLoading({
title: '获取合同信息...'
})
// API
const res = await apiRoute.getContractByOrder({
@ -1689,31 +1798,32 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
}
}
},
}
}
</script>
<style lang="less" scoped>
.fitness-records-container {
.fitness-records-container {
max-height: 60vh;
overflow-y: auto;
}
}
/* 滚动条样式 */
.fitness-records-container::-webkit-scrollbar {
/* 滚动条样式 */
.fitness-records-container::-webkit-scrollbar {
width: 6rpx;
}
}
.fitness-records-container::-webkit-scrollbar-track {
.fitness-records-container::-webkit-scrollbar-track {
background: transparent;
}
}
.fitness-records-container::-webkit-scrollbar-thumb {
.fitness-records-container::-webkit-scrollbar-thumb {
background: #29D3B4;
border-radius: 3rpx;
}
}
.fitness-records-container::-webkit-scrollbar-thumb:hover {
.fitness-records-container::-webkit-scrollbar-thumb:hover {
background: #24B89E;
}
@import './clue_info.less';
}
@import './clue_info.less';
</style>

10
uniapp/pages-market/clue/edit_clues.vue

@ -165,12 +165,18 @@
</view>
</fui-form-item>
<!-- 承诺到访时间 -->
<fui-form-item labelWidth="240" label="2、承诺到访时间" labelSize='26' prop="promised_visit_time" background='#434544' labelColor='#fff' :bottomBorder='false'>
<!-- <fui-form-item labelWidth="240" label="2、承诺到访时间" labelSize='26' prop="promised_visit_time" background='#434544' labelColor='#fff' :bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<view class="input-title" style="margin-right:14rpx;" @click="openDateTime('promised_visit_time')">
{{ formData.promised_visit_time ? formData.promised_visit_time : '点击选择' }}
</view>
</view>
</fui-form-item> -->
<fui-form-item labelWidth="240" label="2、承诺到访时间" labelSize='26' prop="promised_visit_time" background='#434544' labelColor='#fff' :bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input :borderBottom="false" :padding="[0]" placeholder="填写承诺到访时间" v-model="formData.promised_visit_time" backgroundColor="#434544" size="26" color="#fff" ></fui-input>
</view>
</fui-form-item>
<!-- 距离 -->
<fui-form-item label="3、距离" label-width="210" labelSize='26' prop="distance" background='#434544' labelColor='#fff' :bottomBorder='false'>
@ -309,7 +315,7 @@
<fui-date-picker :show="date_picker_show" type="5" @change="change_date" @cancel="cancel_date" :value="default_date_value"></fui-date-picker>
<!-- 日期时间选择器 -->
<fui-date-picker :show="datetime_picker_show" type="1" @change="change_datetime" @cancel="cancel_datetime" :value="default_datetime_value"></fui-date-picker>
<fui-date-picker :show="datetime_picker_show" type="5" @change="change_datetime" @cancel="cancel_datetime" :value="default_datetime_value"></fui-date-picker>
<fui-picker :linkage='picker_linkage' :options="picker_options" :layer="1" :show="picker_show" @change="changeCicker" @cancel="cancelCicker"></fui-picker>

26
uniapp/pages-market/clue/index.vue

@ -18,10 +18,10 @@
</view>
<view class="card" v-for="(v,k) in tableList_1" :key="k">
<!-- 状态水印 -->
<view class="status-watermark" v-if="!v.customerResource.communication_time">
<view class="status-watermark" v-if="v.customerResource && !v.customerResource.communication_time">
新资源
</view>
<view class="card-content">
<view class="card-content" v-if="v.customerResource">
<view class="card-left" @click="clue_info(v)">
<view class="user-info-row">
<view class="user-avatar">
@ -79,14 +79,14 @@
</view>
<view class="card-footer">
<view class="card-date">
<view class="card-con" v-if="v.customerResource.communication_time">
<view class="card-con" v-if="v.customerResource && v.customerResource.communication_time">
{{ $util.formatToDateTime((v.customerResource.communication_time || ''), 'm-d H:i') }}
拨打电话
</view>
<view class="card-con" v-else>
暂未联系
</view>
<view style="margin-left: 30rpx;">
<view style="margin-left: 30rpx;" v-if="v.customerResource">
<view style="display: flex;align-items: center;">
<view class="title-x">
是否有效{{ v.sixSpeed && v.sixSpeed.efficacious === 1 ? '有效' : '无效' }}
@ -134,7 +134,7 @@
</view>
<view class="card" v-for="(v,k) in tableList_2" :key="k" @click="batchMode ? toggleItemSelection(v) : null">
<!-- 状态水印 -->
<view class="status-watermark" v-if="!v.customerResource.communication_time">
<view class="status-watermark" v-if="v.customerResource && !v.customerResource.communication_time">
新资源
</view>
<view class="card-content">
@ -153,6 +153,18 @@
</view>
<!-- <view class="card-label">{{v.is_status == 1 ? '试听' : '成交'}}</view>-->
</view>
<view class="card-con">
所属校区{{ v.customerResource.campus_name }}
</view>
<view class="card-con">
市场老师{{ v.customerResource.consultant_name }}
</view>
<view class="card-con">
决策人{{v.customerResource.name}} <span
class="card-con-span">{{v.customerResource.decision_maker}}</span>
@ -169,13 +181,13 @@
</view>
<view class="card-footer">
<view class="card-date">
<view class="card-con" v-if="v.customerResource.communication_time">
<view class="card-con" v-if="v.customerResource && v.customerResource.communication_time">
{{ $util.formatToDateTime((v.customerResource.communication_time || ''),'m-d H:i') }} 拨打电话
</view>
<view class="card-con" v-else>
暂未联系
</view>
<view style="margin-left: 30rpx;">
<view style="margin-left: 30rpx;" v-if="v.customerResource">
<view style="display: flex;align-items: center;">
<view style="padding: 12rpx;">
<image v-if="v.customerResource.initial_intent == 'high'"

1
uniapp/pages-student/schedule/index.vue

@ -498,6 +498,7 @@
},
async requestLeave() {
this.showCoursePopup = false
if (!this.selectedCourse) return
uni.showModal({

Loading…
Cancel
Save