From a3d57d370d038fc0d9b088963ba9c1ff65b1ba9a Mon Sep 17 00:00:00 2001
From: zeyan <258785420@qq.com>
Date: Mon, 18 Aug 2025 12:23:20 +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
---
.../components/course-arrangement-detail.vue | 106 ++++++++++++------
.../components/student-action-menu.vue | 6 +-
docker-compose.yml | 13 +++
.../api/apiService/OrderTableService.php | 7 +-
niucloud/core/upload/Tencent.php | 17 +--
uniapp/pages-market/clue/clue_info.vue | 2 +-
uniapp/pages-student/contracts/sign.vue | 2 +-
7 files changed, 100 insertions(+), 53 deletions(-)
diff --git a/admin/src/app/views/course_schedule/components/course-arrangement-detail.vue b/admin/src/app/views/course_schedule/components/course-arrangement-detail.vue
index a63cfe20..811d9cd5 100644
--- a/admin/src/app/views/course_schedule/components/course-arrangement-detail.vue
+++ b/admin/src/app/views/course_schedule/components/course-arrangement-detail.vue
@@ -43,6 +43,9 @@
:formal-has-empty="formalEmptySeats.length > 0"
@confirm-action="handleConfirmAction"
/>
+
+
+
@@ -61,6 +64,7 @@ import CourseInfoSection from './course-info-section.vue'
import StudentSection from './student-section.vue'
import StudentSearchModal from './student-search-modal.vue'
import StudentActionMenu from './student-action-menu.vue'
+import StudentDetailModal from './student-detail-modal.vue'
import type {
StudentInfo,
@@ -104,6 +108,9 @@ const currentSlot = ref({ type: 'formal', index: 1 })
const currentStudent = ref(null)
const presetStudent = ref(null)
+// 学员详情弹窗引用
+const studentDetailModalRef = ref()
+
// 暴露给父组件的方法
const open = (scheduleId: number, resourceId?: number, studentId?: number) => {
if (scheduleId) {
@@ -630,40 +637,59 @@ const handleCancelLeave = async (student: StudentInfo) => {
// 学员签到
const handleStudentCheckin = async (student: StudentInfo) => {
try {
- const statusOptions = [
- { label: '待上课', value: 0 },
- { label: '已签到', value: 1 },
- { label: '请假', value: 2 }
- ]
-
- const currentStatus = statusOptions.find(opt => opt.value === student.status)
+ const currentStatus = student.status === 1 ? '已签到' : student.status === 2 ? '请假' : '待上课'
- const { value: statusValue } = await ElMessageBox.prompt(
- `当前状态:${currentStatus?.label || '未知'}\n请选择新的签到状态:`,
- '更新签到状态',
- {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- inputPlaceholder: '请选择状态: 0-待上课, 1-已签到, 2-请假',
- inputPattern: /^[0-2]$/,
- inputErrorMessage: '请输入 0、1 或 2'
- }
- )
+ // 如果已经签到,询问是否取消签到
+ if (student.status === 1) {
+ const result = await ElMessageBox.confirm(
+ `学员 ${student.name} 当前状态:${currentStatus}\n\n确定要取消签到吗?`,
+ '取消签到确认',
+ {
+ confirmButtonText: '取消签到',
+ cancelButtonText: '保持现状',
+ type: 'warning'
+ }
+ )
+
+ if (result === 'confirm') {
+ const response = await updateStudentStatus({
+ schedule_id: scheduleInfo.value.id,
+ person_id: student.person_id || student.id,
+ status: 0, // 改为待上课
+ reason: '管理员取消签到'
+ })
- const newStatus = parseInt(statusValue)
-
- if (!isNaN(newStatus) && newStatus !== student.status && [0, 1, 2].includes(newStatus)) {
- const response = await updateStudentStatus({
- schedule_id: scheduleInfo.value.id,
- person_id: student.person_id || student.id,
- status: newStatus,
- reason: `签到状态更新为: ${statusOptions.find(opt => opt.value === newStatus)?.label}`
- })
+ if (response.code === 1) {
+ ElMessage.success('已取消签到状态')
+ } else {
+ ElMessage.error(response.msg || '取消签到失败')
+ }
+ }
+ } else {
+ // 其他状态,询问是否签到
+ const result = await ElMessageBox.confirm(
+ `学员 ${student.name} 当前状态:${currentStatus}\n\n确定要标记为已签到吗?`,
+ '签到确认',
+ {
+ confirmButtonText: '确认签到',
+ cancelButtonText: '取消',
+ type: 'info'
+ }
+ )
+
+ if (result === 'confirm') {
+ const response = await updateStudentStatus({
+ schedule_id: scheduleInfo.value.id,
+ person_id: student.person_id || student.id,
+ status: 1, // 标记为已签到
+ reason: '管理员确认签到'
+ })
- if (response.code === 1) {
- ElMessage.success('签到状态更新成功')
- } else {
- ElMessage.error(response.msg || '签到状态更新失败')
+ if (response.code === 1) {
+ ElMessage.success('签到成功')
+ } else {
+ ElMessage.error(response.msg || '签到失败')
+ }
}
}
} catch (error) {
@@ -677,10 +703,20 @@ const handleStudentCheckin = async (student: StudentInfo) => {
// 查看学员详情
const handleViewStudentDetails = async (student: StudentInfo) => {
try {
- // 这里可以打开学员详情页面或弹窗
- ElMessage.info('查看学员详情功能开发中')
- // TODO: 实现学员详情查看功能
- console.log('查看学员详情:', student)
+ // 从StudentInfo中获取student_id或person_id作为学员ID
+ const studentId = student.student_id || student.person_id || student.id
+
+ if (!studentId) {
+ ElMessage.warning('无法获取学员ID')
+ return
+ }
+
+ // 打开学员详情弹窗
+ if (studentDetailModalRef.value) {
+ await studentDetailModalRef.value.open(studentId)
+ } else {
+ ElMessage.error('学员详情组件未正确加载')
+ }
} catch (error) {
console.error('查看学员详情失败:', error)
ElMessage.error('查看学员详情失败')
diff --git a/admin/src/app/views/course_schedule/components/student-action-menu.vue b/admin/src/app/views/course_schedule/components/student-action-menu.vue
index 74428433..7e24ae30 100644
--- a/admin/src/app/views/course_schedule/components/student-action-menu.vue
+++ b/admin/src/app/views/course_schedule/components/student-action-menu.vue
@@ -136,8 +136,9 @@
升级到正式位
-
+
-
+
insert($insertData, true);
if ($result) {
- // 更新订单表的合同模板ID(来自课程配置)
- OrderTable::where('id', $orderData['id'])->update(['contract_id' => $course['contract_id']]);
+ // 更新订单表的合同模板ID和合同签署记录ID
+ OrderTable::where('id', $orderData['id'])->update([
+ 'contract_id' => $course['contract_id'], // 合同模板ID
+ 'contract_sign_id' => $result // 合同签署记录ID
+ ]);
// 创建签署记录成功后,为甲乙双方生成数据源配置记录
$this->createDocumentDataSourceConfig($course['contract_id'], $orderData);
diff --git a/niucloud/core/upload/Tencent.php b/niucloud/core/upload/Tencent.php
index f2cfc03a..20b86d44 100644
--- a/niucloud/core/upload/Tencent.php
+++ b/niucloud/core/upload/Tencent.php
@@ -42,10 +42,13 @@ class Tencent extends BaseUpload
return new Client(
array(
'region' => $region,
-// 'schema' => 'https', //协议头部,默认为http
+// 'schema' => 'https', // 强制使用HTTPS,避免签名问题
'credentials' => array(
'secretId' => $secret_id,
- 'secretKey' => $secret_key)
+ 'secretKey' => $secret_key),
+ // 添加调试和时间同步选项
+ 'timeout' => 60, // 增加超时时间
+ 'verify' => false // 在开发环境禁用SSL验证(仅开发用)
)
);
}
@@ -61,24 +64,14 @@ class Tencent extends BaseUpload
$this->validate();
$bucket = $this->config['bucket'];
try {
- // 临时关闭PHP警告,避免deprecated警告被当作异常
- $old_error_reporting = error_reporting(E_ERROR | E_PARSE);
-
$result = $this->client()->putObject(array(
'Bucket' => $bucket, //存储桶名称,由BucketName-Appid 组成,可以在COS控制台查看 https://console.tencentcloud.com/cos5/bucket
'Key' => $this->getFullPath($dir),
'Body' => fopen($this->getRealPath(), 'rb'),
));
-
- // 恢复错误报告级别
- error_reporting($old_error_reporting);
-
// 请求成功
return true;
} catch ( Exception $e ) {
- // 恢复错误报告级别
- error_reporting($old_error_reporting);
-
// 输出详细错误信息用于调试
error_log("Tencent COS Upload Error: " . $e->getMessage());
error_log("Tencent COS Config: " . json_encode($this->config));
diff --git a/uniapp/pages-market/clue/clue_info.vue b/uniapp/pages-market/clue/clue_info.vue
index 844e6bf3..61c2a2e2 100644
--- a/uniapp/pages-market/clue/clue_info.vue
+++ b/uniapp/pages-market/clue/clue_info.vue
@@ -1555,7 +1555,7 @@ ${orderInfo.paid_at ? '支付时间:' + this.formatOrderTime(orderInfo.paid_at
const isOrderPaid = order.status === 'paid'
const buttons = isOrderPaid ? ['知道了', '合同签署'] : ['知道了']
-
+ console.log('订单数据',order)
uni.showModal({
title: '订单详情',
content: detailText,
diff --git a/uniapp/pages-student/contracts/sign.vue b/uniapp/pages-student/contracts/sign.vue
index cfc058fa..0db54738 100644
--- a/uniapp/pages-student/contracts/sign.vue
+++ b/uniapp/pages-student/contracts/sign.vue
@@ -406,7 +406,7 @@
// 上传图片到服务器
const uploadResult = await new Promise((resolve, reject) => {
uni.uploadFile({
- url: Api_url + '/api/upload/image',
+ url: Api_url + '/file/image',
filePath: tempFilePath,
name: 'image',
header: {