From 7d7a4aa4d22737c01fa8d0578f214ff483126282 Mon Sep 17 00:00:00 2001 From: ShengLong <452591453@qq.com> Date: Fri, 8 May 2026 10:49:16 +0800 Subject: [PATCH] =?UTF-8?q?oss=20=E7=9B=B4=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 分片上传 --- admin/package-lock.json | 45 ++ admin/package.json | 1 + admin/src/api/file.ts | 47 ++ admin/src/api/tcm.ts | 15 +- admin/src/components/upload/index.vue | 76 ++- admin/src/utils/oss-direct-upload.ts | 142 ++++++ .../diagnosis/components/CallRecordPanel.vue | 178 +++++-- .../adminapi/controller/UploadController.php | 38 ++ .../controller/tcm/DiagnosisController.php | 18 + .../common/service/DirectUploadService.php | 150 ++++++ .../common/service/storage/engine/Qcloud.php | 122 +++++ server/composer.json | 1 + server/composer.lock | 60 ++- server/vendor/composer/InstalledVersions.php | 27 +- server/vendor/composer/autoload_psr4.php | 5 +- server/vendor/composer/autoload_static.php | 15 +- server/vendor/composer/installed.json | 55 +++ server/vendor/composer/installed.php | 21 +- server/vendor/composer/platform_check.php | 7 +- .../qcloud_sts/qcloud-sts-sdk/.gitignore | 7 + .../vendor/qcloud_sts/qcloud-sts-sdk/LICENSE | 21 + .../qcloud_sts/qcloud-sts-sdk/README.md | 110 +++++ .../qcloud_sts/qcloud-sts-sdk/composer.json | 28 ++ .../qcloud_sts/qcloud-sts-sdk/src/Scope.php | 59 +++ .../qcloud_sts/qcloud-sts-sdk/src/Sts.php | 466 ++++++++++++++++++ server/vendor/services.php | 2 +- 26 files changed, 1644 insertions(+), 72 deletions(-) create mode 100644 admin/src/utils/oss-direct-upload.ts create mode 100644 server/app/common/service/DirectUploadService.php create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/.gitignore create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/LICENSE create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/README.md create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/composer.json create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/src/Scope.php create mode 100644 server/vendor/qcloud_sts/qcloud-sts-sdk/src/Sts.php diff --git a/admin/package-lock.json b/admin/package-lock.json index f9a0dac8..0e110d3d 100644 --- a/admin/package-lock.json +++ b/admin/package-lock.json @@ -19,6 +19,7 @@ "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", "axios": "^1.7.9", + "cos-js-sdk-v5": "^1.10.1", "css-color-function": "^1.3.3", "echarts": "^5.6.0", "element-plus": "^2.9.4", @@ -6064,6 +6065,16 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cos-js-sdk-v5": { + "version": "1.10.1", + "resolved": "https://registry.npmmirror.com/cos-js-sdk-v5/-/cos-js-sdk-v5-1.10.1.tgz", + "integrity": "sha512-a4SRfCY5g6Z35C7OWe9te/S1zk77rVQzfpvZ33gmTdJQzKxbNbEG7Aw/v453XwVMsQB352FIf7KRMm5Ya/wlZQ==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "fast-xml-parser": "4.5.0" + } + }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -7580,6 +7591,28 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -12299,6 +12332,18 @@ "dev": true, "license": "MIT" }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/sucrase": { "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", diff --git a/admin/package.json b/admin/package.json index 4be5a68b..087fa4a4 100644 --- a/admin/package.json +++ b/admin/package.json @@ -21,6 +21,7 @@ "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", "axios": "^1.7.9", + "cos-js-sdk-v5": "^1.10.1", "css-color-function": "^1.3.3", "echarts": "^5.6.0", "element-plus": "^2.9.4", diff --git a/admin/src/api/file.ts b/admin/src/api/file.ts index 565b25d9..2d60dd2c 100644 --- a/admin/src/api/file.ts +++ b/admin/src/api/file.ts @@ -90,3 +90,50 @@ export function fileMove(params: Record) { export function fileRename(params: { id: number; name: string }) { return request.post({ url: '/file/rename', params }) } + +/** 浏览器直传 OSS - 凭证类型 */ +export interface OssCredentialsResponse { + provider: string + fallback: boolean + bucket?: string + region?: string + host?: string + cdn_domain?: string + key_prefix?: string + max_size?: number + duration?: number + expired_time?: number + start_time?: number + credentials?: { + tmpSecretId: string + tmpSecretKey: string + sessionToken: string + } +} + +/** 申请 STS 临时凭证 */ +export function getOssCredentials(params: { type: 'video' }) { + return request.post({ + url: '/upload/ossCredentials', + params + }) as Promise +} + +/** 直传完成回执:写 file 表 + HEAD 校验 */ +export function confirmOssUpload(params: { + type: 'video' + key: string + name: string + size: number + content_type: string + cid?: number +}) { + return request.post({ url: '/upload/ossConfirm', params }) as Promise<{ + id: number + cid: number + type: number + name: string + uri: string + url: string + }> +} diff --git a/admin/src/api/tcm.ts b/admin/src/api/tcm.ts index 242e1744..8a31caa9 100644 --- a/admin/src/api/tcm.ts +++ b/admin/src/api/tcm.ts @@ -229,14 +229,25 @@ export function startCloudRecording(params: { diagnosis_id: number }) { return request.post({ url: '/tcm.diagnosis/startCloudRecording', params }) } -/** 本地录制完成后,将已上传视频的访问地址写入通话记录(忽略取消令牌,避免与其它 POST 互斥取消) */ -export function attachLocalCallRecording(params: { diagnosis_id: number; file_url: string }) { +/** 本地录制完成后,将已上传视频的访问地址写入通话记录(可显式传 call_record_id) */ +export function attachLocalCallRecording(params: { + diagnosis_id: number + file_url: string + call_record_id?: number +}) { return request.post( { url: '/tcm.diagnosis/attachLocalCallRecording', params }, { ignoreCancelToken: true, isOpenRetry: false } ) } +export function createManualCallRecord(params: { diagnosis_id: number }) { + return request.post( + { url: '/tcm.diagnosis/createManualCallRecord', params }, + { ignoreCancelToken: true, isOpenRetry: false } + ) +} + /** 医助旁观当前进行中的视频通话(进房参数,Web TRTC 只拉流) */ export function getAssistantWatchCallParams(params: { diagnosis_id: number }) { return request.get({ url: '/tcm.diagnosis/watchCall', params }) diff --git a/admin/src/components/upload/index.vue b/admin/src/components/upload/index.vue index ac470697..a51838c8 100644 --- a/admin/src/components/upload/index.vue +++ b/admin/src/components/upload/index.vue @@ -9,6 +9,7 @@ :show-file-list="false" :headers="headers" :data="data" + :http-request="useDirect ? httpRequest : undefined" :on-progress="handleProgress" :on-success="handleSuccess" :on-exceed="handleExceed" @@ -41,7 +42,7 @@