mirror of
https://github.com/shy3130/tick-stock-panel.git
synced 2026-11-02 10:26:13 +00:00
brand: 品牌统一为 TSP — 应用名/图标(浅色圆角卡, Windows/macOS 双平台)对齐 brand 资产, README 新增官网入口与标题行内嵌 logo
This commit is contained in:
@@ -46,7 +46,7 @@ jobs:
|
||||
# 2) 项目依赖 polars, 而 polars 自 1.33 起移除了 macOS x86_64 原生 wheel
|
||||
# (改 py3-none-any), 在 arm64 runner 上经 Rosetta 无法产出可运行的 x64 包。
|
||||
# runner 用 macos-26 (2026-02 GA, 免费, arm64 原生, SDK 更新)。
|
||||
ALL='[{"os":"windows-latest","artifact":"TickFlowStockPanel-Setup-x64.exe","platform":"windows"},{"os":"macos-26","artifact":"TickFlowStockPanel-macos-arm64.dmg","platform":"macos","arch":"arm64"},{"os":"ubuntu-latest","artifact":"TickFlowStockPanel-linux-x64.tar.gz","platform":"linux"}]'
|
||||
ALL='[{"os":"windows-latest","artifact":"TSP-Setup-x64.exe","platform":"windows"},{"os":"macos-26","artifact":"TSP-macos-arm64.dmg","platform":"macos","arch":"arm64"},{"os":"ubuntu-latest","artifact":"TSP-linux-x64.tar.gz","platform":"linux"}]'
|
||||
# 按 input 过滤平台 (macos → arm64 单项)
|
||||
python3 -c "
|
||||
import json, sys
|
||||
@@ -115,21 +115,10 @@ jobs:
|
||||
working-directory: backend
|
||||
run: uv pip install pyinstaller
|
||||
|
||||
- name: 生成 macOS 图标 (仅 macOS)
|
||||
if: matrix.platform == 'macos'
|
||||
# icon.ico 已入库 (Windows 直接用), 但 icon.icns 未入库 (macOS 专用产物)。
|
||||
# 用 generate_icon.py 现场生成, 否则 spec 第 37 行 BUNDLE 会因找不到图标而崩。
|
||||
# 注意: Pillow 不是 backend 的运行时依赖 (它属于 backtest 的 matplotlib 链),
|
||||
# --no-dev --extra desktop 不装它, 故需在此显式安装 (仅图标生成需要)。
|
||||
working-directory: backend
|
||||
run: |
|
||||
uv pip install pillow
|
||||
uv run python ../packaging/generate_icon.py
|
||||
|
||||
- name: 打包 (PyInstaller)
|
||||
# 在 backend 目录跑 (用该目录的 venv: pywebview/polars 等依赖)。
|
||||
# 产物输出到 backend/dist/ (PyInstaller 默认路径), 与 packaging/tickflow.iss
|
||||
# 第 78 行的 Source 路径 (..\backend\dist\TickFlowStockPanel\*) 保持一致。
|
||||
# 第 78 行的 Source 路径 (..\backend\dist\TSP\*) 保持一致。
|
||||
# SPECPATH 由 spec 文件位置决定 (packaging/tickflow.spec → 项目根),
|
||||
# 与 cwd 无关, 故 frontend/dist、tiers.yaml 等相对路径仍正确。
|
||||
working-directory: backend
|
||||
@@ -139,7 +128,7 @@ jobs:
|
||||
if: matrix.platform == 'windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$runtimeRoot = 'backend/dist/TickFlowStockPanel/_internal'
|
||||
$runtimeRoot = 'backend/dist/TSP/_internal'
|
||||
$required = @(
|
||||
'_polars_runtime_32/_polars_runtime.pyd',
|
||||
'_polars_runtime_compat/_polars_runtime.pyd'
|
||||
@@ -164,7 +153,7 @@ jobs:
|
||||
echo "版本号: $ver"
|
||||
ISCC.exe "/DMyAppVersion=$ver" packaging/tickflow.iss
|
||||
# 把生成的 Setup.exe 移到工作区根 (Release 上传用)
|
||||
Move-Item packaging/Output/TickFlowStockPanel-Setup-$ver.exe ${{ matrix.artifact }} -Force
|
||||
Move-Item packaging/Output/TSP-Setup-$ver.exe ${{ matrix.artifact }} -Force
|
||||
shell: pwsh
|
||||
|
||||
- name: 生成 DMG (macOS)
|
||||
@@ -183,19 +172,19 @@ jobs:
|
||||
--window-pos 200 120 \
|
||||
--window-size 600 400 \
|
||||
--icon-size 100 \
|
||||
--icon "TickFlowStockPanel.app" 175 190 \
|
||||
--icon "TSP.app" 175 190 \
|
||||
--app-drop-link 425 190 \
|
||||
--hide-extension "TickFlowStockPanel.app" \
|
||||
--hide-extension "TSP.app" \
|
||||
--skip-jenkins \
|
||||
--no-internet-enable \
|
||||
"${{ matrix.artifact }}" \
|
||||
backend/dist/TickFlowStockPanel.app
|
||||
backend/dist/TSP.app
|
||||
|
||||
- name: 压缩产物 (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
run: |
|
||||
cd backend/dist
|
||||
tar -czf ../../${{ matrix.artifact }} TickFlowStockPanel
|
||||
tar -czf ../../${{ matrix.artifact }} TSP
|
||||
|
||||
- name: 上传产物为构建产物 (备查)
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -218,16 +207,16 @@ jobs:
|
||||
|
||||
| 平台 | 文件 | 下载 |
|
||||
| :--- | :--- | :--- |
|
||||
| **Windows x64** | `TickFlowStockPanel-Setup-x64.exe` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TickFlowStockPanel-Setup-x64.exe) |
|
||||
| **macOS (Apple Silicon / M 系列芯片)** | `TickFlowStockPanel-macos-arm64.dmg` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TickFlowStockPanel-macos-arm64.dmg) |
|
||||
| **Linux** | `TickFlowStockPanel-linux-x64.tar.gz` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TickFlowStockPanel-linux-x64.tar.gz) |
|
||||
| **Windows x64** | `TSP-Setup-x64.exe` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TSP-Setup-x64.exe) |
|
||||
| **macOS (Apple Silicon / M 系列芯片)** | `TSP-macos-arm64.dmg` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TSP-macos-arm64.dmg) |
|
||||
| **Linux** | `TSP-linux-x64.tar.gz` | [⬇️ 立即下载](https://github.com/${{ github.repository }}/releases/download/${{ github.event.inputs.version }}/TSP-linux-x64.tar.gz) |
|
||||
|
||||
> 💡 点击「立即下载」直接获取, 无需滚动到底部附件区。
|
||||
> 🍎 **macOS 仅提供 Apple Silicon (M 系列芯片) 版本**: 点左上角 → "关于本机", 看"芯片"一项是否为 Apple; Intel 芯片 Mac 暂不支持 (上游 polars 已停止发布 Intel wheel)。
|
||||
|
||||
### 📋 使用说明
|
||||
- **Windows**: 下载后双击运行, 按安装向导操作(无需管理员权限), 自动创建桌面/开始菜单快捷方式
|
||||
- **macOS**: 双击 dmg 打开, 将 TickFlowStockPanel 拖入 Applications 文件夹; 首次启动需右键→打开(绕过 Gatekeeper)
|
||||
- **macOS**: 双击 dmg 打开, 将 TSP 拖入 Applications 文件夹; 首次启动需右键→打开(绕过 Gatekeeper)
|
||||
- **Linux**: 解压后运行可执行文件
|
||||
- 数据存储在安装目录下的 `data/` 子文件夹, 卸载重装不丢数据
|
||||
- 内置 Polars 兼容内核, 新老 CPU (无 AVX2) 均可运行
|
||||
@@ -253,9 +242,9 @@ jobs:
|
||||
mkdir -p assets && cd assets
|
||||
# 只拉已知的三个安装包 (latest.json 自身等其他资产不进清单)
|
||||
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
|
||||
--pattern 'TickFlowStockPanel-Setup-x64.exe' \
|
||||
--pattern 'TickFlowStockPanel-macos-arm64.dmg' \
|
||||
--pattern 'TickFlowStockPanel-linux-x64.tar.gz' \
|
||||
--pattern 'TSP-Setup-x64.exe' \
|
||||
--pattern 'TSP-macos-arm64.dmg' \
|
||||
--pattern 'TSP-linux-x64.tar.gz' \
|
||||
--clobber || true
|
||||
cd ..
|
||||
RELEASE_JSON=$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$TAG")
|
||||
@@ -269,9 +258,9 @@ jobs:
|
||||
|
||||
# 资产文件名 → 渠道名 (客户端按渠道取下载地址)
|
||||
channels_cfg = {
|
||||
"TickFlowStockPanel-Setup-x64.exe": "windows",
|
||||
"TickFlowStockPanel-macos-arm64.dmg": "macos-arm64",
|
||||
"TickFlowStockPanel-linux-x64.tar.gz": "linux-x64",
|
||||
"TSP-Setup-x64.exe": "windows",
|
||||
"TSP-macos-arm64.dmg": "macos-arm64",
|
||||
"TSP-linux-x64.tar.gz": "linux-x64",
|
||||
}
|
||||
by_name = {a["name"]: a for a in rel.get("assets", [])}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<div align="center">
|
||||
|
||||
# 📈 TSP · A股智能量化工作台
|
||||
# <picture><source media="(prefers-color-scheme: dark)" srcset="brand/logo-dark-title.svg"><img src="brand/logo-title.svg" width="30" alt="TSP Logo"></picture> TSP · A股智能量化工作台
|
||||
|
||||
[](https://tsp.shy313.com/)
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -406,6 +408,9 @@ flowchart TB
|
||||
|
||||
面板的核心能力不只长在页面上 —— **全部开放成受控接口**,外部程序与 AI 客户端平等消费:
|
||||
|
||||
> 🌐 **开放平台门户已上线 → [tsp.shy313.com](https://tsp.shy313.com/)**
|
||||
> 浏览 TSP 全部功能 · 注册账户 · 邀请好友 · 创建 API Key · 在线调用开放接口,一个入口直达。
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" align="center"><b>设置 → 开放接口 · Token 管理</b><br/><sub>明文只显示一次,六档 scope 按需授予</sub></td>
|
||||
@@ -492,6 +497,8 @@ docker run -d --name tsp -p 3018:3018 -v ${PWD}/data:/app/data ghcr.io/shy3130/t
|
||||
|
||||
**打开 <http://localhost:3018> 即可使用** · 多架构镜像(linux/amd64 · arm64)由 CI 自动发布,本地无需 Python / Node
|
||||
|
||||
**还没决定要不要部署?** 先逛逛 **[官网 tsp.shy313.com](https://tsp.shy313.com/)** —— 功能总览 · 账户注册 · API Key 管理
|
||||
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -25,7 +25,7 @@ from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_APP_NAME = "TickFlow 股票面板"
|
||||
_APP_NAME = "TSP 股票面板"
|
||||
_BASE_PORT = 3018
|
||||
_PORT_PROBE_RANGE = 50 # 从 3018 起最多试 50 个端口
|
||||
|
||||
@@ -339,7 +339,7 @@ def main() -> int:
|
||||
# 写完整 traceback 到 data/desktop.log, 并弹原生 MessageBox 让用户截图反馈。
|
||||
# 必须排在 KeyboardInterrupt 之后 —— Exception 是基类, 在前会遮蔽它。
|
||||
logger.exception("桌面客户端启动失败")
|
||||
_show_crash("TickFlow 启动失败", traceback.format_exc())
|
||||
_show_crash("TSP 启动失败", traceback.format_exc())
|
||||
return 1
|
||||
finally:
|
||||
_release_single_instance()
|
||||
|
||||
+3
-1
@@ -13,6 +13,7 @@
|
||||
| `logo-badge.svg` | 徽章 · 方底白标 `#8B5CF6 → #6D28D9` | App 图标 / 头像(平台圆角由宿主裁切) |
|
||||
| `logo-tile-light.svg` | 场景底卡 · 浅色圆角卡 `#F6F6F8` 底 | 文档配图 / 社交卡片(浅色) |
|
||||
| `logo-tile-dark.svg` | 场景底卡 · 深色圆角卡 `#191C25` 底 + `#232838` 描边 | 文档配图 / 社交卡片(深色) |
|
||||
| `logo-title.svg` / `logo-dark-title.svg` | 裁剪版 · viewBox 裁至墨迹底边 (`0 0 64 57.6`) | **README 标题行内嵌** — 墨迹贴基线, 与文字垂直居中 |
|
||||
|
||||
## PNG(全部透明底)
|
||||
|
||||
@@ -25,7 +26,8 @@
|
||||
|
||||
## 其他
|
||||
|
||||
- `icon.ico` — Windows 应用图标(内嵌 16 / 24 / 32 / 48 / 64 / 128 / 256 七档)
|
||||
- `icon.ico` — Windows 应用图标(内嵌 16 / 24 / 32 / 48 / 64 / 128 / 256 七档;浅色圆角卡版,由 `png/logo-tile-light-512.png` 派生 —— 透明底渐变 logo 在桌面快捷方式上显得过空,圆角浅卡在深/浅壁纸均成立)
|
||||
- `icon.icns` — macOS 应用图标(16–1024 八档,含 @2x;与 `icon.ico` 同源同版)
|
||||
|
||||
## 接入指引
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,15 @@
|
||||
<!-- Tick Stock Panel · 方案 0 正式主标 — 亮紫渐变 · 透明底 · 全直角
|
||||
变体: 渐变·深底 (终端 / 暗色 UI)
|
||||
与 logo.svg 同几何, 仅渐变换为深底优化亮度 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 57.6" fill="none" role="img" aria-label="Tick Stock Panel">
|
||||
<defs>
|
||||
<linearGradient id="tsp-grad-dark" x1="8" y1="6" x2="56" y2="58" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#C4B5FD"/>
|
||||
<stop offset="1" stop-color="#8B5CF6"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="M20 9 H11 V55 H20" stroke="url(#tsp-grad-dark)" stroke-width="5" stroke-linejoin="miter" stroke-linecap="butt"/>
|
||||
<path d="M44 9 H53 V55 H44" stroke="url(#tsp-grad-dark)" stroke-width="5" stroke-linejoin="miter" stroke-linecap="butt"/>
|
||||
<line x1="32" y1="15" x2="32" y2="49" stroke="url(#tsp-grad-dark)" stroke-width="3.5" stroke-linecap="butt" stroke-opacity="0.55"/>
|
||||
<rect x="26.5" y="19.5" width="11" height="17" fill="url(#tsp-grad-dark)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1023 B |
@@ -0,0 +1,22 @@
|
||||
<!-- Tick Stock Panel 品牌主 logo — 透明底, 品牌紫渐变, 全直角 (无圆角/圆笔帽)
|
||||
概念: 方括号 [ ] = 终端/代码/量化边界; 中央 K 线 = 行情本体
|
||||
bullish 姿态: 上影短/下影长, 站稳向上
|
||||
用法: 浅色背景; 深色背景请用 logo-white.svg -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 57.6" fill="none" role="img" aria-label="Tick Stock Panel">
|
||||
<defs>
|
||||
<linearGradient id="tsp-brand" x1="8" y1="6" x2="56" y2="58" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#A78BFA"/>
|
||||
<stop offset="1" stop-color="#7C3AED"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- 左方括号 (直角折线) -->
|
||||
<path d="M20 9 H11 V55 H20"
|
||||
stroke="url(#tsp-brand)" stroke-width="5" stroke-linejoin="miter" stroke-linecap="butt"/>
|
||||
<!-- 右方括号 (直角折线) -->
|
||||
<path d="M44 9 H53 V55 H44"
|
||||
stroke="url(#tsp-brand)" stroke-width="5" stroke-linejoin="miter" stroke-linecap="butt"/>
|
||||
<!-- K 线 wick (上影短/下影长, 平头端点) -->
|
||||
<line x1="32" y1="15" x2="32" y2="49" stroke="url(#tsp-brand)" stroke-width="3.5" stroke-linecap="butt" stroke-opacity="0.55"/>
|
||||
<!-- K 线 body (直角矩形) -->
|
||||
<rect x="26.5" y="19.5" width="11" height="17" fill="url(#tsp-brand)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -1,156 +0,0 @@
|
||||
"""生成应用图标 — 白色 squircle 背景 + 品牌 gradient Logo。
|
||||
|
||||
设计 (与 frontend favicon.svg / brand/logo.svg 一致):
|
||||
背景: 白色 squircle (macOS Big Sur+ 要求不透明 squircle 背景, 用白色填充)
|
||||
内容: 品牌渐变 (#A78BFA→#7C3AED, 亮端朝上) 方括号 + K线 (上影短/下影长, bullish 站稳)
|
||||
|
||||
蜡烛几何 (32x32 viewBox):
|
||||
wick: y=7 ~ y=25
|
||||
body: y=9 ~ y=19 (偏上)
|
||||
→ 上影 = 2 (短), 下影 = 6 (长)
|
||||
|
||||
每尺寸独立绘制: 线条占比全尺寸统一 (~9.4%), 小尺寸微调补偿, 不随尺寸递减。
|
||||
运行: python packaging/generate_icon.py
|
||||
产物:
|
||||
packaging/icon.ico — Windows (16/32/48/64/128/256)
|
||||
packaging/icon.icns — macOS (16/32/64/128/256/512, 含 @2x)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image, ImageChops, ImageDraw
|
||||
|
||||
OUT_ICO = Path(__file__).parent / "icon.ico"
|
||||
OUT_ICNS = Path(__file__).parent / "icon.icns"
|
||||
|
||||
# 背景: 白色 squircle (不透明, macOS 规范)
|
||||
BG = (255, 255, 255, 255)
|
||||
# logo 线条色: 品牌渐变 #A78BFA(亮端,左上) → #7C3AED(品牌紫,右下), 与 favicon.svg/brand/logo.svg 一致
|
||||
GRAD_A = (167, 139, 250) # #A78BFA
|
||||
GRAD_B = (124, 58, 237) # #7C3AED
|
||||
# wick 影线: 70% 不透明 (与 favicon.svg 一致; 16px 最小档经超采样仍可读)
|
||||
WICK_ALPHA = 0.7
|
||||
|
||||
|
||||
def _grad_image(size_px: int) -> Image.Image:
|
||||
"""32-viewBox 对角渐变 (4,3)→(28,29), 64px 生成后放大 (线性渐变缩放无损)。"""
|
||||
small = 64
|
||||
ax, ay, bx, by = 4 / 32, 3 / 32, 28 / 32, 29 / 32
|
||||
dx, dy = bx - ax, by - ay
|
||||
len2 = dx * dx + dy * dy
|
||||
img = Image.new("RGB", (small, small))
|
||||
px = img.load()
|
||||
for y in range(small):
|
||||
vy = (y + 0.5) / small
|
||||
for x in range(small):
|
||||
vx = (x + 0.5) / small
|
||||
t = max(0.0, min(1.0, ((vx - ax) * dx + (vy - ay) * dy) / len2))
|
||||
px[x, y] = tuple(round(a + (b - a) * t) for a, b in zip(GRAD_A, GRAD_B))
|
||||
return img.resize((size_px, size_px), Image.BILINEAR)
|
||||
|
||||
|
||||
def _draw(size: int, sw_b: float, sw_w: float, body_w: float) -> Image.Image:
|
||||
"""绘制单尺寸图标 (像素直接映射 32-viewBox)。"""
|
||||
factor = max(8, 2048 // size)
|
||||
s = size * factor
|
||||
img = Image.new("RGBA", (s, s), (0, 0, 0, 0))
|
||||
d = ImageDraw.Draw(img)
|
||||
|
||||
# 品牌色 squircle 背景 (圆角方块, macOS Big Sur+ 规范形状, 不透明)
|
||||
# 纯色填充, 不用渐变 — 渐变在 16px 小尺寸下看不出, 反而易引入 alpha 合成 bug
|
||||
d.rounded_rectangle([0, 0, s - 1, s - 1], radius=int(s * 0.22), fill=BG)
|
||||
|
||||
def p(v):
|
||||
return v * s / 32
|
||||
|
||||
swb = max(1, int(round(sw_b * factor)))
|
||||
sww = max(1, int(round(sw_w * factor)))
|
||||
|
||||
# 标记掩膜: 渐变经 alpha 通道贴入, 线条几何与旧版完全一致
|
||||
mark = Image.new("L", (s, s), 0)
|
||||
dm = ImageDraw.Draw(mark)
|
||||
|
||||
# 方括号 [ ]
|
||||
for pts in [[(10, 4), (4, 4), (4, 28), (10, 28)], [(22, 4), (28, 4), (28, 28), (22, 28)]]:
|
||||
scaled = [(p(x), p(y)) for x, y in pts]
|
||||
for i in range(len(scaled) - 1):
|
||||
dm.line([scaled[i], scaled[i + 1]], fill=255, width=swb, joint="curve")
|
||||
|
||||
# body 实体 (偏上 → 上影短下影长)
|
||||
dm.rounded_rectangle(
|
||||
[p(16 - body_w / 2), p(9), p(16 + body_w / 2), p(19)],
|
||||
radius=p(0.5), fill=255,
|
||||
)
|
||||
|
||||
# wick 影线 (上短下长, 70% 不透明)
|
||||
wick = Image.new("L", (s, s), 0)
|
||||
dw = ImageDraw.Draw(wick)
|
||||
dw.line([(p(16), p(7)), (p(16), p(25))], fill=255, width=sww)
|
||||
wcap = sww // 2 + 1
|
||||
for cy in [7, 25]:
|
||||
dw.ellipse([p(16) - wcap, p(cy) - wcap, p(16) + wcap, p(cy) + wcap], fill=255)
|
||||
|
||||
# 渐变层: alpha = mark + WICK_ALPHA * wick
|
||||
alpha = ImageChops.add(mark, wick.point(lambda v: round(v * WICK_ALPHA)))
|
||||
layer = _grad_image(s).convert("RGBA")
|
||||
layer.putalpha(alpha)
|
||||
img.alpha_composite(layer)
|
||||
|
||||
return img.resize((size, size), Image.LANCZOS)
|
||||
|
||||
|
||||
def draw_logo(size: int) -> Image.Image:
|
||||
"""按尺寸选参数, 保证各尺寸视觉粗细一致。
|
||||
|
||||
核心原则: 所有尺寸线条占图标的视觉比例统一, 不能出现"大尺寸反而显细"。
|
||||
基准定为 sw=4.0/32 (12.5%) — 经多轮对比选定, Dock 放大时线条仍清晰有力。
|
||||
小尺寸在基准上略加粗, 抵消像素化糊掉; 大尺寸统一用基准, 不递减。
|
||||
"""
|
||||
if size <= 16:
|
||||
return _draw(size, sw_b=4.5, sw_w=3.8, body_w=9)
|
||||
elif size <= 32:
|
||||
return _draw(size, sw_b=4.2, sw_w=3.6, body_w=8)
|
||||
else:
|
||||
# ≥48px 统一用基准 4.0, 不随尺寸递减
|
||||
return _draw(size, sw_b=4.0, sw_w=3.4, body_w=8)
|
||||
|
||||
|
||||
def _save_ico(images_by_size: dict[int, Image.Image]) -> None:
|
||||
"""Windows .ico (16/32/48/64/128/256)。主图 256 优先, 资源管理器大图清晰。"""
|
||||
sizes = [16, 32, 48, 64, 128, 256]
|
||||
images = [images_by_size[s] for s in sizes]
|
||||
images[-1].save(
|
||||
OUT_ICO, format="ICO",
|
||||
sizes=[(s, s) for s in sizes],
|
||||
append_images=images[:-1],
|
||||
)
|
||||
print(f"生成: {OUT_ICO} (尺寸 {sizes})")
|
||||
|
||||
|
||||
def _save_icns(images_by_size: dict[int, Image.Image]) -> None:
|
||||
"""macOS .icns (16/32/64/128/256/512)。
|
||||
|
||||
Apple 要求 .icns 至少含一张大图 (512 或 1024) 才合法, 否则 Finder/Dock
|
||||
不显示。这里用 512 作主图 (Pillow 12 写 1024 需额外编码, 512 已覆盖
|
||||
Retina @2x)。@2x 高清由系统从大图自动缩放, 无需单独提供。
|
||||
"""
|
||||
sizes = [16, 32, 64, 128, 256, 512]
|
||||
images = [images_by_size[s] for s in sizes]
|
||||
images[-1].save(
|
||||
OUT_ICNS, format="ICNS",
|
||||
append_images=images[:-1],
|
||||
)
|
||||
print(f"生成: {OUT_ICNS} (尺寸 {sizes})")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# 一次绘制所有用到的尺寸 (ico 和 icns 取并集), 避免重复绘制
|
||||
all_sizes = {16, 32, 48, 64, 128, 256, 512}
|
||||
images_by_size = {sz: draw_logo(sz) for sz in all_sizes}
|
||||
_save_ico(images_by_size)
|
||||
_save_icns(images_by_size)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+15
-10
@@ -1,13 +1,13 @@
|
||||
; ===========================================================================
|
||||
; Tick Stock Panel — Inno Setup 安装包脚本
|
||||
; ===========================================================================
|
||||
; 用途: 把 PyInstaller 产出的 dist/TickFlowStockPanel/ 文件夹封装成
|
||||
; 用途: 把 PyInstaller 产出的 dist/TSP/ 文件夹封装成
|
||||
; 单个 Setup.exe 安装程序 (双击→安装向导→快捷方式→可卸载)。
|
||||
;
|
||||
; 构建 (本地):
|
||||
; 1. 先跑 PyInstaller: cd backend && uv run pyinstaller ../packaging/tickflow.spec
|
||||
; 2. 再跑 Inno Setup: ISCC.exe packaging\tickflow.iss
|
||||
; 3. 产物: packaging\Output\TickFlowStockPanel-Setup-x.x.x.exe
|
||||
; 3. 产物: packaging\Output\TSP-Setup-x.x.x.exe
|
||||
;
|
||||
; 设计决策:
|
||||
; - 装到用户目录 {localappdata}\Programs\ (不弹 UAC, 不需管理员)
|
||||
@@ -18,10 +18,10 @@
|
||||
; - 卸载入口 (控制面板可见)
|
||||
; ===========================================================================
|
||||
|
||||
#define MyAppName "TickFlow 股票面板"
|
||||
#define MyAppName "TSP 股票面板"
|
||||
#define MyAppNameEN "Tick Stock Panel"
|
||||
#define MyAppExeName "TickFlowStockPanel.exe"
|
||||
#define MyAppPublisher "TickFlow"
|
||||
#define MyAppExeName "TSP.exe"
|
||||
#define MyAppPublisher "TSP"
|
||||
|
||||
; 版本号: 从 frontend/package.json 读取, 与 Release tag 保持一致
|
||||
; 手动指定更可靠 (CI 传入 /DMyAppVersion)
|
||||
@@ -31,17 +31,20 @@
|
||||
|
||||
[Setup]
|
||||
; 基本信息
|
||||
; AppId 固定 GUID: Inno 默认从 AppName 派生, 一旦改名旧安装会变成重复程序;
|
||||
; 固定后应用名再调整也保持同一卸载/升级身份
|
||||
AppId={{B7F4C9E2-3A51-4D8E-9C60-5E8A2F1D7B43}
|
||||
AppName={#MyAppName}
|
||||
AppVerName={#MyAppName} {#MyAppVersion}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
; 默认装到 D 盘 (非系统盘), 用户可在向导中改任意位置
|
||||
; 若 D 盘不存在, [Code] 段 InitializeWizard 会自动回退到用户目录
|
||||
DefaultDirName=D:\TickFlowStockPanel
|
||||
DefaultDirName=D:\TSP
|
||||
DefaultGroupName={#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
OutputDir=Output
|
||||
OutputBaseFilename=TickFlowStockPanel-Setup-{#MyAppVersion}
|
||||
OutputBaseFilename=TSP-Setup-{#MyAppVersion}
|
||||
|
||||
; 关键: 不需要管理员权限, 永不弹 UAC
|
||||
; 装到 D 盘普通目录 (非 Program Files) 不需要管理员权限
|
||||
@@ -58,7 +61,9 @@ LZMAUseSeparateProcess=yes
|
||||
WizardStyle=modern
|
||||
DisableWelcomePage=no
|
||||
DisableReadyPage=no
|
||||
SetupIconFile=icon.ico
|
||||
; 安装向导/卸载图标: 直接引用品牌资产唯一来源 (brand/README 接入指引),
|
||||
; 不再使用 packaging/icon.ico 的旧手绘版本, 避免两处漂移
|
||||
SetupIconFile=..\brand\icon.ico
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
|
||||
; 卸载相关
|
||||
@@ -77,7 +82,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
|
||||
[Files]
|
||||
; 把 PyInstaller 产出的整个文件夹搬进安装目录
|
||||
; Source 路径相对于 .iss 文件所在目录
|
||||
Source: "..\backend\dist\TickFlowStockPanel\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "..\backend\dist\TSP\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
; 开始菜单
|
||||
@@ -139,7 +144,7 @@ begin
|
||||
// D 盘存在 → 用 D 盘; 否则回退用户目录 (无需管理员权限)
|
||||
if not DirExists('D:\') then
|
||||
begin
|
||||
DefaultDir := ExpandConstant('{localappdata}\Programs\TickFlowStockPanel');
|
||||
DefaultDir := ExpandConstant('{localappdata}\Programs\TSP');
|
||||
WizardForm.DirEdit.Text := DefaultDir;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
构建 (在项目根目录):
|
||||
cd frontend && pnpm build # 先构建前端到 frontend/dist
|
||||
pyinstaller packaging/tickflow.spec # 产物在 dist/TickFlowStockPanel/
|
||||
pyinstaller packaging/tickflow.spec # 产物在 dist/TSP/
|
||||
"""
|
||||
import sys
|
||||
from importlib.util import find_spec
|
||||
@@ -32,10 +32,10 @@ ROOT = Path(SPECPATH).parent
|
||||
FRONTEND_DIST = str(ROOT / "frontend" / "dist")
|
||||
TIERS_YAML = str(ROOT / "tiers.yaml")
|
||||
BUILTIN_STRATEGIES = str(ROOT / "backend" / "app" / "strategy" / "builtin")
|
||||
# 图标按平台选: Windows 用 .ico, macOS 用 .icns (PyInstaller 对 .ico 在
|
||||
# mac 上静默忽略, 不换格式 Dock/Finder 会显示通用图标)。两者都由
|
||||
# packaging/generate_icon.py 一并生成。
|
||||
APP_ICON = str(ROOT / "packaging" / ("icon.icns" if _IS_MACOS else "icon.ico"))
|
||||
# 图标按平台选: Windows 用 brand/icon.ico, macOS 用 brand/icon.icns —
|
||||
# 两者均由 brand/png/logo-tile-light-512.png 派生 (浅色圆角卡版, 品牌资产唯一来源,
|
||||
# 见 brand/README 接入指引), 无需 CI 现场生成。
|
||||
APP_ICON = str((ROOT / "brand" / "icon.icns") if _IS_MACOS else (ROOT / "brand" / "icon.ico"))
|
||||
|
||||
# ── 收集带原生库的依赖 (.libs/ 目录必须完整, 否则启动崩) ─────────────
|
||||
# polars / pyarrow / duckdb / fastexcel 都自带共享库子目录
|
||||
@@ -157,7 +157,7 @@ exe = EXE(
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="TickFlowStockPanel",
|
||||
name="TSP",
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
@@ -179,7 +179,7 @@ coll = COLLECT(
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
name="TickFlowStockPanel",
|
||||
name="TSP",
|
||||
)
|
||||
|
||||
# ── macOS: 封装成 .app 包 ────────────────────────────────────────────
|
||||
@@ -200,13 +200,13 @@ if _IS_MACOS:
|
||||
|
||||
app = BUNDLE(
|
||||
coll,
|
||||
name="TickFlowStockPanel.app",
|
||||
name="TSP.app",
|
||||
icon=APP_ICON,
|
||||
bundle_identifier="com.tickflow.stockpanel",
|
||||
version=APP_VERSION, # → CFBundleShortVersionString / CFBundleVersion
|
||||
info_plist={
|
||||
"CFBundleName": "Tick Stock Panel",
|
||||
"CFBundleDisplayName": "TickFlow 股票面板",
|
||||
"CFBundleDisplayName": "TSP 股票面板",
|
||||
"CFBundleVersion": APP_VERSION,
|
||||
"NSHighResolutionCapable": True,
|
||||
"LSMinimumSystemVersion": "10.13",
|
||||
|
||||
Reference in New Issue
Block a user