增加公共下载进度、增加接收SKU、密钥分别存放
This commit is contained in:
128
app/main.py
128
app/main.py
@@ -4,6 +4,8 @@ import json
|
||||
import sys
|
||||
import shutil
|
||||
import os
|
||||
import uuid
|
||||
import ctypes
|
||||
os.makedirs(cache_path,exist_ok=True)
|
||||
if not debug:
|
||||
today = datetime.datetime.now().strftime("%Y_%m_%d")
|
||||
@@ -186,17 +188,7 @@ class WindowAPI:
|
||||
if not result:
|
||||
return {'success': False, 'error': '用户取消'}
|
||||
path = result[0] if isinstance(result, (list, tuple)) else result
|
||||
try:
|
||||
import requests
|
||||
resp = requests.get(url.strip(), timeout=120, stream=True)
|
||||
resp.raise_for_status()
|
||||
with open(path, 'wb') as f:
|
||||
for chunk in resp.iter_content(chunk_size=65536):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
return {'success': True, 'path': path}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
return self._download_url_to_path(url, path)
|
||||
|
||||
def save_file_from_url_new(self, url, default_filename='download.bin'):
|
||||
"""弹窗选择保存位置,从 url 下载文件并保存。根据文件后缀动态设置保存类型。"""
|
||||
@@ -230,18 +222,124 @@ class WindowAPI:
|
||||
return {'success': False, 'error': '用户取消'}
|
||||
|
||||
path = result[0] if isinstance(result, (list, tuple)) else result
|
||||
return self._download_url_to_path(url, path)
|
||||
|
||||
def save_file_from_url_with_progress(self, url, default_filename='download.bin', download_id=''):
|
||||
"""弹窗选择保存位置,从 url 下载文件并通过前端事件上报下载进度。"""
|
||||
print("调用到save_file_from_url_with_progress方法")
|
||||
if not url or not url.strip():
|
||||
return {'success': False, 'error': '下载地址为空'}
|
||||
|
||||
filename = str(default_filename or 'download.bin').strip() or 'download.bin'
|
||||
ext = os.path.splitext(filename)[1].lower()
|
||||
if ext == '.zip':
|
||||
file_types = ('ZIP 压缩包 (*.zip)', '所有文件 (*.*)')
|
||||
elif ext in ('.xlsx', '.xls'):
|
||||
file_types = ('Excel 文件 (*.xlsx;*.xls)', '所有文件 (*.*)')
|
||||
elif ext == '.csv':
|
||||
file_types = ('CSV 文件 (*.csv)', '所有文件 (*.*)')
|
||||
elif ext == '.txt':
|
||||
file_types = ('文本文件 (*.txt)', '所有文件 (*.*)')
|
||||
elif ext == '.json':
|
||||
file_types = ('JSON 文件 (*.json)', '所有文件 (*.*)')
|
||||
else:
|
||||
file_types = ('所有文件 (*.*)',)
|
||||
|
||||
result = self._window.create_file_dialog(
|
||||
webview.SAVE_DIALOG,
|
||||
save_filename=filename,
|
||||
file_types=file_types
|
||||
)
|
||||
if not result:
|
||||
return {'success': False, 'error': '用户取消'}
|
||||
|
||||
path = result[0] if isinstance(result, (list, tuple)) else result
|
||||
progress_id = str(download_id or uuid.uuid4())
|
||||
return self._download_url_to_path(url, path, progress_id)
|
||||
|
||||
def _download_url_to_path(self, url, path, download_id=''):
|
||||
"""先下载到临时文件,完整下载后再替换为最终文件,避免用户打开半成品。"""
|
||||
final_path = os.path.abspath(path)
|
||||
final_dir = os.path.dirname(final_path) or os.getcwd()
|
||||
final_name = os.path.basename(final_path)
|
||||
temp_path = os.path.join(final_dir, f".{final_name}.crdownload")
|
||||
last_progress_emit = 0.0
|
||||
last_progress_percent = -1
|
||||
try:
|
||||
import requests
|
||||
os.makedirs(final_dir, exist_ok=True)
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)
|
||||
resp = requests.get(url.strip(), timeout=120, stream=True)
|
||||
resp.raise_for_status()
|
||||
with open(path, 'wb') as f:
|
||||
total = int(resp.headers.get('Content-Length') or 0)
|
||||
downloaded = 0
|
||||
self._emit_download_progress(download_id, 'running', final_path, downloaded, total)
|
||||
with open(temp_path, 'wb') as f:
|
||||
self._hide_file(temp_path)
|
||||
for chunk in resp.iter_content(chunk_size=65536):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
return {'success': True, 'path': path}
|
||||
downloaded += len(chunk)
|
||||
percent = int(downloaded * 100 / total) if total else 0
|
||||
now_time = time.time()
|
||||
if percent != last_progress_percent or now_time - last_progress_emit >= 0.2:
|
||||
self._emit_download_progress(download_id, 'running', final_path, downloaded, total)
|
||||
last_progress_emit = now_time
|
||||
last_progress_percent = percent
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
self._show_file(temp_path)
|
||||
os.replace(temp_path, final_path)
|
||||
self._emit_download_progress(download_id, 'success', final_path, downloaded, total)
|
||||
return {'success': True, 'path': final_path}
|
||||
except Exception as e:
|
||||
try:
|
||||
if os.path.exists(temp_path):
|
||||
os.remove(temp_path)
|
||||
except Exception:
|
||||
pass
|
||||
self._emit_download_progress(download_id, 'failed', final_path, 0, 0, str(e))
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def _emit_download_progress(self, download_id, status, path, downloaded, total, error=''):
|
||||
if not download_id:
|
||||
return
|
||||
payload = {
|
||||
'id': download_id,
|
||||
'status': status,
|
||||
'path': path,
|
||||
'downloaded': downloaded,
|
||||
'total': total,
|
||||
'percent': round(downloaded * 100 / total, 1) if total else 0,
|
||||
'error': error,
|
||||
}
|
||||
script = (
|
||||
"window.dispatchEvent(new CustomEvent('pywebview-download-progress', "
|
||||
f"{{ detail: {json.dumps(payload, ensure_ascii=False)} }}));"
|
||||
)
|
||||
try:
|
||||
self._window.evaluate_js(script)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _hide_file(self, path):
|
||||
"""Windows 下隐藏临时下载文件,减少用户误打开半成品的机会。"""
|
||||
if os.name != 'nt':
|
||||
return
|
||||
try:
|
||||
ctypes.windll.kernel32.SetFileAttributesW(path, 0x02)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _show_file(self, path):
|
||||
"""恢复普通文件属性,避免最终保存文件被隐藏。"""
|
||||
if os.name != 'nt':
|
||||
return
|
||||
try:
|
||||
ctypes.windll.kernel32.SetFileAttributesW(path, 0x80)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def save_template_xlsx(self):
|
||||
"""弹窗选择保存位置,将品牌文档格式模板 xlsx 保存到用户选择的位置。"""
|
||||
template_name = '品牌文档格式_模板.xlsx'
|
||||
@@ -440,7 +538,7 @@ def main():
|
||||
|
||||
api = WindowAPI(window)
|
||||
window.expose(api.close, api.minimize, api.maximize, api.toggle_maximize, generate_images, api.save_image, api.save_image_to_folder, api.select_folder, api.select_brand_xlsx_files, api.select_brand_folder,
|
||||
api.save_file_from_url, api.save_template_xlsx,api.save_template_zip,api.upload_file_to_java,api.open_external_url,api.enqueue_json,api.get_detail_del,api.save_file_from_url_new,api.get_device_id)
|
||||
api.save_file_from_url, api.save_template_xlsx,api.save_template_zip,api.upload_file_to_java,api.open_external_url,api.enqueue_json,api.get_detail_del,api.save_file_from_url_new,api.save_file_from_url_with_progress,api.get_device_id)
|
||||
webview.start(
|
||||
debug=True,
|
||||
storage_path=cache_path,
|
||||
|
||||
Reference in New Issue
Block a user