From 4ad6b5e0c8859290aa46825cba0e32129aceecad Mon Sep 17 00:00:00 2001
From: zeyan <258785420@qq.com>
Date: Sat, 16 Aug 2025 01:47:58 +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
---
admin/src/app/api/salary.ts | 2 +-
.../views/salary/components/salary-edit.vue | 2 +-
admin/src/app/views/salary/list.vue | 25 ++++-
admin/src/components/direct-upload/index.vue | 8 +-
admin/src/utils/directUpload.ts | 94 ++++++++++++++++++-
.../LessonCourseTeaching.php | 3 +-
niucloud/app/adminapi/route/sys.php | 2 +
.../LessonCourseTeachingService.php | 8 +-
.../admin/upload/DirectUploadService.php | 28 ++++--
9 files changed, 149 insertions(+), 23 deletions(-)
diff --git a/admin/src/app/api/salary.ts b/admin/src/app/api/salary.ts
index 0ea2d149..4844c27a 100644
--- a/admin/src/app/api/salary.ts
+++ b/admin/src/app/api/salary.ts
@@ -123,7 +123,7 @@ export const getStatisticsTrend = (params: { months?: number; campus_id?: number
// 获取员工列表
export const getPersonnelList = () => {
- return request.get('/personnel/list')
+ return request.get('/lesson_course_teaching/personnel_data_all',{params:{is_all:1}})
}
// 获取校区列表
diff --git a/admin/src/app/views/salary/components/salary-edit.vue b/admin/src/app/views/salary/components/salary-edit.vue
index 18c5563a..5fbb202d 100644
--- a/admin/src/app/views/salary/components/salary-edit.vue
+++ b/admin/src/app/views/salary/components/salary-edit.vue
@@ -45,7 +45,7 @@
diff --git a/admin/src/app/views/salary/list.vue b/admin/src/app/views/salary/list.vue
index 9d655481..7e896a78 100644
--- a/admin/src/app/views/salary/list.vue
+++ b/admin/src/app/views/salary/list.vue
@@ -29,7 +29,7 @@
@@ -223,6 +223,7 @@ import {
type QueryParams,
type SalaryItem
} from '@/app/api/salary'
+
import SalaryEdit from './components/salary-edit.vue'
import SalaryDetail from './components/salary-detail.vue'
@@ -275,7 +276,27 @@ const loadTableData = async () => {
loading.value = true
try {
const res = await getSalaryList(queryParams)
- tableData.value = res.data.list
+
+ // 修正数据结构访问路径
+ const rawData = res.data.data || []
+
+ // 数据类型转换处理
+ tableData.value = rawData.map((item: any) => ({
+ ...item,
+ base_salary: Number(item.base_salary) || 0,
+ work_salary: Number(item.work_salary) || 0,
+ mgr_performance: Number(item.mgr_performance) || 0,
+ performance_bonus: Number(item.performance_bonus) || 0,
+ other_subsidies: Number(item.other_subsidies) || 0,
+ deductions: Number(item.deductions) || 0,
+ gross_salary: Number(item.gross_salary) || 0,
+ social_security: Number(item.social_security) || 0,
+ individual_income_tax: Number(item.individual_income_tax) || 0,
+ net_salary: Number(item.net_salary) || 0,
+ attendance: Number(item.attendance) || 0,
+ full_attendance_days: Number(item.full_attendance_days) || 0
+ }))
+
total.value = res.data.total
} catch (error) {
console.error('加载数据失败:', error)
diff --git a/admin/src/components/direct-upload/index.vue b/admin/src/components/direct-upload/index.vue
index 15883040..c2ec5d15 100644
--- a/admin/src/components/direct-upload/index.vue
+++ b/admin/src/components/direct-upload/index.vue
@@ -139,7 +139,7 @@ const handleFileChange = async (uploadFile: UploadFile) => {
/**
* 直传上传
*/
-const handleDirectUpload = async (file: File, uploadFile: UploadFile) => {
+const handleDirectUpload = async (file: File, uploadFileObj: UploadFile) => {
const result = await uploadFile({
file,
fileType: props.fileType,
@@ -151,7 +151,7 @@ const handleDirectUpload = async (file: File, uploadFile: UploadFile) => {
if (result.success) {
ElMessage.success('上传成功')
- emit('success', result.url, uploadFile)
+ emit('success', result.url, uploadFileObj)
} else {
throw new Error(result.error || '上传失败')
}
@@ -160,7 +160,7 @@ const handleDirectUpload = async (file: File, uploadFile: UploadFile) => {
/**
* 后备上传(传统方式)
*/
-const handleFallbackUpload = async (file: File, uploadFile: UploadFile) => {
+const handleFallbackUpload = async (file: File, uploadFileObj: UploadFile) => {
if (!props.fallbackUrl) {
throw new Error('直传不可用且未配置后备上传接口')
}
@@ -186,7 +186,7 @@ const handleFallbackUpload = async (file: File, uploadFile: UploadFile) => {
const response = JSON.parse(xhr.responseText)
if (response.code === 1) {
ElMessage.success('上传成功')
- emit('success', response.data.url, uploadFile)
+ emit('success', response.data.url, uploadFileObj)
resolve()
} else {
reject(new Error(response.msg || '上传失败'))
diff --git a/admin/src/utils/directUpload.ts b/admin/src/utils/directUpload.ts
index ade06c20..f7e71b29 100644
--- a/admin/src/utils/directUpload.ts
+++ b/admin/src/utils/directUpload.ts
@@ -119,13 +119,38 @@ export class DirectUpload {
file: File,
credentials: UploadCredentials,
onProgress?: (percent: number) => void
+ ): Promise {
+ return new Promise(async (resolve, reject) => {
+ const filePath = credentials.file_path.replace('${filename}', file.name)
+
+ // 尝试直传,如果CORS失败则使用代理
+ try {
+ const directResult = await this.directUploadToTencent(file, credentials, filePath, onProgress)
+ resolve(directResult)
+ } catch (error) {
+ console.warn('Direct upload failed, trying proxy:', error)
+ try {
+ const proxyResult = await this.proxyUploadToTencent(file, credentials, filePath, onProgress)
+ resolve(proxyResult)
+ } catch (proxyError) {
+ reject(proxyError)
+ }
+ }
+ })
+ }
+
+ /**
+ * 腾讯云COS直接上传
+ */
+ private async directUploadToTencent(
+ file: File,
+ credentials: UploadCredentials,
+ filePath: string,
+ onProgress?: (percent: number) => void
): Promise {
return new Promise((resolve, reject) => {
const formData = new FormData()
- // 生成文件路径(替换模板中的${filename})
- const filePath = credentials.file_path.replace('${filename}', file.name)
-
// 添加腾讯云COS必需的字段
formData.append('key', filePath)
formData.append('policy', credentials.credentials.policy)
@@ -171,6 +196,69 @@ export class DirectUpload {
})
}
+ /**
+ * 腾讯云COS代理上传(开发环境临时方案)
+ */
+ private async proxyUploadToTencent(
+ file: File,
+ credentials: UploadCredentials,
+ filePath: string,
+ onProgress?: (percent: number) => void
+ ): Promise {
+ return new Promise((resolve, reject) => {
+ const formData = new FormData()
+
+ // 添加后端代理需要的参数(分别发送各个字段,避免JSON解析问题)
+ formData.append('upload_url', credentials.upload_url)
+ formData.append('key', filePath)
+ formData.append('policy', credentials.credentials.policy)
+ formData.append('q-sign-algorithm', credentials.credentials['q-sign-algorithm'])
+ formData.append('q-ak', credentials.credentials['q-ak'])
+ formData.append('q-key-time', credentials.credentials['q-key-time'])
+ formData.append('q-signature', credentials.credentials['q-signature'])
+ formData.append('domain', credentials.domain)
+ formData.append('file', file)
+
+ const xhr = new XMLHttpRequest()
+
+ // 上传进度
+ if (onProgress) {
+ xhr.upload.addEventListener('progress', (event) => {
+ if (event.lengthComputable) {
+ const percent = Math.round((event.loaded / event.total) * 100)
+ onProgress(percent)
+ }
+ })
+ }
+
+ // 上传完成
+ xhr.addEventListener('load', () => {
+ try {
+ const response = JSON.parse(xhr.responseText)
+ if (response.code === 1) {
+ resolve({
+ success: true,
+ url: response.data.url
+ })
+ } else {
+ reject(new Error(response.msg || '上传失败'))
+ }
+ } catch (error) {
+ reject(new Error('响应解析失败'))
+ }
+ })
+
+ // 上传错误
+ xhr.addEventListener('error', () => {
+ reject(new Error('网络错误,上传失败'))
+ })
+
+ // 执行代理上传
+ xhr.open('POST', `${this.baseUrl}/adminapi/sys/direct/cos_proxy`, true)
+ xhr.send(formData)
+ })
+ }
+
/**
* 阿里云OSS直传
*/
diff --git a/niucloud/app/adminapi/controller/lesson_course_teaching/LessonCourseTeaching.php b/niucloud/app/adminapi/controller/lesson_course_teaching/LessonCourseTeaching.php
index 0ab918d7..d92792f5 100644
--- a/niucloud/app/adminapi/controller/lesson_course_teaching/LessonCourseTeaching.php
+++ b/niucloud/app/adminapi/controller/lesson_course_teaching/LessonCourseTeaching.php
@@ -756,7 +756,8 @@ class LessonCourseTeaching extends BaseAdminController
["name",""],
["phone",""],
["role_id",""],
- ["dept_id",""]
+ ["dept_id",""],
+ ['is_all',""]
]);
return success((new LessonCourseTeachingService())->getPersonnelDataAll($data));
}
diff --git a/niucloud/app/adminapi/route/sys.php b/niucloud/app/adminapi/route/sys.php
index 3a57de1d..24239852 100644
--- a/niucloud/app/adminapi/route/sys.php
+++ b/niucloud/app/adminapi/route/sys.php
@@ -333,6 +333,8 @@ Route::group('sys', function() {
Route::get('direct/credentials', 'upload.DirectUpload/getUploadCredentials');
//确认上传完成
Route::post('direct/confirm', 'upload.DirectUpload/confirmUpload');
+ //COS代理上传(开发环境临时方案)
+ Route::post('direct/cos_proxy', 'upload.CosProxy/proxyUpload');
//附件列表
Route::get('attachment', 'sys.Attachment/lists');
diff --git a/niucloud/app/service/admin/lesson_course_teaching/LessonCourseTeachingService.php b/niucloud/app/service/admin/lesson_course_teaching/LessonCourseTeachingService.php
index ad5822da..76160cdf 100644
--- a/niucloud/app/service/admin/lesson_course_teaching/LessonCourseTeachingService.php
+++ b/niucloud/app/service/admin/lesson_course_teaching/LessonCourseTeachingService.php
@@ -734,8 +734,12 @@ class LessonCourseTeachingService extends BaseAdminService
->where($whereArr)
->group("a.id")
->order($order);
-
- $list = $this->pageQuery($search_model);
+ if ($where['is_all']){
+ $list = $search_model->select()->toArray();
+ }else{
+ $list = $this->pageQuery($search_model);
+ }
+
return $list;
}
diff --git a/niucloud/app/service/admin/upload/DirectUploadService.php b/niucloud/app/service/admin/upload/DirectUploadService.php
index 26d3be16..578fa89b 100644
--- a/niucloud/app/service/admin/upload/DirectUploadService.php
+++ b/niucloud/app/service/admin/upload/DirectUploadService.php
@@ -85,13 +85,20 @@ class DirectUploadService extends BaseAdminService
}
}
- // 生成策略
- $expired = time() + 3600; // 1小时过期
+ $current_time = time();
+ $expired = $current_time + 3600; // 1小时过期
+ $key_time = $current_time . ';' . $expired;
+
+ // 生成POST策略 (腾讯云COS对象格式)
$policy = [
'expiration' => gmdate('Y-m-d\TH:i:s.000\Z', $expired),
'conditions' => [
- ['bucket' => $config['bucket']],
- ['starts-with' => '$key', $file_path]
+ // key路径限制 - starts-with格式
+ ['starts-with', '$key', dirname($file_path) . '/'],
+ // 签名字段 - 对象格式 (腾讯云COS要求)
+ ['$q-sign-algorithm' => 'sha1'],
+ ['$q-ak' => $config['access_key']],
+ ['$q-key-time' => $key_time]
]
];
@@ -101,9 +108,12 @@ class DirectUploadService extends BaseAdminService
$policy['conditions'][] = ['content-length-range', 0, $max_size];
}
- $policy_encoded = base64_encode(json_encode($policy));
- $signature = hash_hmac('sha1', $policy_encoded, $config['secret_key'], true);
- $signature_encoded = base64_encode($signature);
+ $policy_encoded = base64_encode(json_encode($policy, JSON_UNESCAPED_SLASHES));
+
+ // 腾讯云COS POST签名算法
+ $sign_key = hash_hmac('sha1', $key_time, $config['secret_key']);
+ $string_to_sign = $policy_encoded;
+ $signature = hash_hmac('sha1', $string_to_sign, $sign_key);
return [
'storage_type' => 'tencent',
@@ -112,8 +122,8 @@ class DirectUploadService extends BaseAdminService
'policy' => $policy_encoded,
'q-sign-algorithm' => 'sha1',
'q-ak' => $config['access_key'],
- 'q-key-time' => time() . ';' . $expired,
- 'q-signature' => $signature_encoded,
+ 'q-key-time' => $key_time,
+ 'q-signature' => $signature,
],
'file_path' => $file_path,
'domain' => $config['domain'] ?? "https://{$config['bucket']}.cos.{$config['region']}.myqcloud.com",