Files
xian_algorithm_new/app/services/qgis/template_cache.py
T

121 lines
3.8 KiB
Python
Raw Normal View History

2026-06-19 17:04:03 +08:00
"""
模板缓存引擎。解决 QgsProject 单例问题。
流程:
1. 首次请求:project.read() 加载模板(慢,仅一次)
2. 加载后 project.write() 保存到临时文件
3. 后续同模板请求:从临时文件恢复(快,连接复用)
4. 手动恢复文本/过滤/缩放(毫秒级)
"""
import os
import time
import tempfile
from qgis.core import QgsProject, QgsRectangle
from app.config.paths import get_logger
logger = get_logger("qgis.cache")
class TemplateCache:
def __init__(self):
self._cache: dict[str, dict] = {}
def is_loaded(self, template_path: str) -> bool:
return template_path in self._cache
def load_template(self, template_path: str, layout_name: str = "A4") -> None:
"""首次加载模板"""
start = time.time()
project = QgsProject.instance()
logger.info(f"首次加载: {os.path.basename(template_path)}")
project.read(template_path)
logger.info(f"project.read() 耗时: {time.time() - start:.1f}s")
# 保存到临时文件
tmp_file = tempfile.NamedTemporaryFile(
suffix=".qgz", delete=False,
2026-06-20 17:44:44 +08:00
dir=tempfile.gettempdir(),
2026-06-19 17:04:03 +08:00
)
tmp_path = tmp_file.name
tmp_file.close()
t_save = time.time()
project.write(tmp_path)
logger.info(f"项目保存耗时: {time.time() - t_save:.1f}s")
# 记录初始状态
texts = {}
extent = None
layout = project.layoutManager().layoutByName(layout_name)
if layout:
2026-06-20 15:50:24 +08:00
for item_id in ["mapTitle", "mapTime", "mapUint", "info"]:
2026-06-19 17:04:03 +08:00
item = layout.itemById(item_id)
if item:
texts[item_id] = item.text()
map_item = layout.itemById("Map")
if map_item:
extent = QgsRectangle(map_item.extent())
self._cache[template_path] = {
"file": tmp_path,
"texts": texts,
"extent": extent,
"layout": layout_name,
}
logger.info(f"模板加载完成,总耗时: {time.time() - start:.1f}s")
def restore_template(self, template_path: str) -> tuple:
"""从缓存恢复模板"""
cached = self._cache.get(template_path)
if not cached:
raise RuntimeError(f"模板未缓存: {template_path}")
start = time.time()
project = QgsProject.instance()
logger.info(f"恢复模板: {os.path.basename(template_path)}")
project.read(cached["file"])
logger.info(f"project.read() 耗时: {time.time() - start:.1f}s")
return project, cached["texts"], cached["extent"]
def reset_project_state(self, project: QgsProject, texts: dict, extent) -> None:
"""重置项目到干净状态"""
start = time.time()
for layer in project.mapLayers().values():
if layer.subsetString():
layer.setSubsetString("")
# 获取 layout 名称(从缓存中)
layout_name = "A4"
for cached in self._cache.values():
layout_name = cached.get("layout", "A4")
break
layout = project.layoutManager().layoutByName(layout_name)
if layout:
for item_id, text in texts.items():
item = layout.itemById(item_id)
if item:
item.setText(text)
if extent:
map_item = layout.itemById("Map")
if map_item:
map_item.zoomToExtent(extent)
logger.info(f"状态重置耗时: {time.time() - start:.3f}s")
def cleanup(self) -> None:
"""清理所有临时文件"""
for cached in self._cache.values():
try:
os.remove(cached["file"])
except OSError:
pass
self._cache.clear()
logger.info("已清理所有缓存")