From b54b68b4f6915ffbd171c3147f62cf53c227b175 Mon Sep 17 00:00:00 2001
From: zeyan <258785420@qq.com>
Date: Mon, 18 Aug 2025 19:44:45 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../api/controller/apiController/Contract.php | 89 +++
niucloud/app/api/route/route.php | 3 +
.../apiService/ContractSignFormService.php | 524 +++++++++++++++---
uniapp/api/apiRoute.js | 25 +-
uniapp/api/member.js | 35 +-
uniapp/common/config.js | 4 +-
uniapp/pages-market/clue/clue_info.vue | 4 +-
uniapp/pages-student/contracts/sign.vue | 220 +++++++-
uniapp/pages-student/messages/index.vue | 75 ++-
uniapp/pages/student/home/index.vue | 18 +-
10 files changed, 872 insertions(+), 125 deletions(-)
diff --git a/niucloud/app/api/controller/apiController/Contract.php b/niucloud/app/api/controller/apiController/Contract.php
index 087189b4..751ed165 100644
--- a/niucloud/app/api/controller/apiController/Contract.php
+++ b/niucloud/app/api/controller/apiController/Contract.php
@@ -336,4 +336,93 @@ class Contract extends BaseApiService
return fail('合同签署失败:' . $e->getMessage());
}
}
+
+ /**
+ * 员工端合同签署
+ * @param Request $request
+ * @return mixed
+ */
+ public function signStaffContract(Request $request)
+ {
+ $contract_id = $request->param('contract_id', 0);
+ $contract_sign_id = $request->param('contract_sign_id', 0);
+ $form_data = $request->param('form_data', []);
+ $signature_image = $request->param('signature_image', '');
+
+ if (empty($contract_id)) {
+ return fail('合同ID不能为空');
+ }
+
+ if (empty($contract_sign_id)) {
+ return fail('合同签署记录ID不能为空');
+ }
+
+ $params = [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'personnel_id' => $this->member_id,
+ 'form_data' => $form_data,
+ 'signature_image' => $signature_image
+ ];
+
+ try {
+ $service = new ContractSignFormService();
+ $res = $service->submitStaffContractSign($params);
+
+ if (!$res['code']) {
+ return fail($res['msg']);
+ }
+
+ return success($res['data'], '合同签署成功');
+ } catch (\Exception $e) {
+ return fail('合同签署失败:' . $e->getMessage());
+ }
+ }
+
+ /**
+ * 学员端合同签署
+ * @param Request $request
+ * @return mixed
+ */
+ public function signStudentContract(Request $request)
+ {
+ $contract_id = $request->param('contract_id', 0);
+ $contract_sign_id = $request->param('contract_sign_id', 0);
+ $student_id = $request->param('student_id', 0);
+ $form_data = $request->param('form_data', []);
+ $signature_image = $request->param('signature_image', '');
+
+ if (empty($contract_id)) {
+ return fail('合同ID不能为空');
+ }
+
+ if (empty($contract_sign_id)) {
+ return fail('合同签署记录ID不能为空');
+ }
+
+ if (empty($student_id)) {
+ return fail('学生ID不能为空');
+ }
+
+ $params = [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'student_id' => $student_id,
+ 'form_data' => $form_data,
+ 'signature_image' => $signature_image
+ ];
+
+ try {
+ $service = new ContractSignFormService();
+ $res = $service->submitStudentContractSign($params);
+
+ if (!$res['code']) {
+ return fail($res['msg']);
+ }
+
+ return success($res['data'], '合同签署成功');
+ } catch (\Exception $e) {
+ return fail('合同签署失败:' . $e->getMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/niucloud/app/api/route/route.php b/niucloud/app/api/route/route.php
index 3233a243..02d21cb0 100644
--- a/niucloud/app/api/route/route.php
+++ b/niucloud/app/api/route/route.php
@@ -468,6 +468,9 @@ Route::group(function () {
Route::get('contract/getStudentContractSignFormBySignId', 'apiController.Contract/getStudentContractSignFormBySignId');
// 前端期望的路由路径(映射到相同的控制器方法)
Route::get('student/contract/sign-form', 'apiController.Contract/getStudentContractSignForm');
+ // 员工端和学员端合同签署接口
+ Route::post('contract/signStaffContract', 'apiController.Contract/signStaffContract');
+ Route::post('contract/signStudentContract', 'apiController.Contract/signStudentContract');
//服务管理
diff --git a/niucloud/app/service/api/apiService/ContractSignFormService.php b/niucloud/app/service/api/apiService/ContractSignFormService.php
index 640a6429..8c9d6457 100644
--- a/niucloud/app/service/api/apiService/ContractSignFormService.php
+++ b/niucloud/app/service/api/apiService/ContractSignFormService.php
@@ -581,79 +581,6 @@ class ContractSignFormService extends BaseApiService
return (string)$value;
}
- /**
- * 提交学员合同签署数据
- * 处理移动端提交的合同签署表单数据
- * 验证数据完整性并保存到数据库
- *
- * @param array $params 提交参数
- * - contract_id: 合同模板ID
- * - student_id: 学员ID
- * - form_data: 表单数据数组
- * @return array 提交结果
- */
- public function submitStudentContractSign(array $params)
- {
- try {
- // 验证必要参数
- if (empty($params['contract_id']) || empty($params['student_id']) || empty($params['form_data'])) {
- throw new \Exception('缺少必要参数');
- }
-
- $contract_id = (int)$params['contract_id'];
- $student_id = (int)$params['student_id'];
- $form_data = $params['form_data'];
-
- Log::info('开始处理学员合同签署提交', [
- 'contract_id' => $contract_id,
- 'student_id' => $student_id,
- 'form_data_keys' => array_keys($form_data)
- ]);
-
- // 验证合同和学员是否存在
- $contract = $this->getContractInfo($contract_id);
- if (!$contract) {
- throw new \Exception('合同模板不存在');
- }
-
- $student = $this->getStudentInfo($student_id);
- if (!$student) {
- throw new \Exception('学员信息不存在');
- }
-
- // 保存签署记录
- $sign_id = $this->saveContractSignRecord($contract_id, $student_id, $form_data);
-
- if ($sign_id) {
- Log::info('学员合同签署成功', [
- 'contract_id' => $contract_id,
- 'student_id' => $student_id,
- 'sign_id' => $sign_id
- ]);
-
- return [
- 'code' => 1,
- 'msg' => '合同签署成功',
- 'data' => ['sign_id' => $sign_id]
- ];
- } else {
- throw new \Exception('保存签署记录失败');
- }
-
- } catch (\Exception $e) {
- Log::error('学员合同签署失败', [
- 'params' => $params,
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
-
- return [
- 'code' => 0,
- 'msg' => $e->getMessage(),
- 'data' => []
- ];
- }
- }
/**
* 保存合同签署记录
@@ -895,4 +822,455 @@ class ContractSignFormService extends BaseApiService
return '';
}
}
+
+ /**
+ * 员工端合同签署提交
+ * 处理员工端提交的合同签署表单数据,员工可以填写甲乙双方所有字段
+ *
+ * @param array $params 提交参数
+ * - contract_id: 合同模板ID
+ * - contract_sign_id: 合同签署记录ID
+ * - personnel_id: 员工ID
+ * - form_data: 表单数据数组
+ * - signature_image: 签名图片数据
+ * @return array 提交结果
+ */
+ public function submitStaffContractSign(array $params)
+ {
+ try {
+ // 验证必要参数
+ if (empty($params['contract_id']) || empty($params['contract_sign_id']) || empty($params['personnel_id'])) {
+ throw new \Exception('缺少必要参数:contract_id、contract_sign_id、personnel_id');
+ }
+
+ $contract_id = (int)$params['contract_id'];
+ $contract_sign_id = (int)$params['contract_sign_id'];
+ $personnel_id = (int)$params['personnel_id'];
+ $form_data = $params['form_data'] ?? [];
+ $signature_image = $params['signature_image'] ?? '';
+
+ Log::info('开始处理员工端合同签署提交', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'personnel_id' => $personnel_id,
+ 'form_data_keys' => array_keys($form_data)
+ ]);
+
+ // 验证合同签署记录是否存在
+ $sign_record = Db::table('school_contract_sign')
+ ->where('id', $contract_sign_id)
+ ->where('contract_id', $contract_id)
+ ->find();
+
+ if (!$sign_record) {
+ throw new \Exception('合同签署记录不存在');
+ }
+
+ // 验证员工是否存在
+ $personnel = Db::table('school_personnel')
+ ->where('id', $personnel_id)
+ ->where('status', 1)
+ ->find();
+
+ if (!$personnel) {
+ throw new \Exception('员工信息不存在');
+ }
+
+ // 事务处理
+ Db::startTrans();
+ try {
+ // 1. 保存表单数据到 school_document_data_source_config 表
+ $this->saveFormDataToConfig($contract_id, $contract_sign_id, $form_data, 'staff');
+
+ // 2. 更新合同签署记录状态
+ $this->updateContractSignStatus($contract_sign_id, $personnel_id, $signature_image);
+
+ Db::commit();
+
+ Log::info('员工端合同签署成功', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'personnel_id' => $personnel_id
+ ]);
+
+ return [
+ 'code' => 1,
+ 'msg' => '合同签署成功',
+ 'data' => ['contract_sign_id' => $contract_sign_id]
+ ];
+
+ } catch (\Exception $e) {
+ Db::rollback();
+ throw $e;
+ }
+
+ } catch (\Exception $e) {
+ Log::error('员工端合同签署失败', [
+ 'params' => $params,
+ 'error' => $e->getMessage(),
+ 'trace' => $e->getTraceAsString()
+ ]);
+
+ return [
+ 'code' => 0,
+ 'msg' => $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
+ /**
+ * 学员端合同签署提交(新版本)
+ * 处理学员端提交的合同签署表单数据,学员只能填写乙方字段
+ *
+ * @param array $params 提交参数
+ * - contract_id: 合同模板ID
+ * - contract_sign_id: 合同签署记录ID
+ * - student_id: 学员ID
+ * - form_data: 表单数据数组
+ * - signature_image: 签名图片数据
+ * @return array 提交结果
+ */
+ public function submitStudentContractSign(array $params)
+ {
+ try {
+ // 验证必要参数
+ if (empty($params['contract_id']) || empty($params['contract_sign_id']) || empty($params['student_id'])) {
+ throw new \Exception('缺少必要参数:contract_id、contract_sign_id、student_id');
+ }
+
+ $contract_id = (int)$params['contract_id'];
+ $contract_sign_id = (int)$params['contract_sign_id'];
+ $student_id = (int)$params['student_id'];
+ $form_data = $params['form_data'] ?? [];
+ $signature_image = $params['signature_image'] ?? '';
+
+ Log::info('开始处理学员端合同签署提交', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'student_id' => $student_id,
+ 'form_data_keys' => array_keys($form_data)
+ ]);
+
+ // 验证合同签署记录是否存在
+ $sign_record = Db::table('school_contract_sign')
+ ->where('id', $contract_sign_id)
+ ->where('contract_id', $contract_id)
+ ->where('student_id', $student_id)
+ ->find();
+
+ if (!$sign_record) {
+ throw new \Exception('合同签署记录不存在');
+ }
+
+ // 验证学员是否存在
+ $student = Db::table('school_student')
+ ->where('id', $student_id)
+ ->where('status', 1)
+ ->find();
+
+ if (!$student) {
+ throw new \Exception('学员信息不存在');
+ }
+
+ // 事务处理
+ Db::startTrans();
+ try {
+ // 1. 过滤学员端只能填写的字段(乙方字段)
+ $filtered_form_data = $this->filterStudentFormData($contract_id, $contract_sign_id, $form_data);
+
+ // 2. 保存表单数据到 school_document_data_source_config 表
+ $this->saveFormDataToConfig($contract_id, $contract_sign_id, $filtered_form_data, 'student');
+
+ // 3. 更新合同签署记录状态
+ $this->updateContractSignStatus($contract_sign_id, null, $signature_image, $student_id);
+
+ Db::commit();
+
+ Log::info('学员端合同签署成功', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'student_id' => $student_id
+ ]);
+
+ return [
+ 'code' => 1,
+ 'msg' => '合同签署成功',
+ 'data' => ['contract_sign_id' => $contract_sign_id]
+ ];
+
+ } catch (\Exception $e) {
+ Db::rollback();
+ throw $e;
+ }
+
+ } catch (\Exception $e) {
+ Log::error('学员端合同签署失败', [
+ 'params' => $params,
+ 'error' => $e->getMessage(),
+ 'trace' => $e->getTraceAsString()
+ ]);
+
+ return [
+ 'code' => 0,
+ 'msg' => $e->getMessage(),
+ 'data' => []
+ ];
+ }
+ }
+
+ /**
+ * 保存表单数据到 school_document_data_source_config 表的 default_value 字段
+ * 这是核心方法,确保数据正确写入到指定表中
+ *
+ * @param int $contract_id 合同模板ID
+ * @param int $contract_sign_id 合同签署记录ID
+ * @param array $form_data 表单数据
+ * @param string $user_type 用户类型(staff/student)
+ * @return bool
+ */
+ private function saveFormDataToConfig($contract_id, $contract_sign_id, $form_data, $user_type)
+ {
+ try {
+ Log::info('开始保存表单数据到 school_document_data_source_config', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'user_type' => $user_type,
+ 'form_data_count' => count($form_data)
+ ]);
+
+ $now = date('Y-m-d H:i:s');
+ $success_count = 0;
+ $total_count = count($form_data);
+
+ foreach ($form_data as $placeholder => $value) {
+ // 检查该字段配置是否已存在
+ $existing_config = Db::table('school_document_data_source_config')
+ ->where('contract_id', $contract_id)
+ ->where('contract_sign_id', $contract_sign_id)
+ ->where('placeholder', $placeholder)
+ ->find();
+
+ if ($existing_config) {
+ // 更新已存在的配置记录的 default_value 字段
+ $update_result = Db::table('school_document_data_source_config')
+ ->where('id', $existing_config['id'])
+ ->update([
+ 'default_value' => (string)$value,
+ 'updated_at' => $now,
+ 'updated_by' => $user_type
+ ]);
+
+ if ($update_result) {
+ $success_count++;
+ Log::info('更新字段配置成功', [
+ 'config_id' => $existing_config['id'],
+ 'placeholder' => $placeholder,
+ 'value' => $value
+ ]);
+ } else {
+ Log::warning('更新字段配置失败', [
+ 'config_id' => $existing_config['id'],
+ 'placeholder' => $placeholder,
+ 'value' => $value
+ ]);
+ }
+ } else {
+ // 创建新的配置记录(这种情况说明配置数据可能缺失)
+ $config_data = [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'placeholder' => $placeholder,
+ 'data_type' => 'user_input', // 默认为用户输入类型
+ 'field_type' => 'text', // 默认为文本类型
+ 'default_value' => (string)$value,
+ 'is_required' => 0,
+ 'sign_party' => '', // 需要根据字段名推断甲乙方
+ 'created_at' => $now,
+ 'updated_at' => $now,
+ 'created_by' => $user_type,
+ 'updated_by' => $user_type,
+ 'deleted_at' => 0
+ ];
+
+ $insert_result = Db::table('school_document_data_source_config')->insertGetId($config_data);
+
+ if ($insert_result) {
+ $success_count++;
+ Log::info('创建字段配置成功', [
+ 'config_id' => $insert_result,
+ 'placeholder' => $placeholder,
+ 'value' => $value
+ ]);
+ } else {
+ Log::warning('创建字段配置失败', [
+ 'placeholder' => $placeholder,
+ 'value' => $value
+ ]);
+ }
+ }
+ }
+
+ Log::info('表单数据保存完成', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'user_type' => $user_type,
+ 'total_count' => $total_count,
+ 'success_count' => $success_count
+ ]);
+
+ // 如果所有数据都保存成功,返回 true
+ return $success_count === $total_count;
+
+ } catch (\Exception $e) {
+ Log::error('保存表单数据到配置表失败', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'user_type' => $user_type,
+ 'error' => $e->getMessage(),
+ 'trace' => $e->getTraceAsString()
+ ]);
+ throw $e;
+ }
+ }
+
+ /**
+ * 过滤学员端表单数据,只保留乙方字段
+ *
+ * @param int $contract_id 合同模板ID
+ * @param int $contract_sign_id 合同签署记录ID
+ * @param array $form_data 原始表单数据
+ * @return array 过滤后的表单数据
+ */
+ private function filterStudentFormData($contract_id, $contract_sign_id, $form_data)
+ {
+ try {
+ // 获取该签署记录的字段配置
+ $configs = Db::table('school_document_data_source_config')
+ ->where('contract_id', $contract_id)
+ ->where('contract_sign_id', $contract_sign_id)
+ ->select()
+ ->toArray();
+
+ $filtered_data = [];
+
+ foreach ($form_data as $placeholder => $value) {
+ // 查找对应的字段配置
+ $config = array_filter($configs, function($c) use ($placeholder) {
+ return $c['placeholder'] === $placeholder;
+ });
+
+ if (!empty($config)) {
+ $config = array_values($config)[0];
+ $sign_party = $config['sign_party'] ?? '';
+
+ // 学员只能填写乙方字段
+ if (in_array($sign_party, ['second_party', 'party_b', '乙方', ''])) {
+ $filtered_data[$placeholder] = $value;
+ Log::info('学员字段通过过滤', [
+ 'placeholder' => $placeholder,
+ 'sign_party' => $sign_party,
+ 'value' => $value
+ ]);
+ } else {
+ Log::warning('学员字段被过滤', [
+ 'placeholder' => $placeholder,
+ 'sign_party' => $sign_party,
+ 'reason' => '学员只能填写乙方字段'
+ ]);
+ }
+ } else {
+ // 如果没有找到配置,保守处理:允许提交但记录警告
+ $filtered_data[$placeholder] = $value;
+ Log::warning('未找到字段配置,默认允许', [
+ 'placeholder' => $placeholder,
+ 'value' => $value
+ ]);
+ }
+ }
+
+ Log::info('学员表单数据过滤完成', [
+ 'original_count' => count($form_data),
+ 'filtered_count' => count($filtered_data)
+ ]);
+
+ return $filtered_data;
+
+ } catch (\Exception $e) {
+ Log::error('过滤学员表单数据失败', [
+ 'contract_id' => $contract_id,
+ 'contract_sign_id' => $contract_sign_id,
+ 'error' => $e->getMessage()
+ ]);
+ // 出现异常时返回原始数据,避免阻断流程
+ return $form_data;
+ }
+ }
+
+ /**
+ * 更新合同签署记录状态
+ *
+ * @param int $contract_sign_id 合同签署记录ID
+ * @param int|null $personnel_id 员工ID(员工签署时传入)
+ * @param string $signature_image 签名图片
+ * @param int|null $student_id 学员ID(学员签署时传入)
+ * @return bool
+ */
+ private function updateContractSignStatus($contract_sign_id, $personnel_id = null, $signature_image = '', $student_id = null)
+ {
+ try {
+ $now = date('Y-m-d H:i:s');
+
+ $update_data = [
+ 'sign_status' => 1, // 已签署
+ 'sign_time' => $now,
+ 'updated_at' => $now
+ ];
+
+ // 如果是员工签署,记录员工ID
+ if ($personnel_id) {
+ $update_data['personnel_id'] = $personnel_id;
+ $update_data['signed_by'] = 'staff';
+ }
+
+ // 如果是学员签署,确保学员ID正确
+ if ($student_id) {
+ $update_data['signed_by'] = 'student';
+ }
+
+ // 如果有签名图片,保存签名图片路径
+ if (!empty($signature_image)) {
+ $update_data['signature_image'] = $signature_image;
+ }
+
+ $result = Db::table('school_contract_sign')
+ ->where('id', $contract_sign_id)
+ ->update($update_data);
+
+ if ($result) {
+ Log::info('合同签署记录状态更新成功', [
+ 'contract_sign_id' => $contract_sign_id,
+ 'personnel_id' => $personnel_id,
+ 'student_id' => $student_id,
+ 'signature_image_length' => strlen($signature_image)
+ ]);
+ return true;
+ } else {
+ Log::warning('合同签署记录状态更新失败', [
+ 'contract_sign_id' => $contract_sign_id,
+ 'update_data' => $update_data
+ ]);
+ return false;
+ }
+
+ } catch (\Exception $e) {
+ Log::error('更新合同签署记录状态失败', [
+ 'contract_sign_id' => $contract_sign_id,
+ 'personnel_id' => $personnel_id,
+ 'student_id' => $student_id,
+ 'error' => $e->getMessage()
+ ]);
+ throw $e;
+ }
+ }
}
\ No newline at end of file
diff --git a/uniapp/api/apiRoute.js b/uniapp/api/apiRoute.js
index a9bd79fd..5d743035 100644
--- a/uniapp/api/apiRoute.js
+++ b/uniapp/api/apiRoute.js
@@ -1757,9 +1757,12 @@ export default {
// 获取学员基本信息
async getStudentInfo(data = {}) {
- return await http.get('/student/student-info', {
- student_id: data.student_id,
- })
+ return await http.get(`/student/info/${data.student_id}`)
+ },
+
+ // 获取当前用户的学员列表
+ async getMyStudentList() {
+ return await http.get('/student/mychild')
},
// 获取学员基本信息
@@ -2167,7 +2170,7 @@ export default {
keyword: data.keyword,
is_read: data.is_read,
}
- const response = await http.get(`/message-test/list/${data.student_id}`, params)
+ const response = await http.get(`/message/list/${data.student_id}`, params)
return response
} catch (error) {
console.error('获取学员消息列表错误:', error)
@@ -2182,7 +2185,7 @@ export default {
const params = {
student_id: data.student_id,
}
- const response = await http.get(`/message-test/detail/${data.message_id}`, params)
+ const response = await http.get(`/message/detail/${data.message_id}`, params)
return response
} catch (error) {
console.error('获取消息详情错误:', error)
@@ -2194,7 +2197,7 @@ export default {
// 标记消息已读
async markStudentMessageRead(data = {}) {
try {
- const response = await http.post('/message-test/mark-read', {
+ const response = await http.post('/message/mark-read', {
message_id: data.message_id,
student_id: data.student_id,
})
@@ -2213,7 +2216,7 @@ export default {
// 批量标记消息已读
async markStudentMessageBatchRead(data = {}) {
try {
- const response = await http.post('/message-test/mark-batch-read', {
+ const response = await http.post('/message/mark-batch-read', {
student_id: data.student_id,
message_ids: data.message_ids,
message_type: data.message_type,
@@ -2233,7 +2236,7 @@ export default {
// 获取学员消息统计
async getStudentMessageStats(data = {}) {
try {
- const response = await http.get(`/message-test/stats/${data.student_id}`)
+ const response = await http.get(`/message/stats/${data.student_id}`)
return response
} catch (error) {
console.error('获取消息统计错误:', error)
@@ -2252,7 +2255,7 @@ export default {
page: data.page || 1,
limit: data.limit || 20,
}
- const response = await http.get('/message-test/conversation', params)
+ const response = await http.get('/message/conversation', params)
return response
} catch (error) {
console.error('获取对话消息错误:', error)
@@ -2275,7 +2278,7 @@ export default {
// 学员回复消息
async replyMessage(data = {}) {
try {
- const response = await http.post('/message-test/reply', {
+ const response = await http.post('/message/reply', {
student_id: data.student_id,
to_type: data.to_type,
to_id: data.to_id,
@@ -2314,7 +2317,7 @@ export default {
page: data.page || 1,
limit: data.limit || 10,
}
- const response = await http.get(`/message-test/search/${data.student_id}`, params)
+ const response = await http.get(`/message/search/${data.student_id}`, params)
return response
} catch (error) {
console.error('搜索消息错误:', error)
diff --git a/uniapp/api/member.js b/uniapp/api/member.js
index 4c88af67..cf760614 100644
--- a/uniapp/api/member.js
+++ b/uniapp/api/member.js
@@ -28,15 +28,34 @@ export default {
return await http.post('/student/avatar', data);
},
- // 获取未读消息数量(如果有接口的话,暂时模拟)
- async getUnreadMessageCount(data = {}) {
- // 这里可以调用真实的消息接口,暂时返回模拟数据
- return {
- code: 1,
- data: {
- unread_count: Math.floor(Math.random() * 5)
+ // 获取未读消息数量
+ async getUnreadMessageCount(studentId) {
+ try {
+ if (!studentId) {
+ throw new Error('学员ID不能为空')
}
- };
+ // 调用消息统计API
+ const response = await http.get(`/message/stats/${studentId}`)
+ if (response && response.code === 1) {
+ return {
+ code: 1,
+ data: {
+ unread_count: response.data.unread_messages || 0
+ }
+ }
+ } else {
+ throw new Error(response?.msg || 'API调用失败')
+ }
+ } catch (error) {
+ console.error('获取未读消息数量失败:', error)
+ // 降级到0未读消息
+ return {
+ code: 1,
+ data: {
+ unread_count: 0
+ }
+ }
+ }
},
//↓↓↓↓↓↓↓↓↓↓↓↓-----体测数据管理接口-----↓↓↓↓↓↓↓↓↓↓↓↓
diff --git a/uniapp/common/config.js b/uniapp/common/config.js
index c98a2253..2459f37b 100644
--- a/uniapp/common/config.js
+++ b/uniapp/common/config.js
@@ -1,6 +1,6 @@
// 环境变量配置
-const env = 'development'
-// const env = 'prod'
+// const env = 'development'
+const env = 'prod'
const isMockEnabled = false // 默认禁用Mock优先模式,仅作为回退
const isDebug = false // 默认启用调试模式
const devurl = 'http://localhost:20080/api'
diff --git a/uniapp/pages-market/clue/clue_info.vue b/uniapp/pages-market/clue/clue_info.vue
index af2cbe4c..b7bb25ba 100644
--- a/uniapp/pages-market/clue/clue_info.vue
+++ b/uniapp/pages-market/clue/clue_info.vue
@@ -1596,7 +1596,7 @@ ${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 + '合同')}`
+ let url = `/pages-student/contracts/sign?contract_id=${contractId}&student_id=${studentId}&contract_name=${encodeURIComponent(order.product_name + '合同')}&user_role=staff`
// 如果有合同签署记录ID,也传递过去(用于已存在的签署记录)
if (contractSignId) {
@@ -1626,7 +1626,7 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
const contractInfo = res.data
// 跳转到合同签署页面
uni.navigateTo({
- url: `/pages-student/contracts/sign?contract_id=${contractInfo.contract_id}&student_id=${studentId}&contract_name=${encodeURIComponent(contractInfo.contract_name || order.product_name + '合同')}`
+ url: `/pages-student/contracts/sign?contract_id=${contractInfo.contract_id}&student_id=${studentId}&contract_name=${encodeURIComponent(contractInfo.contract_name || order.product_name + '合同')}&user_role=staff`
})
} else {
uni.showToast({
diff --git a/uniapp/pages-student/contracts/sign.vue b/uniapp/pages-student/contracts/sign.vue
index f5045954..d2b5c88b 100644
--- a/uniapp/pages-student/contracts/sign.vue
+++ b/uniapp/pages-student/contracts/sign.vue
@@ -36,13 +36,17 @@
请填写以下信息
{{ field.name }}
*
+
+ {{ getPartyLabel(field) }}
+
@@ -85,8 +89,8 @@
type="text"
:placeholder="field.placeholder || '请输入' + field.name"
v-model="formData[field.placeholder]"
- :disabled="field.data_type !== 'user_input'"
- :class="field.data_type !== 'user_input' ? 'disabled' : ''"
+ :disabled="!canEditField(field)"
+ :class="!canEditField(field) ? 'disabled' : ''"
/>
@@ -115,8 +119,8 @@
type="number"
:placeholder="field.placeholder || '请输入' + field.name"
v-model="formData[field.placeholder]"
- :disabled="field.data_type !== 'user_input'"
- :class="field.data_type !== 'user_input' ? 'disabled' : ''"
+ :disabled="!canEditField(field)"
+ :class="!canEditField(field) ? 'disabled' : ''"
/>
@@ -125,8 +129,8 @@
@@ -176,11 +180,38 @@
formFields: [],
formData: {},
loading: true,
- submitting: false
+ submitting: false,
+ // 角色和权限控制
+ userInfo: null,
+ userRole: 'student', // 默认为学生角色
+ isStaffMode: false
}
},
computed: {
+ // 检查当前用户是否为员工
+ isStaff() {
+ return this.userRole === 'staff' || this.isStaffMode
+ },
+
+ // 根据角色过滤表单字段
+ filteredFormFields() {
+ if (!this.formFields || this.formFields.length === 0) {
+ return []
+ }
+
+ // 员工可以填写所有字段
+ if (this.isStaff) {
+ return this.formFields
+ }
+
+ // 学生只能填写乙方字段
+ return this.formFields.filter(field => {
+ const signParty = field.sign_party || ''
+ return signParty === 'second_party' || signParty === 'party_b' || signParty === '乙方'
+ })
+ },
+
// 渲染合同内容,替换占位符为实际值
renderContractContent() {
if (!this.contractContent) return ''
@@ -268,6 +299,13 @@
// 新增:支持合同签署记录ID(用于已存在的签署记录)
this.contractSignId = parseInt(options.contract_sign_id) || 0
+ // 角色检测
+ this.userRole = options.user_role || 'student'
+ this.isStaffMode = options.user_role === 'staff'
+
+ // 获取用户信息进行角色验证
+ this.getUserInfo()
+
if (this.contractId && this.studentId) {
this.loadSignForm()
} else {
@@ -298,6 +336,82 @@
uni.navigateBack()
},
+ // 获取用户信息
+ getUserInfo() {
+ try {
+ const userInfo = uni.getStorageSync('userInfo')
+ if (userInfo) {
+ this.userInfo = JSON.parse(userInfo)
+ // 如果缓存的用户类型与URL参数不符,以URL参数为准
+ if (this.userInfo.user_type && this.userRole === 'student') {
+ this.userRole = this.userInfo.user_type === 'staff' ? 'staff' : 'student'
+ this.isStaffMode = this.userRole === 'staff'
+ }
+ }
+ } catch (error) {
+ console.error('获取用户信息失败:', error)
+ }
+ },
+
+ // 检查字段是否可编辑
+ canEditField(field) {
+ // 非用户输入类型的字段都不可编辑
+ if (field.data_type !== 'user_input') {
+ return false
+ }
+
+ // 员工可以编辑所有用户输入字段
+ if (this.isStaff) {
+ return true
+ }
+
+ // 学生只能编辑乙方字段
+ const signParty = field.sign_party || ''
+ return signParty === 'second_party' || signParty === 'party_b' || signParty === '乙方'
+ },
+
+ // 获取字段样式类
+ getFieldClass(field) {
+ const classes = []
+
+ if (this.isStaff) {
+ const signParty = field.sign_party || ''
+ if (signParty === 'first_party' || signParty === 'party_a' || signParty === '甲方') {
+ classes.push('first_party_field')
+ } else if (signParty === 'second_party' || signParty === 'party_b' || signParty === '乙方') {
+ classes.push('second_party_field')
+ }
+ }
+
+ if (!this.canEditField(field)) {
+ classes.push('readonly_field')
+ }
+
+ return classes.join(' ')
+ },
+
+ // 获取甲乙方标签样式类
+ getPartyClass(field) {
+ const signParty = field.sign_party || ''
+ if (signParty === 'first_party' || signParty === 'party_a' || signParty === '甲方') {
+ return 'party_first'
+ } else if (signParty === 'second_party' || signParty === 'party_b' || signParty === '乙方') {
+ return 'party_second'
+ }
+ return 'party_unknown'
+ },
+
+ // 获取甲乙方标签文本
+ getPartyLabel(field) {
+ const signParty = field.sign_party || ''
+ if (signParty === 'first_party' || signParty === 'party_a' || signParty === '甲方') {
+ return '甲方'
+ } else if (signParty === 'second_party' || signParty === 'party_b' || signParty === '乙方') {
+ return '乙方'
+ }
+ return '未知'
+ },
+
async loadSignForm() {
this.loading = true
try {
@@ -517,12 +631,24 @@
formData: this.formData
})
- // 提交签署数据
- const response = await apiRoute.signStudentContract({
- contract_id: this.contractId,
- student_id: this.studentId,
- form_data: this.formData
- })
+ // 根据角色提交签署数据
+ let response
+ if (this.isStaff) {
+ // 员工端签署
+ response = await apiRoute.signStaffContract({
+ contract_id: this.contractId,
+ student_id: this.studentId,
+ form_data: this.formData,
+ personnel_id: this.userInfo?.id || 0
+ })
+ } else {
+ // 学生端签署
+ response = await apiRoute.signStudentContract({
+ contract_id: this.contractId,
+ student_id: this.studentId,
+ form_data: this.formData
+ })
+ }
if (response.code === 1) {
uni.showToast({
@@ -863,6 +989,72 @@
100% { transform: rotate(360deg); }
}
+// 甲乙方标识和字段样式
+.party_indicator {
+ display: inline-flex;
+ align-items: center;
+ margin-left: 12rpx;
+
+ .party_tag {
+ font-size: 20rpx;
+ padding: 4rpx 8rpx;
+ border-radius: 6rpx;
+ font-weight: 500;
+
+ &.party_first {
+ background: rgba(255, 152, 0, 0.1);
+ color: #ff9800;
+ border: 1rpx solid rgba(255, 152, 0, 0.3);
+ }
+
+ &.party_second {
+ background: rgba(76, 175, 80, 0.1);
+ color: #4caf50;
+ border: 1rpx solid rgba(76, 175, 80, 0.3);
+ }
+
+ &.party_unknown {
+ background: rgba(158, 158, 158, 0.1);
+ color: #9e9e9e;
+ border: 1rpx solid rgba(158, 158, 158, 0.3);
+ }
+ }
+}
+
+// 字段样式区分
+.form_field {
+ &.first_party_field {
+ border-left: 4rpx solid #ff9800;
+ background: linear-gradient(90deg, rgba(255, 152, 0, 0.02) 0%, transparent 100%);
+
+ .field_label {
+ color: #e65100;
+ }
+ }
+
+ &.second_party_field {
+ border-left: 4rpx solid #4caf50;
+ background: linear-gradient(90deg, rgba(76, 175, 80, 0.02) 0%, transparent 100%);
+
+ .field_label {
+ color: #2e7d32;
+ }
+ }
+
+ &.readonly_field {
+ background: #f8f9fa;
+
+ .field_label {
+ color: #6c757d;
+ }
+
+ input, textarea {
+ background: #f8f9fa !important;
+ color: #6c757d !important;
+ }
+ }
+}
+
// 提交按钮
.submit_section {
position: fixed;
diff --git a/uniapp/pages-student/messages/index.vue b/uniapp/pages-student/messages/index.vue
index 7c388485..87098735 100644
--- a/uniapp/pages-student/messages/index.vue
+++ b/uniapp/pages-student/messages/index.vue
@@ -228,9 +228,9 @@
{ value: 'all', text: '全部', count: 0 },
{ value: 'system', text: '系统消息', count: 0 },
{ value: 'notification', text: '通知公告', count: 0 },
- { value: 'homework', text: '作业任务', count: 0 },
- { value: 'feedback', text: '反馈评价', count: 0 },
- { value: 'reminder', text: '课程提醒', count: 0 }
+ // { value: 'homework', text: '作业任务', count: 0 },
+ // { value: 'feedback', text: '反馈评价', count: 0 },
+ // { value: 'reminder', text: '课程提醒', count: 0 }
]
}
},
@@ -241,12 +241,12 @@
}
},
- onLoad(options) {
+ async onLoad(options) {
// 使用本地缓存的用户信息而不是页面参数
const userInfo = uni.getStorageSync('userInfo')
if (userInfo && userInfo.id) {
- this.studentId = parseInt(userInfo.id)
- this.initPage()
+ // userInfo.id 是会员ID,需要查找对应的学员ID
+ await this.findStudentIdByMemberId(parseInt(userInfo.id))
} else {
// 如果没有用户信息,尝试使用页面参数作为备用
this.studentId = parseInt(options.student_id) || 0
@@ -267,6 +267,33 @@
uni.navigateBack()
},
+ async findStudentIdByMemberId(memberId) {
+ try {
+ console.log('查找会员ID对应的学员ID:', memberId)
+
+ // 调用API获取当前用户的学员列表
+ const response = await apiRoute.getMyStudentList()
+
+ if (response && response.code === 1 && response.data && response.data.list && response.data.list.length > 0) {
+ // 使用第一个学员作为当前学员(通常家长账号下只有一个学员)
+ const firstStudent = response.data.list[0]
+ this.studentId = firstStudent.id || firstStudent.student_id
+ console.log('找到学员ID:', this.studentId, '学员姓名:', firstStudent.name)
+ this.initPage()
+ } else {
+ console.warn('当前用户没有关联的学员,使用会员ID作为学员ID')
+ // 降级处理,使用会员ID作为学员ID
+ this.studentId = memberId
+ this.initPage()
+ }
+ } catch (error) {
+ console.error('查找学员ID失败:', error)
+ // 降级处理,使用会员ID作为学员ID
+ this.studentId = memberId
+ this.initPage()
+ }
+ },
+
async initPage() {
await this.loadStudentInfo()
await this.loadMessages()
@@ -275,14 +302,37 @@
async loadStudentInfo() {
try {
- // 模拟获取学员信息
- const mockStudentInfo = {
- id: this.studentId,
- name: '小明'
+ console.log('加载学员信息:', this.studentId)
+
+ // 调用真实API获取学员信息
+ const response = await apiRoute.getStudentInfo({
+ student_id: this.studentId
+ })
+
+ if (response && response.code === 1 && response.data && response.data.student_info) {
+ this.studentInfo = {
+ id: response.data.student_info.id,
+ name: response.data.student_info.name,
+ gender_text: response.data.student_info.gender_text,
+ birthday: response.data.student_info.birthday,
+ headimg: response.data.student_info.headimg
+ }
+ console.log('学员信息加载成功:', this.studentInfo)
+ } else {
+ console.warn('API返回失败,使用Mock数据:', response?.msg)
+ // 降级到Mock数据
+ this.studentInfo = {
+ id: this.studentId,
+ name: '学员'
+ }
}
- this.studentInfo = mockStudentInfo
} catch (error) {
console.error('获取学员信息失败:', error)
+ // 网络错误时降级到Mock数据
+ this.studentInfo = {
+ id: this.studentId,
+ name: '学员'
+ }
}
},
@@ -845,12 +895,13 @@
.search_box {
.search_input {
width: 100%;
- padding: 16rpx 20rpx;
+ padding: 16rpx;
border: 1px solid #e0e0e0;
border-radius: 8rpx;
font-size: 28rpx;
background: #f8f9fa;
margin-bottom: 16rpx;
+ height: 60rpx;
&::placeholder {
color: #999;
diff --git a/uniapp/pages/student/home/index.vue b/uniapp/pages/student/home/index.vue
index 54e36aef..193ea37e 100644
--- a/uniapp/pages/student/home/index.vue
+++ b/uniapp/pages/student/home/index.vue
@@ -216,12 +216,14 @@
this.setCurrentWeekDay()
await this.loadUserInfo()
await this.loadStudentList()
- this.loadUnreadMessageCount()
+ // 在学员信息加载完成后再获取未读消息数量
+ await this.loadUnreadMessageCount()
},
async refreshData() {
await this.loadStudentList()
- this.loadUnreadMessageCount()
+ // 在学员信息加载完成后再获取未读消息数量
+ await this.loadUnreadMessageCount()
},
setCurrentWeekDay() {
@@ -307,8 +309,18 @@
async loadUnreadMessageCount() {
try {
+ // 需要学员ID才能获取未读消息数量
+ if (!this.selectedStudent || !this.selectedStudent.id) {
+ console.warn('没有选中的学员,无法获取未读消息数量')
+ this.unreadCount = 0
+ return
+ }
+
+ const studentId = this.selectedStudent.student_id || this.selectedStudent.id
+ console.log('获取学员未读消息数量:', studentId)
+
// 调用真实API获取未读消息数量
- const response = await apiRoute.getUnreadMessageCount()
+ const response = await apiRoute.getUnreadMessageCount(studentId)
console.log('未读消息数量API响应:', response)
if (response.code === 1) {