272272 <div class =" w-full bg-gray-200 rounded-full h-2.5 overflow-hidden" >
273273 <div
274274 class =" h-2.5 rounded-full transition-all duration-300 ease-out"
275- :class =" decryptProgress.status === 'complete' ? 'bg-[#07C160]' : 'bg-[#91D300]'"
275+ :class =" decryptProgress.status === 'complete' ? 'bg-[#07C160]' : decryptProgress.status === 'cancelled' ? 'bg-[#FAAD14]' : 'bg-[#91D300]'"
276276 :style =" { width: progressPercent + '%' }"
277277 ></div >
278278 </div >
366366 </svg >
367367 {{ mediaDecrypting ? '解密中...' : (mediaDecryptResult ? '重新解密' : '开始解密图片') }}
368368 </button >
369+ <button
370+ v-if =" mediaDecrypting"
371+ @click =" cancelMediaDecrypt"
372+ class =" inline-flex items-center px-6 py-3 bg-[#FA5151] text-white rounded-lg font-medium hover:bg-[#E54D4D] transition-all duration-200"
373+ >
374+ 停止解密
375+ </button >
369376 <button
370377 @click =" skipToChat"
371378 :disabled =" mediaDecrypting"
@@ -671,6 +678,18 @@ const validateForm = () => {
671678}
672679
673680let dbDecryptEventSource = null
681+ let mediaDecryptEventSource = null
682+
683+ const closeMediaDecryptEventSource = () => {
684+ try {
685+ if (mediaDecryptEventSource) mediaDecryptEventSource .close ()
686+ } catch (e) {
687+ // ignore
688+ } finally {
689+ mediaDecryptEventSource = null
690+ }
691+ }
692+
674693onBeforeUnmount (() => {
675694 try {
676695 if (dbDecryptEventSource) dbDecryptEventSource .close ()
@@ -679,6 +698,8 @@ onBeforeUnmount(() => {
679698 } finally {
680699 dbDecryptEventSource = null
681700 }
701+
702+ closeMediaDecryptEventSource ()
682703})
683704
684705const resetDbDecryptProgress = () => {
@@ -691,6 +712,17 @@ const resetDbDecryptProgress = () => {
691712 dbDecryptProgress .message = ' '
692713}
693714
715+ const resetMediaDecryptProgress = () => {
716+ decryptProgress .current = 0
717+ decryptProgress .total = 0
718+ decryptProgress .success_count = 0
719+ decryptProgress .skip_count = 0
720+ decryptProgress .fail_count = 0
721+ decryptProgress .current_file = ' '
722+ decryptProgress .fileStatus = ' '
723+ decryptProgress .status = ' '
724+ }
725+
694726// 处理解密
695727const handleDecrypt = async () => {
696728 if (! validateForm ()) {
@@ -877,20 +909,14 @@ const handleDecrypt = async () => {
877909
878910// 批量解密所有图片(使用SSE实时进度)
879911const decryptAllImages = async () => {
912+ closeMediaDecryptEventSource ()
880913 mediaDecrypting .value = true
881914 mediaDecryptResult .value = null
882915 error .value = ' '
883916 warning .value = ' '
884917
885918 // 重置进度
886- decryptProgress .current = 0
887- decryptProgress .total = 0
888- decryptProgress .success_count = 0
889- decryptProgress .skip_count = 0
890- decryptProgress .fail_count = 0
891- decryptProgress .current_file = ' '
892- decryptProgress .fileStatus = ' '
893- decryptProgress .status = ' '
919+ resetMediaDecryptProgress ()
894920
895921 try {
896922 // 构建SSE URL
@@ -903,8 +929,11 @@ const decryptAllImages = async () => {
903929
904930 // 使用EventSource接收SSE
905931 const eventSource = new EventSource (url)
932+ mediaDecryptEventSource = eventSource
906933
907934 eventSource .onmessage = (event ) => {
935+ if (mediaDecryptEventSource !== eventSource) return
936+
908937 try {
909938 const data = JSON .parse (event .data )
910939
@@ -928,21 +957,23 @@ const decryptAllImages = async () => {
928957 decryptProgress .skip_count = data .skip_count
929958 decryptProgress .fail_count = data .fail_count
930959 mediaDecryptResult .value = data
931- eventSource .close ()
932960 mediaDecrypting .value = false
961+ closeMediaDecryptEventSource ()
933962 } else if (data .type === ' error' ) {
934963 error .value = data .message
935- eventSource .close ()
936964 mediaDecrypting .value = false
965+ closeMediaDecryptEventSource ()
937966 }
938967 } catch (e) {
939968 console .error (' 解析SSE消息失败:' , e)
940969 }
941970 }
942971
943972 eventSource .onerror = (e ) => {
973+ if (mediaDecryptEventSource !== eventSource) return
974+
944975 console .error (' SSE连接错误:' , e)
945- eventSource . close ()
976+ closeMediaDecryptEventSource ()
946977 if (mediaDecrypting .value ) {
947978 error .value = ' SSE连接中断,请重试'
948979 mediaDecrypting .value = false
@@ -951,9 +982,19 @@ const decryptAllImages = async () => {
951982 } catch (err) {
952983 error .value = err .message || ' 图片解密过程中发生错误'
953984 mediaDecrypting .value = false
985+ closeMediaDecryptEventSource ()
954986 }
955987}
956988
989+ const cancelMediaDecrypt = () => {
990+ if (! mediaDecrypting .value ) return
991+
992+ decryptProgress .status = ' cancelled'
993+ mediaDecrypting .value = false
994+ warning .value = ' 已停止图片解密,已完成的图片会保留。'
995+ closeMediaDecryptEventSource ()
996+ }
997+
957998// 从密钥步骤进入图片解密步骤
958999const goToMediaDecryptStep = async () => {
9591000 error .value = ' '
0 commit comments