modified: app/ali_oss.py
new file: app/amazon/del_brand.py new file: app/amazon/main.py modified: app/blueprints/__pycache__/brand.cpython-39.pyc modified: app/blueprints/__pycache__/communication.cpython-39.pyc modified: app/blueprints/__pycache__/main.cpython-39.pyc modified: app/blueprints/brand.py new file: "app/blueprints/brand_\345\244\207\344\273\275.py" modified: app/blueprints/communication.py modified: app/blueprints/main.py modified: app/config.py modified: app/main.py
This commit is contained in:
126
app/main.py
126
app/main.py
@@ -1,26 +1,35 @@
|
||||
"""
|
||||
基于 pywebview 实现的跨平台 UI,需先登录方可使用
|
||||
"""
|
||||
from config import cache_path,debug,version,JAVA_API_BASE,JSON_TASK_QUEUE
|
||||
from config import cache_path,debug,version,JAVA_API_BASE,JSON_TASK_QUEUE,runing_task,runing_shop
|
||||
import datetime
|
||||
import json
|
||||
import sys
|
||||
import shutil
|
||||
import os
|
||||
os.makedirs(cache_path,exist_ok=True)
|
||||
if not debug:
|
||||
today = datetime.datetime.now().strftime("%Y_%m_%d")
|
||||
sys.stdout = open(os.path.join(cache_path,f'{today}.log'), 'a',buffering=1)
|
||||
# sys.stderr = sys.stdout
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
import webview
|
||||
import threading
|
||||
import time
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
|
||||
with open("version.txt","w",encoding="utf-8") as file:
|
||||
file.write(json.dumps({"version":version}))
|
||||
|
||||
print(f"""
|
||||
========================================================
|
||||
版本: {version}
|
||||
========================================================
|
||||
|
||||
""")
|
||||
|
||||
|
||||
# 获取当前脚本所在目录
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -170,7 +179,6 @@ class WindowAPI:
|
||||
|
||||
def save_template_xlsx(self):
|
||||
"""弹窗选择保存位置,将品牌文档格式模板 xlsx 保存到用户选择的位置。"""
|
||||
import shutil
|
||||
template_name = '品牌文档格式_模板.xlsx'
|
||||
template_path = os.path.join(BASE_DIR, 'static', template_name)
|
||||
if not os.path.isfile(template_path):
|
||||
@@ -189,7 +197,6 @@ class WindowAPI:
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
|
||||
def save_template_zip(self):
|
||||
"""弹窗选择保存位置,将品牌文档格式模板 xlsx 保存到用户选择的位置。"""
|
||||
import shutil
|
||||
@@ -234,6 +241,21 @@ class WindowAPI:
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def open_external_url(self, url):
|
||||
if not url or not str(url).strip():
|
||||
return {'success': False, 'error': '链接为空'}
|
||||
target = str(url).strip()
|
||||
try:
|
||||
if sys.platform.startswith('win'):
|
||||
os.startfile(target)
|
||||
elif sys.platform == 'darwin':
|
||||
subprocess.Popen(['open', target])
|
||||
else:
|
||||
subprocess.Popen(['xdg-open', target])
|
||||
return {'success': True}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def enqueue_json(self, data):
|
||||
"""保存任务到队列"""
|
||||
try:
|
||||
@@ -245,83 +267,33 @@ class WindowAPI:
|
||||
payload = json.loads(data)
|
||||
if not isinstance(payload, (dict, list)):
|
||||
return {'success': False, 'error': '仅支持 JSON 对象或数组'}
|
||||
if payload.get("type") == "delete-brand-run" and payload.get("data").get("taskId") in runing_task:
|
||||
return {'success': False, 'error': '已存在正在执行的删除品牌任务'}
|
||||
# 判断当前店铺是否正在运行中
|
||||
if payload.get("data").get("items"):
|
||||
shop_name = payload["data"]["items"][0]["shopName"]
|
||||
if shop_name in runing_shop:
|
||||
return {'success': False, 'error': '当前店铺正在执行中,请等待店铺完成之后重试'}
|
||||
JSON_TASK_QUEUE.put(payload)
|
||||
return {'success': True, 'queue_size': JSON_TASK_QUEUE.qsize()}
|
||||
except Exception as e:
|
||||
return {'success': False, 'error': str(e)}
|
||||
|
||||
def _select_folder_win32():
|
||||
"""Windows: 用 ctypes 调用系统文件夹选择对话框,打包成 exe 后也能正常弹窗(不依赖 tkinter)"""
|
||||
try:
|
||||
import ctypes
|
||||
from ctypes import wintypes
|
||||
BIF_RETURNONLYFSDIRS = 0x00000001
|
||||
BIF_NEWDIALOGSTYLE = 0x00000040
|
||||
MAX_PATH = 260
|
||||
shell32 = ctypes.windll.shell32 # type: ignore[attr-defined]
|
||||
# BROWSEINFOW
|
||||
class BROWSEINFOW(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("hwndOwner", wintypes.HWND),
|
||||
("pidlRoot", ctypes.c_void_p),
|
||||
("pszDisplayName", ctypes.c_wchar_p),
|
||||
("lpszTitle", ctypes.c_wchar_p),
|
||||
("ulFlags", wintypes.UINT),
|
||||
("lpfn", ctypes.c_void_p),
|
||||
("lParam", wintypes.LPARAM),
|
||||
("iImage", ctypes.c_int),
|
||||
]
|
||||
display_name_buf = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
bi = BROWSEINFOW()
|
||||
bi.hwndOwner = 0
|
||||
bi.pidlRoot = 0
|
||||
bi.pszDisplayName = ctypes.cast(display_name_buf, ctypes.c_wchar_p)
|
||||
bi.lpszTitle = "选择保存图片的文件夹"
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE
|
||||
bi.lpfn = 0
|
||||
bi.lParam = 0
|
||||
bi.iImage = 0
|
||||
pidl = shell32.SHBrowseForFolderW(ctypes.byref(bi))
|
||||
if not pidl:
|
||||
return ''
|
||||
path_buf = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
if not shell32.SHGetPathFromIDListW(pidl, path_buf):
|
||||
return ''
|
||||
ole32 = ctypes.windll.ole32 # type: ignore[attr-defined]
|
||||
ole32.CoTaskMemFree(pidl)
|
||||
return path_buf.value or ''
|
||||
except Exception as e:
|
||||
print("Windows 文件夹选择失败:", e)
|
||||
return ''
|
||||
|
||||
|
||||
def _select_folder_tk():
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog
|
||||
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
root.attributes('-topmost', True)
|
||||
|
||||
# 使用 after 确保 askdirectory 在主循环启动后执行
|
||||
def ask():
|
||||
nonlocal path
|
||||
path = filedialog.askdirectory(title='选择保存图片的文件夹')
|
||||
root.quit() # 关闭主循环
|
||||
|
||||
path = ''
|
||||
root.after(100, ask)
|
||||
root.mainloop() # 启动主循环,直到 root.quit() 被调用
|
||||
try:
|
||||
root.destroy()
|
||||
except:
|
||||
pass
|
||||
return path
|
||||
|
||||
|
||||
def select_folder():
|
||||
"""弹窗选择文件夹,返回路径(空字符串表示取消)。Windows 打包 exe 时优先用系统 API 避免 tkinter 不弹窗。"""
|
||||
return _select_folder_tk()
|
||||
def get_detail_del(self,task_id):
|
||||
"""获取正在执行的删除品牌任务详情"""
|
||||
task_info = runing_task.get(task_id)
|
||||
if not task_info:
|
||||
return {'success': False, 'error': '任务不存在'}
|
||||
return {'success': True, 'task_info': task_info}
|
||||
|
||||
def stop_task(self,task_id):
|
||||
"""停止正在执行的删除品牌任务"""
|
||||
task_info = runing_task.get(task_id)
|
||||
if not task_info:
|
||||
return {'success': False, 'error': '任务不存在'}
|
||||
# 这里可以设置一个标志位,实际的删除品牌任务需要定期检查这个标志位来决定是否停止
|
||||
task_info['stop_requested'] = True
|
||||
return {'success': True, 'message': '已请求停止任务'}
|
||||
|
||||
|
||||
def start_flask():
|
||||
@@ -350,7 +322,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.enqueue_json)
|
||||
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)
|
||||
webview.start(
|
||||
debug=True,
|
||||
storage_path=cache_path,
|
||||
|
||||
Reference in New Issue
Block a user