diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml deleted file mode 100644 index 3554578..0000000 --- a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - ./index.html - - --enable-nodejs - --mixed-context - - - - - true - - - - Panel - Designer Admin Panel - - - 800 - 1200 - - - 400 - 600 - - - - - - - - diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html deleted file mode 100644 index aa65222..0000000 --- a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - Designer Admin Panel - - - - -
-
-

加载中...

-
- - - - - - - - diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat deleted file mode 100644 index 75f09e0..0000000 --- a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat +++ /dev/null @@ -1,41 +0,0 @@ -@echo off -chcp 65001 >nul -echo ======================================== -echo CEP 扩展调试模式检查工具 -echo ======================================== -echo. - -echo [1] 检查当前 CEP 调试模式状态... -reg query "HKEY_CURRENT_USER\Software\Adobe\CSXS.8" /v PlayerDebugMode 2>nul -if %errorlevel% neq 0 ( - echo ❌ 未找到 CSXS.8 调试模式配置 -) else ( - echo ✅ CSXS.8 配置已存在 -) -echo. - -echo [2] 启用 CEP 调试模式... -reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.8" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul -reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.9" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul -reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.10" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul -reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.11" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul - -echo ✅ CEP 调试模式已启用(CSXS 8/9/10/11) -echo. - -echo [3] 检查插件安装位置... -set "EXT_DIR=%APPDATA%\Adobe\CEP\extensions\AdminPanel" -if exist "%EXT_DIR%\" ( - echo ✅ 插件已安装到: %EXT_DIR% - dir "%EXT_DIR%" /B -) else ( - echo ❌ 插件未安装,请运行安装命令 -) -echo. - -echo ======================================== -echo 操作完成! -echo 请 [完全关闭 Photoshop] 后重新打开 -echo ======================================== -pause - diff --git a/AI改图-双图.py b/AI改图-双图.py new file mode 100644 index 0000000..4fb70e9 --- /dev/null +++ b/AI改图-双图.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +双图合成处理 - 基于 multi_image_merge 方法 +使用 Gemini 3 Pro Image Preview 模型进行双图创意合成 + +特点: +- 支持本地图片和网络图片 URL 两种输入方式 +- 支持自定义提示词 +- 创意合成、场景融合 + +使用方法: +1. 安装依赖:pip install openai requests +2. 在下方配置区填入您的 API Key +3. 修改文件底部的参数变量 +4. 运行:python 双图合成处理.py + +获取 API Key:https://api.laozhang.ai/token +""" + +import base64 +import re +import os +from openai import OpenAI + +# ========== 配置区(请填入您的 API Key)========== +API_KEY = "sk-KZ9TGgZAWnzY1T3c90B277F72e184c26A53f22440e08E86e" # 替换为您的 API Key +BASE_URL = "https://api.laozhang.ai/v1" + +# 模型选择 +MODEL = "gemini-3-pro-image-preview" # 最新版,支持更高质量 +# MODEL = "gemini-2.5-flash-image" # 稳定版,价格更低($0.025 vs $0.05) +# ================================================ + + +def extract_and_save_image(content: str, filename: str) -> bool: + """从响应内容中提取 base64 图片并保存""" + # 匹配 markdown 格式的 base64 图片 + match = re.search(r'!\[.*?\]\((data:image/\w+;base64,([^)]+))\)', content) + if match: + base64_data = match.group(2) + # 确保 base64 填充正确 + padding = 4 - len(base64_data) % 4 + if padding != 4: + base64_data += '=' * padding + image_data = base64.b64decode(base64_data) + with open(filename, 'wb') as f: + f.write(image_data) + return True + return False + + +def is_url(path: str) -> bool: + """判断路径是否为 URL""" + return path.startswith('http://') or path.startswith('https://') + + +def multi_image_merge(image1_path: str, image2_path: str, prompt: str, output_filename: str = None) -> bool: + """ + 多图合成 + + 参数: + image1_path: 第一张图片路径(本地文件路径或 URL) + image2_path: 第二张图片路径(本地文件路径或 URL) + prompt: 合成提示词 + output_filename: 输出文件名(可选) + + 返回: 是否成功 + """ + print("\n" + "="*60) + print("🎨 双图合成处理") + print("="*60) + + client = OpenAI(api_key=API_KEY, base_url=BASE_URL) + + # 构建 content 数组 + content = [{"type": "text", "text": prompt}] + + # 处理第一张图片 + if is_url(image1_path): + # 网络图片 URL + content.append({"type": "image_url", "image_url": {"url": image1_path}}) + print(f"🖼️ 图片1 (URL): {image1_path[:50]}...") + else: + # 本地图片 Base64 + if not os.path.exists(image1_path): + print(f"❌ 错误:图片1不存在: {image1_path}") + return False + with open(image1_path, "rb") as f: + image1_b64 = base64.b64encode(f.read()).decode("utf-8") + content.append({ + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{image1_b64}" + } + }) + print(f"🖼️ 图片1 (本地): {image1_path}") + + # 处理第二张图片 + if is_url(image2_path): + # 网络图片 URL + content.append({"type": "image_url", "image_url": {"url": image2_path}}) + print(f"🖼️ 图片2 (URL): {image2_path[:50]}...") + else: + # 本地图片 Base64 + if not os.path.exists(image2_path): + print(f"❌ 错误:图片2不存在: {image2_path}") + return False + with open(image2_path, "rb") as f: + image2_b64 = base64.b64encode(f.read()).decode("utf-8") + content.append({ + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{image2_b64}" + } + }) + print(f"🖼️ 图片2 (本地): {image2_path}") + + print(f"📝 提示词: {prompt}") + print("📡 发送请求...") + + try: + response = client.chat.completions.create( + model=MODEL, + messages=[ + { + "role": "user", + "content": content + } + ] + ) + + result_content = response.choices[0].message.content + + # 确定输出文件名 + if output_filename: + output_file = output_filename + else: + output_file = "result_multi_merge.png" + + if extract_and_save_image(result_content, output_file): + print(f"✅ 成功!图片已保存: {output_file}") + return True + else: + print(f"⚠️ 未找到图片数据") + return False + + except Exception as e: + print(f"❌ 错误: {str(e)}") + return False + + +def main(): + """主函数""" + print("="*60) + print("🎨 双图合成处理") + print(f"模型: {MODEL}") + print("="*60) + + # 检查 API Key + if API_KEY == "sk-YOUR_API_KEY" or not API_KEY: + print("\n❌ 请先配置您的 API Key!") + print(" 获取地址: https://api.laozhang.ai/token") + print(" 然后修改脚本顶部的 API_KEY 变量") + return + + # 检查图片是否存在(仅本地文件) + if not is_url(IMAGE1_PATH) and not os.path.exists(IMAGE1_PATH): + print(f"\n❌ 错误:图片1文件不存在: {IMAGE1_PATH}") + print(" 请检查文件路径是否正确") + return + + if not is_url(IMAGE2_PATH) and not os.path.exists(IMAGE2_PATH): + print(f"\n❌ 错误:图片2文件不存在: {IMAGE2_PATH}") + print(" 请检查文件路径是否正确") + return + + print(f"\n📋 配置信息:") + print(f" 图片1: {IMAGE1_PATH}") + print(f" 图片2: {IMAGE2_PATH}") + print(f" 提示词: {PROMPT}") + print() + + # 执行合成 + result = multi_image_merge( + image1_path=IMAGE1_PATH, + image2_path=IMAGE2_PATH, + prompt=PROMPT, + output_filename=OUTPUT_FILENAME + ) + + if result: + print("\n" + "="*60) + print("🎉 合成完成!") + print("="*60) + else: + print("\n" + "="*60) + print("❌ 合成失败,请检查错误信息") + print("="*60) + + +# ========== 参数配置区(请修改以下参数)========== + +# 1. 第一张图片路径(支持本地文件路径或网络 URL) +IMAGE1_PATH = "5.png" # 本地文件示例: "1.png" 或 "C:/images/photo1.jpg" +# IMAGE1_PATH = "https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=800&q=80" # URL 示例 + +# 2. 第二张图片路径(支持本地文件路径或网络 URL) +IMAGE2_PATH = "6.png" # 本地文件示例: "2.png" 或 "C:/images/photo2.jpg" +# IMAGE2_PATH = "https://images.unsplash.com/photo-1560806887-1e4cd0b6cbd6?w=800&q=80" # URL 示例 + +# 3. 合成提示词(描述如何合成这两张图片) +PROMPT = "把第2张图的衣股花型图案替换成图1的花型图案" # 修改为您想要的合成效果描述 + +# 4. 输出文件名(可选,留空则使用默认名称) +OUTPUT_FILENAME = None # 例如: "合成结果.png" 或 None(使用默认名称) + +# ================================================ + + +if __name__ == "__main__": + main() + diff --git a/AdminPanel/dev.cep.config.ts b/AdminPanel/dev.cep.config.ts index 31f7831..17cd5aa 100644 --- a/AdminPanel/dev.cep.config.ts +++ b/AdminPanel/dev.cep.config.ts @@ -13,7 +13,7 @@ const config: ICepConfig = { "panels": [ { "name": "AdminPanel-dev", - "displayName": "管理面板", + "displayName": "ps套版", "main": "./index.html", "width": 280, "height": 600, diff --git a/AdminPanel/index.html b/AdminPanel/index.html index 512fe1a..83f75fa 100644 --- a/AdminPanel/index.html +++ b/AdminPanel/index.html @@ -7,6 +7,7 @@
+ diff --git a/AdminPanel/plugins/jsx/copyCepToDev.ts b/AdminPanel/plugins/jsx/copyCepToDev.ts index a696376..3a6a222 100644 --- a/AdminPanel/plugins/jsx/copyCepToDev.ts +++ b/AdminPanel/plugins/jsx/copyCepToDev.ts @@ -78,6 +78,13 @@ export class CEP { this.writeDebug() this.copyJson2() + // 确保 CEP 扩展目录存在 + const cepExtDir = getAdobeCepDir() + if (!fs.existsSync(cepExtDir)) { + fs.mkdirSync(cepExtDir, { recursive: true }) + console.log('[CEP] 已创建 CEP 扩展目录:', cepExtDir) + } + // 创建符号链接或直接复制 if (!fs.existsSync(this.cepLink)) { try { @@ -85,8 +92,8 @@ export class CEP { console.log('[CEP] 符号链接已创建') } catch (error: any) { // 权限不足时,改用复制 - if (error.code === 'EPERM') { - console.warn('[CEP] 符号链接权限不足,改用复制方式') + if (error.code === 'EPERM' || error.code === 'ENOENT') { + console.warn('[CEP] 符号链接创建失败,改用复制方式') this.copyToCepDir() } else { throw error @@ -160,7 +167,7 @@ export class CEP { } // 3. 复制并修正 HTML 路径 - const builtHtmlPath = path.join(this.dist, 'src/launcher/index.html') + const builtHtmlPath = path.join(this.dist, 'index.html') const targetHtmlPath = path.join(this.cepOutput, 'index.html') if (fs.existsSync(builtHtmlPath)) { diff --git a/temp_backup/AdminPanel_plugins_jsx_template/README.md b/AdminPanel/plugins/jsx/template/README.md similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/README.md rename to AdminPanel/plugins/jsx/template/README.md diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep.config.ts b/AdminPanel/plugins/jsx/template/cep.config.ts similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep.config.ts rename to AdminPanel/plugins/jsx/template/cep.config.ts diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/CSXS/manifest.xml b/AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/CSXS/manifest.xml rename to AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark.png b/AdminPanel/plugins/jsx/template/cep/img/dark.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark.png rename to AdminPanel/plugins/jsx/template/cep/img/dark.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@2x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@2x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@2x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@2x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@3x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@3x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@3x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@3x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@4x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@4x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/dark@4x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@4x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight.png b/AdminPanel/plugins/jsx/template/cep/img/highlight.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@2x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@2x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@2x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@2x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@3x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@3x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@3x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@3x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@4x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@4x.png similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/img/highlight@4x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@4x.png diff --git a/temp_backup/AdminPanel_plugins_jsx_template/cep/index.html b/AdminPanel/plugins/jsx/template/cep/index.html similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/cep/index.html rename to AdminPanel/plugins/jsx/template/cep/index.html diff --git a/temp_backup/AdminPanel_plugins_jsx_template/debug.ts b/AdminPanel/plugins/jsx/template/debug.ts similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/debug.ts rename to AdminPanel/plugins/jsx/template/debug.ts diff --git a/temp_backup/AdminPanel_plugins_jsx_template/html.ts b/AdminPanel/plugins/jsx/template/html.ts similarity index 60% rename from temp_backup/AdminPanel_plugins_jsx_template/html.ts rename to AdminPanel/plugins/jsx/template/html.ts index 4b89b4c..372b931 100644 --- a/temp_backup/AdminPanel_plugins_jsx_template/html.ts +++ b/AdminPanel/plugins/jsx/template/html.ts @@ -5,8 +5,8 @@ export function joinHtml(name:string,server:string){ ${name} diff --git a/temp_backup/AdminPanel_plugins_jsx_template/manifest.ts b/AdminPanel/plugins/jsx/template/manifest.ts similarity index 100% rename from temp_backup/AdminPanel_plugins_jsx_template/manifest.ts rename to AdminPanel/plugins/jsx/template/manifest.ts diff --git a/AdminPanel/public/vite.svg b/AdminPanel/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/AdminPanel/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/AdminPanel/src/App.vue b/AdminPanel/src/App.vue index 7f5a458..b280a88 100644 --- a/AdminPanel/src/App.vue +++ b/AdminPanel/src/App.vue @@ -5,10 +5,7 @@ - - -
-
-

正在连接服务器...

-

连接失败,请检查网络

-
- - - -`; - -// manifest.xml -const manifestTemplate = ` - - - - - - - ${CONFIG.hosts.map(h => ``).join('\n ')} - - - - - - - - - - - - - ./index.html - - --enable-nodejs - --mixed-context - - - - true - - - Panel - ${CONFIG.displayName} - - - ${CONFIG.panel.width} - ${CONFIG.panel.height} - - - ${CONFIG.panel.minWidth} - ${CONFIG.panel.minHeight} - - - - ./img/dark.png - ./img/highlight.png - ./img/dark.png - ./img/highlight.png - - - - - -`; - -// ========== 构建函数 ========== - -function copyFolder(src: string, dest: string) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest, { recursive: true }); - } - - const files = fs.readdirSync(src); - for (const file of files) { - const srcPath = path.join(src, file); - const destPath = path.join(dest, file); - - if (fs.statSync(srcPath).isDirectory()) { - copyFolder(srcPath, destPath); - } else { - fs.copyFileSync(srcPath, destPath); - } - } -} - -function build() { - console.log('🚀 构建客户端启动器...\n'); - - const outputDir = path.resolve(__dirname, '..', CONFIG.outputDir); - - // 1. 清理输出目录 - if (fs.existsSync(outputDir)) { - fs.rmSync(outputDir, { recursive: true }); - } - fs.mkdirSync(outputDir, { recursive: true }); - console.log('✓ 创建输出目录:', outputDir); - - // 2. 创建 CSXS 目录 - const csxsDir = path.join(outputDir, 'CSXS'); - fs.mkdirSync(csxsDir, { recursive: true }); - - // 3. 写入 index.html - fs.writeFileSync(path.join(outputDir, 'index.html'), htmlTemplate); - console.log('✓ 生成 index.html'); - - // 4. 写入 manifest.xml - fs.writeFileSync(path.join(csxsDir, 'manifest.xml'), manifestTemplate); - console.log('✓ 生成 CSXS/manifest.xml'); - - // 5. 复制图标 - const imgSrc = path.resolve(__dirname, '../plugins/jsx/template/cep/img'); - const imgDest = path.join(outputDir, 'img'); - if (fs.existsSync(imgSrc)) { - copyFolder(imgSrc, imgDest); - console.log('✓ 复制图标'); - } - - console.log('\n========================================'); - console.log('✅ 构建完成!'); - console.log('========================================'); - console.log(`📁 输出目录: ${outputDir}`); - console.log(`🔗 跳转地址: ${CONFIG.serverURL}`); - console.log('\n下一步:'); - console.log('1. 使用 ZXPSignCmd 签名打包成 .zxp'); - console.log('2. 或直接复制到 Adobe CEP 扩展目录测试'); -} - -// 执行 -build(); - diff --git a/temp_backup/Designer_redundant/test-simple.ts b/temp_backup/Designer_redundant/test-simple.ts deleted file mode 100644 index 77071dc..0000000 --- a/temp_backup/Designer_redundant/test-simple.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 超级简单的测试 - 验证最基础的 evalScript - */ - -import { cep } from "@/utils/cep"; - -/** - * 测试1:最简单的计算 - */ -export async function testSimpleCalc() { - try { - const result = await cep.evalScript("1 + 2 + 3"); - console.log('简单计算结果:', result); - return { success: true, result }; - } catch (error) { - console.error('简单计算失败:', error); - return { success: false, error: String(error) }; - } -} - -/** - * 测试2:获取应用名称(不依赖任何工具库) - */ -export async function testGetAppName() { - try { - const result = await cep.evalScript("app.name"); - console.log('应用名称:', result); - return { success: true, appName: result }; - } catch (error) { - console.error('获取应用名称失败:', error); - return { success: false, error: String(error) }; - } -} - -/** - * 测试3:创建图层(最简单版本,不依赖工具库) - */ -export async function testCreateLayerDirect() { - const jsx = ` - (function() { - try { - if (app.documents.length === 0) { - return "no_document"; - } - var doc = app.activeDocument; - var layer = doc.artLayers.add(); - layer.name = "TestLayer"; - return "success:" + layer.name; - } catch (e) { - return "error:" + e.toString(); - } - })() - `; - - try { - const result = await cep.evalScript(jsx); - console.log('创建图层结果:', result); - return { success: true, result }; - } catch (error) { - console.error('创建图层失败:', error); - return { success: false, error: String(error) }; - } -} - diff --git a/temp_backup/Server_redundant/create_user.py b/temp_backup/Server_redundant/create_user.py deleted file mode 100644 index a663676..0000000 --- a/temp_backup/Server_redundant/create_user.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys -import os - -# Add current directory to sys.path -sys.path.append(os.getcwd()) - -from app.db import SessionLocal -from app.services.auth_service import auth_service -from app.schemas.auth import UserRegister -from app.core.security import get_password_hash -from app.models.user import User - -def create_user(username, password, email=None): - db = SessionLocal() - try: - # Check if user exists - existing = db.query(User).filter(User.username == username).first() - if existing: - print(f"❌ 用户名 '{username}' 已存在") - return - - # Prepare registration data - # We bypass the code verification by not providing code, - # but we set email if provided. - # However, auth_service.register sets is_verified=False by default if code is missing. - # We might want to manually set is_verified=True after registration for convenience. - - register_data = UserRegister( - username=username, - password=password, - confirm_password=password, - email=email, - device_id="local_script" - ) - - # Call register service - try: - token = auth_service.register(db, register_data) - print(f"✅ 用户 '{username}' 注册成功!") - - # Manually verify the user for local convenience - user = db.query(User).filter(User.username == username).first() - if user: - user.is_verified = True - user.permissions = "admin" # Grant admin permissions for local test user - db.commit() - print(f"✅ 已自动验证邮箱并赋予 admin 权限") - - except Exception as e: - print(f"❌ 注册失败: {e}") - - finally: - db.close() - -if __name__ == "__main__": - if len(sys.path) < 2: - print("Usage: python create_user.py [username] [password]") - - username = "admin" - password = "password123" - email = "admin@example.com" - - if len(sys.argv) > 1: - username = sys.argv[1] - if len(sys.argv) > 2: - password = sys.argv[2] - - print(f"正在创建用户: {username} ...") - create_user(username, password, email) diff --git a/temp_backup/Server_redundant/init_db.py b/temp_backup/Server_redundant/init_db.py deleted file mode 100644 index 7edb66a..0000000 --- a/temp_backup/Server_redundant/init_db.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- -""" -数据库初始化脚本 -功能: -1. 检查数据库连接 -2. 创建所有定义的表(如果不存在) -3. 检查现有表的字段,如果缺失则自动添加 -""" - -import os -import sys -import logging -from sqlalchemy import create_engine, inspect, text -from app.core.config import settings -from app.db import Base -# 导入所有模型以确保它们被注册到 Base.metadata -from app.models import user, group, business, session - -# 配置日志 -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -def get_engine(): - """获取数据库引擎""" - # 优先使用环境变量中的配置,如果没有则构建 - db_url = settings.DATABASE_URL - if not db_url: - host = os.getenv('DB_HOST', 'localhost') - port = os.getenv('DB_PORT', '3306') - user = os.getenv('DB_USER', 'root') - password = os.getenv('DB_PASSWORD', '') - db_name = os.getenv('DB_NAME', 'designer_db') - db_url = f"mysql+pymysql://{user}:{password}@{host}:{port}/{db_name}" - - return create_engine(db_url) - -def map_python_type_to_sql(col_type): - """将 SQLAlchemy 类型映射为 MySQL 类型""" - type_str = str(col_type).lower() - if 'varchar' in type_str: - return type_str - if 'string' in type_str: - length = getattr(col_type, 'length', 255) - return f"varchar({length})" - if 'integer' in type_str or 'int' in type_str: - return "int" - if 'boolean' in type_str: - return "tinyint(1)" - if 'datetime' in type_str: - return "datetime" - if 'date' in type_str: - return "date" - if 'float' in type_str: - return "float" - if 'text' in type_str: - return "text" - return "varchar(255)" # 默认 - -def init_db(): - logger.info("🔄 开始数据库初始化检查...") - - try: - engine = get_engine() - inspector = inspect(engine) - - # 1. 创建缺失的表 - logger.info("📊 检查表结构...") - Base.metadata.create_all(bind=engine) - logger.info("✅ 基础表结构检查完成") - - # 2. 检查并补充缺失的列 - logger.info("🔍 检查缺失字段...") - - existing_tables = inspector.get_table_names() - - with engine.connect() as conn: - for table_name, table in Base.metadata.tables.items(): - if table_name not in existing_tables: - continue - - # 获取数据库中现有的列 - existing_columns = [col['name'] for col in inspector.get_columns(table_name)] - - # 检查模型定义的列 - for column in table.columns: - if column.name not in existing_columns: - logger.info(f" ➕ 发现缺失字段: {table_name}.{column.name}") - - # 构建 ALTER TABLE 语句 - col_type = map_python_type_to_sql(column.type) - default_val = "" - - # 处理默认值 (简化处理,只处理常见类型) - if column.default: - arg = column.default.arg - if isinstance(arg, (int, float, bool)): - if isinstance(arg, bool): - arg = 1 if arg else 0 - default_val = f" DEFAULT {arg}" - elif isinstance(arg, str): - default_val = f" DEFAULT '{arg}'" - - nullable = "NULL" if column.nullable else "NOT NULL" - if column.nullable and not default_val: - default_val = " DEFAULT NULL" - - sql = f"ALTER TABLE {table_name} ADD COLUMN {column.name} {col_type} {nullable}{default_val};" - logger.info(f" 🚀 执行: {sql}") - conn.execute(text(sql)) - - conn.commit() - logger.info("✅ 数据库同步完成!") - - except Exception as e: - logger.error(f"❌ 数据库初始化失败: {e}") - # 不抛出异常,以免阻断容器启动(如果是网络波动等临时问题) - # 但在生产环境中可能需要抛出 - -if __name__ == "__main__": - init_db() diff --git a/temp_backup/Server_redundant/init_db.sql b/temp_backup/Server_redundant/init_db.sql deleted file mode 100644 index 1938dc3..0000000 --- a/temp_backup/Server_redundant/init_db.sql +++ /dev/null @@ -1,170 +0,0 @@ --- ========================================== --- Database Initialization Script --- Generated at: 2025-12-22 17:54:23.463367 --- ========================================== - --- 1. Select Database and Cleanup Tables -USE designer_db; - -SET FOREIGN_KEY_CHECKS = 0; -DROP TABLE IF EXISTS check_in_config; -DROP TABLE IF EXISTS check_in_records; -DROP TABLE IF EXISTS features_config; -DROP TABLE IF EXISTS plugin_groups; -DROP TABLE IF EXISTS points_history; -DROP TABLE IF EXISTS vip_config; -DROP TABLE IF EXISTS users; -DROP TABLE IF EXISTS user_sessions; -SET FOREIGN_KEY_CHECKS = 1; - --- 2. Create Tables -CREATE TABLE check_in_config ( - id INTEGER NOT NULL AUTO_INCREMENT, - consecutive_days INTEGER NOT NULL, - base_points INTEGER NOT NULL, - bonus_points INTEGER NOT NULL, - total_points INTEGER NOT NULL, - enabled BOOL, - created_at DATETIME DEFAULT now(), - updated_at DATETIME, - PRIMARY KEY (id), - UNIQUE (consecutive_days) -); - -CREATE TABLE check_in_records ( - id INTEGER NOT NULL AUTO_INCREMENT, - user_id INTEGER NOT NULL, - username VARCHAR(50) NOT NULL, - check_in_date DATE NOT NULL, - points_earned INTEGER NOT NULL, - consecutive_days INTEGER NOT NULL, - vip_multiplier FLOAT, - created_at DATETIME DEFAULT now(), - PRIMARY KEY (id) -); - -CREATE TABLE features_config ( - id INTEGER NOT NULL AUTO_INCREMENT, - feature_key VARCHAR(50) NOT NULL, - feature_name VARCHAR(100) NOT NULL, - category VARCHAR(50), - points_cost INTEGER, - vip_points_cost INTEGER, - svip_points_cost INTEGER, - enabled BOOL, - description TEXT, - created_at DATETIME DEFAULT now(), - updated_at DATETIME, - PRIMARY KEY (id) -); - -CREATE TABLE plugin_groups ( - id INTEGER NOT NULL AUTO_INCREMENT, - name VARCHAR(64) NOT NULL, - current_version_file VARCHAR(255), - comment TEXT, - PRIMARY KEY (id) -); - -CREATE TABLE points_history ( - id INTEGER NOT NULL AUTO_INCREMENT, - user_id INTEGER NOT NULL, - username VARCHAR(50) NOT NULL, - type VARCHAR(20) NOT NULL, - amount INTEGER NOT NULL, - balance INTEGER NOT NULL, - description VARCHAR(255), - created_at DATETIME DEFAULT now(), - PRIMARY KEY (id) -); - -CREATE TABLE vip_config ( - id INTEGER NOT NULL AUTO_INCREMENT, - vip_type VARCHAR(20) NOT NULL, - name VARCHAR(50) NOT NULL, - price FLOAT NOT NULL, - daily_quota INTEGER NOT NULL, - points_multiplier FLOAT, - enabled BOOL, - description TEXT, - created_at DATETIME DEFAULT now(), - updated_at DATETIME, - PRIMARY KEY (id), - UNIQUE (vip_type) -); - -CREATE TABLE users ( - id INTEGER NOT NULL AUTO_INCREMENT, - username VARCHAR(64) NOT NULL, - hashed_password VARCHAR(128) NOT NULL, - created_at DATETIME NOT NULL DEFAULT now(), - group_id INTEGER, - permissions TEXT, - expire_date DATETIME, - email VARCHAR(255), - is_verified BOOL, - verification_code VARCHAR(6), - reset_token VARCHAR(128), - reset_token_expire DATETIME, - nickname VARCHAR(50), - avatar VARCHAR(500), - points INTEGER, - level INTEGER, - vip_type VARCHAR(20), - vip_expire DATETIME, - vip_daily_quota INTEGER, - vip_quota_reset_date DATE, - total_check_in_days INTEGER, - consecutive_check_in INTEGER, - last_check_in_date DATE, - PRIMARY KEY (id), - FOREIGN KEY(group_id) REFERENCES plugin_groups (id) -); - -CREATE TABLE user_sessions ( - id INTEGER NOT NULL AUTO_INCREMENT, - user_id INTEGER NOT NULL, - device_id VARCHAR(128) NOT NULL, - active BOOL NOT NULL, - expires_at DATETIME, - created_at DATETIME NOT NULL DEFAULT now(), - login_at DATETIME, - logout_at DATETIME, - duration_seconds INTEGER, - last_seen_at DATETIME, - PRIMARY KEY (id), - FOREIGN KEY(user_id) REFERENCES users (id) -); - --- 3. Insert Initial Data --- Default User Group -INSERT INTO plugin_groups (name, comment) VALUES ('default', 'Default User Group'); --- VIP Config -INSERT INTO vip_config (vip_type, name, price, daily_quota, points_multiplier) VALUES ('vip', 'VIP会员', 30.0, 20, 1.5); -INSERT INTO vip_config (vip_type, name, price, daily_quota, points_multiplier) VALUES ('svip', 'SVIP会员', 88.0, -1, 2.0); --- Check-in Config -INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (1, 10, 0, 10); -INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (3, 10, 5, 15); -INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (7, 10, 20, 30); --- Feature Config -INSERT INTO feature_configs (feature_key, feature_name, points_cost, category) VALUES ('ai_remove_bg', '智能抠图', 10, 'ai'); --- 4. Create Admin User (admin / password123) - -INSERT INTO users ( - username, hashed_password, email, is_verified, permissions, - group_id, nickname, level, vip_type, vip_expire, - created_at, points, total_check_in_days, consecutive_check_in, vip_daily_quota -) VALUES ( - 'admin', - '$2b$12$UsFjs3Jwn5BG7u/RJ1efNuTF4zIsjT.pSm1mQEBXGWKR.3Kakhpmq', - 'admin@example.com', - 1, - 'admin,vip,svip', - (SELECT id FROM plugin_groups WHERE name = 'default' LIMIT 1), - 'Administrator', - 999, - 'svip', - '2099-12-31 23:59:59', - NOW(), - 0, 0, 0, 0 -); diff --git a/temp_backup/Server_redundant/init_full_db.py b/temp_backup/Server_redundant/init_full_db.py deleted file mode 100644 index 2c4e43a..0000000 --- a/temp_backup/Server_redundant/init_full_db.py +++ /dev/null @@ -1,292 +0,0 @@ -# -*- coding: utf-8 -*- -""" -完整数据库初始化脚本 (Local Execution) -功能: -1. 重建数据库(DROP & CREATE DATABASE) -2. 创建所有表结构 -3. 创建默认数据(用户组、VIP配置、签到配置、功能配置) -4. 创建默认管理员账户 (admin/password123) - -注意:此脚本设计为在本地或 Docker 容器内运行,直接连接 MySQL。 -它会读取环境变量或使用默认配置。 -""" - -import logging -import os -import sys -import argparse -from datetime import datetime -from sqlalchemy.schema import CreateTable - -# 确保可以将当前目录添加到 sys.path -sys.path.append(os.getcwd()) - -from sqlalchemy import create_engine, text -from sqlalchemy.orm import sessionmaker -from sqlalchemy.engine.url import make_url - -# 尝试导入应用模块 -try: - from app.core.config import settings - from app.db import Base - from app.models import user, group, business, session - from app.models.user import User - from app.models.group import PluginGroup - from app.models.business import FeatureConfig, VipConfig, CheckInConfig - from app.core.security import get_password_hash -except ImportError: - print("❌ 无法导入应用模块,请确保在 Server 目录下运行此脚本") - print("示例: python scripts/init_full_db.py") - sys.exit(1) - -# 配置日志 -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') -logger = logging.getLogger(__name__) - -def generate_sql_file(): - """生成完整的初始化 SQL 文件""" - logger.info("📝 正在生成 SQL 文件 (init_db.sql) ...") - - # 获取数据库引擎 (用于编译 SQL) - # 我们使用一个 mock engine,因为我们只想要 SQL 语句 - engine = create_engine("mysql+pymysql://", strategy="mock", executor=lambda sql, *args, **kwargs: print(sql.compile(dialect=engine.dialect))) - - # 真正的 engine 用于 dialect 编译 - compile_engine = create_engine("mysql+pymysql://") - - sql_content = [] - - # 1. 准备数据库 - sql_content.append("-- ==========================================") - sql_content.append("-- Database Initialization Script") - sql_content.append(f"-- Generated at: {datetime.now()}") - sql_content.append("-- ==========================================\n") - - # 既然 DROP DATABASE 被禁用,我们切换到目标数据库,并尝试删除所有表 - sql_content.append("-- 1. Select Database and Cleanup Tables") - sql_content.append("USE designer_db;\n") - - # 获取所有表名并生成 DROP TABLE 语句 - # 注意:为了处理外键约束,我们先禁用外键检查 - sql_content.append("SET FOREIGN_KEY_CHECKS = 0;") - - for table in Base.metadata.sorted_tables: - sql_content.append(f"DROP TABLE IF EXISTS {table.name};") - - sql_content.append("SET FOREIGN_KEY_CHECKS = 1;\n") - - # 2. 创建表结构 - sql_content.append("-- 2. Create Tables") - for table in Base.metadata.sorted_tables: - create_table_sql = CreateTable(table).compile(compile_engine) - sql_content.append(str(create_table_sql).strip() + ";\n") - - # 3. 插入初始数据 - sql_content.append("-- 3. Insert Initial Data") - - # 用户组 - sql_content.append("-- Default User Group") - sql_content.append("INSERT INTO plugin_groups (name, comment) VALUES ('default', 'Default User Group');") - - # VIP 配置 - sql_content.append("-- VIP Config") - sql_content.append("INSERT INTO vip_config (vip_type, name, price, daily_quota, points_multiplier) VALUES ('vip', 'VIP会员', 30.0, 20, 1.5);") - sql_content.append("INSERT INTO vip_config (vip_type, name, price, daily_quota, points_multiplier) VALUES ('svip', 'SVIP会员', 88.0, -1, 2.0);") - - # 签到配置 - sql_content.append("-- Check-in Config") - sql_content.append("INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (1, 10, 0, 10);") - sql_content.append("INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (3, 10, 5, 15);") - sql_content.append("INSERT INTO checkin_config (consecutive_days, base_points, bonus_points, total_points) VALUES (7, 10, 20, 30);") - - # 功能配置 - sql_content.append("-- Feature Config") - sql_content.append("INSERT INTO feature_configs (feature_key, feature_name, points_cost, category) VALUES ('ai_remove_bg', '智能抠图', 10, 'ai');") - - # 4. 创建管理员 - sql_content.append("-- 4. Create Admin User (admin / password123)") - # 计算密码哈希 (这里直接计算一次固定的,避免每次运行不一样) - # password123 的 bcrypt hash (示例) - # 为了准确,我们还是用 python 算一下 - admin_hash = get_password_hash("password123") - - # 获取 default group id (假设是 1,因为刚刚插入且是第一个) - sql_content.append(f""" -INSERT INTO users ( - username, hashed_password, email, is_verified, permissions, - group_id, nickname, level, vip_type, vip_expire, - created_at, points, total_check_in_days, consecutive_check_in, vip_daily_quota -) VALUES ( - 'admin', - '{admin_hash}', - 'admin@example.com', - 1, - 'admin,vip,svip', - (SELECT id FROM plugin_groups WHERE name = 'default' LIMIT 1), - 'Administrator', - 999, - 'svip', - '2099-12-31 23:59:59', - NOW(), - 0, 0, 0, 0 -); -""") - - # 写入文件 - output_file = "init_db.sql" - with open(output_file, "w", encoding="utf-8") as f: - f.write("\n".join(sql_content)) - - logger.info(f"✅ SQL 文件已生成: {output_file}") - print(f"\nSQL 文件已生成: {os.path.abspath(output_file)}") - print("您可以直接在 phpMyAdmin 中导入此文件来初始化数据库。") - - -def get_db_url(): - """获取数据库连接 URL""" - # 优先使用 settings 中的配置 - # db_url = settings.DATABASE_URL - - # 用户指定的远程数据库 - # Host: 103.97.201.136 - # Port: 3388 (映射到了容器内的 3306) - # User: designer_user - # Pass: DesignerPass123! - db_url = "mysql+pymysql://designer_user:DesignerPass123!@103.97.201.136:3388/designer_db" - - # 如果 settings 是默认的 sqlite,尝试构建 mysql 连接(用于本地开发时的强制覆盖) - # if db_url.startswith("sqlite"): - # # 默认开发环境 Docker MySQL 配置 - # db_url = "mysql+pymysql://designer_user:DesignerPass123!@localhost:3306/designer_db" - # logger.info(f"⚠️ 检测到 SQLite 配置,切换为默认 MySQL 配置: {db_url}") - - logger.info(f"🔌 使用数据库配置: {db_url}") - return db_url - -def recreate_database(engine, db_name): - """重建数据库""" - logger.info(f"🗑️ 正在重建数据库: {db_name}...") - - # 获取 root 连接(连接到 mysql 系统库或不指定库) - url = make_url(engine.url) - root_url = url.set(database='mysql') - - # 使用 AUTOCOMMIT 隔离级别 - root_engine = create_engine(root_url, isolation_level="AUTOCOMMIT") - - with root_engine.connect() as conn: - conn.execute(text(f"DROP DATABASE IF EXISTS {db_name}")) - conn.execute(text(f"CREATE DATABASE {db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")) - logger.info(f"✅ 数据库 {db_name} 重建完成") - -def seed_initial_data(session): - """填充初始数据""" - logger.info("🌱 正在填充初始数据...") - - # 1. 默认用户组 - if session.query(PluginGroup).filter(PluginGroup.name == "default").count() == 0: - logger.info(" - 创建默认用户组 'default'") - default_group = PluginGroup(name="default", comment="Default User Group") - session.add(default_group) - - # 2. VIP 配置 - if session.query(VipConfig).count() == 0: - logger.info(" - 创建 VIP 配置") - session.add(VipConfig(vip_type="vip", name="VIP会员", price=30.0, daily_quota=20, points_multiplier=1.5)) - session.add(VipConfig(vip_type="svip", name="SVIP会员", price=88.0, daily_quota=-1, points_multiplier=2.0)) - - # 3. 签到配置 - if session.query(CheckInConfig).count() == 0: - logger.info(" - 创建签到配置") - session.add(CheckInConfig(consecutive_days=1, base_points=10, bonus_points=0, total_points=10)) - session.add(CheckInConfig(consecutive_days=3, base_points=10, bonus_points=5, total_points=15)) - session.add(CheckInConfig(consecutive_days=7, base_points=10, bonus_points=20, total_points=30)) - - # 4. 功能配置 - if session.query(FeatureConfig).count() == 0: - logger.info(" - 创建功能配置") - session.add(FeatureConfig(feature_key="ai_remove_bg", feature_name="智能抠图", points_cost=10, category="ai")) - - session.commit() - logger.info("✅ 初始数据填充完成") - -def create_admin_user(session): - """创建管理员用户""" - username = "admin" - password = "123456" - email = "admin@example.com" - - existing = session.query(User).filter(User.username == username).first() - if existing: - logger.info(f"ℹ️ 管理员用户 '{username}' 已存在,跳过创建") - return - - logger.info(f"👤 正在创建管理员用户: {username} ...") - - # 获取默认组 - default_group = session.query(PluginGroup).filter(PluginGroup.name == "default").first() - group_id = default_group.id if default_group else None - - new_user = User( - username=username, - hashed_password=get_password_hash(password), - email=email, - is_verified=True, - permissions="admin,vip,svip", # 赋予所有权限 - group_id=group_id, - nickname="Administrator", - level=999, - vip_type="svip", - vip_expire=datetime(2099, 12, 31) - ) - - session.add(new_user) - session.commit() - logger.info(f"✅ 管理员用户创建成功!(User: {username}, Pass: {password})") - -def main(): - parser = argparse.ArgumentParser(description='Initialize DesignerCEP Database') - parser.add_argument('--generate-sql', action='store_true', help='Generate init_db.sql file only') - args = parser.parse_args() - - if args.generate_sql: - generate_sql_file() - return - - logger.info("🚀 开始全量数据库初始化流程") - - try: - db_url = get_db_url() - engine = create_engine(db_url) - - # 1. 重建数据库 - # 注意:这会删除现有数据! - db_name = make_url(db_url).database - recreate_database(engine, db_name) - - # 重新连接到新创建的数据库 - target_engine = create_engine(db_url) - - # 2. 创建表结构 - logger.info("🏗️ 正在创建表结构...") - Base.metadata.create_all(bind=target_engine) - logger.info("✅ 表结构创建完成") - - # 3. 数据填充 - SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=target_engine) - session = SessionLocal() - - try: - seed_initial_data(session) - create_admin_user(session) - finally: - session.close() - - logger.info("✨✨✨ 数据库初始化全部完成! ✨✨✨") - - except Exception as e: - logger.error(f"❌ 初始化失败: {str(e)}") - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/temp_backup/Server_redundant/tempdemo/client/build.bat b/temp_backup/Server_redundant/tempdemo/client/build.bat deleted file mode 100644 index 1b17028..0000000 --- a/temp_backup/Server_redundant/tempdemo/client/build.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off - -rem D:\Python37\Scripts\pyinstaller.exe -w -i ./newapp.ico run.py - -pyinstaller -w -i ./newapp.ico run.py - -pause \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdemo/client/run.py b/temp_backup/Server_redundant/tempdemo/client/run.py deleted file mode 100644 index 47a74b3..0000000 --- a/temp_backup/Server_redundant/tempdemo/client/run.py +++ /dev/null @@ -1,396 +0,0 @@ -import os -import shutil -import sys -import tempfile -import time -import wmi -import psutil -import threading -import qtpy, platform -import winreg -from qtpy.QtCore import Qt, QMetaObject, Signal, Slot, QEvent -from qtpy.QtWidgets import QWidget, QVBoxLayout, QInputDialog, QHBoxLayout, QToolButton, QLabel, QSizePolicy, QSplashScreen -from PyQt5.QtGui import QIcon, QPixmap -import re -import hashlib -import configparser -from win32com.client import Dispatch -import ezdxf -import zipfile -import PyQt5 -from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QVBoxLayout, QWidget, QTabWidget, QPushButton, QLabel, QVBoxLayout, QWidget, QHBoxLayout, QFrame, QMessageBox -from PyQt5.QtGui import QIcon -from PyQt5.QtCore import Qt -import qdarktheme -import sys -import subprocess -import re -import hashlib -from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QGroupBox, \ - QSpacerItem, QSizePolicy, QMessageBox -import pymysql -import requests - -BASE_URL = "http://43.134.82.18/psmark" -#BASE_URL = "http://127.0.0.1:5001" - -tempdir = "" - -def exception_hook(exctype, value, traceback): - # Handle the uncaught exception - # 处理未捕获的异常 - QMessageBox.warning(None, "错误", f"发生了未知的异常:{value}") - - -class LoginDialog(QWidget): - def __init__(self): - super().__init__() - self.setWindowTitle("PSMARK登录界面") - self.setWindowIcon(QIcon("icons/newapp.ico")) # 设置窗口小图标,替换为您的图标文件路径 - - self.resize(300, 200) - - 主布局 = QVBoxLayout() - - group1 = QGroupBox("登录验证") - group1_layout = QVBoxLayout() - - group2 = QHBoxLayout() - label1 = QLabel("用户名") - self.edit1 = QLineEdit() - self.edit1.setFixedWidth(200) - spacer1 = QSpacerItem(40, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) - group2.addWidget(label1) - group2.addItem(spacer1) - group2.addWidget(self.edit1) - - group3 = QHBoxLayout() - label2 = QLabel("密码") - self.edit2 = QLineEdit() - self.edit2.setFixedWidth(200) - self.edit2.setEchoMode(QLineEdit.Password) # 设置密码输入框为密文 - spacer2 = QSpacerItem(40, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) - group3.addWidget(label2) - group3.addItem(spacer2) - group3.addWidget(self.edit2) - - group4 = QHBoxLayout() - button1 = QPushButton("登录") - button2 = QPushButton("注册") - group4.addWidget(button1) - group4.addWidget(button2) - - group1_layout.addLayout(group2) - group1_layout.addLayout(group3) - group1_layout.addLayout(group4) - group1.setLayout(group1_layout) - - 主布局.addWidget(group1) - - group5 = QHBoxLayout() - label3 = QLabel("机器码") - self.edit3 = QLineEdit() - self.edit3.setFixedWidth(200) - self.edit3.setReadOnly(True) - self.edit3.setFocusPolicy(Qt.NoFocus) - - # 获取主板序列号并提取数字部分 - '''try: - result = subprocess.run(['wmic', 'baseboard', 'get', 'serialnumber'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE, text=True) - motherboard_serial = result.stdout.strip() - - # 使用正则表达式提取数字 - motherboard_serial = re.sub(r'\D', '', motherboard_serial) - - # 使用SHA-256加密特征码 - feature_code = hashlib.sha256(motherboard_serial.encode()).hexdigest() - - # 去掉特征码中的英文字符 - feature_code = re.sub(r'[a-zA-Z]', '', feature_code) - except Exception as e: - feature_code = "Error: " + str(e)''' - # 计算序列号 - - try: - feature_code = self.get_computer_code() - count = ord(feature_code[0]) + ord(feature_code[1]) - for _ in range(count): - feature_code = hashlib.md5(feature_code.encode()).hexdigest().upper() - - except Exception as e: - feature_code = "Error: " + str(e) - - self.edit3.setText(feature_code) # 将加密后的特征码设置为 "特征码" 输入框的文本 - self.rem_user() - - spacer3 = QSpacerItem(10, 10, QSizePolicy.Fixed, QSizePolicy.Minimum) - group5.addWidget(label3) - group5.addItem(spacer3) - group5.addWidget(self.edit3) - - 主布局.addLayout(group5) - - self.setLayout(主布局) - - # 链接登录的点击事件 - button1.clicked.connect(self.slot_login) - # 连接注册按钮的点击事件 - button2.clicked.connect(self.register) - - def get_computer_code(self): - computer_code = '' - c = wmi.WMI() - for cpu in c.Win32_Processor(): - computer_code += cpu.ProcessorId.strip() - - key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\SQMClient", 0, winreg.KEY_READ | winreg.KEY_WOW64_64KEY) - # 读取设备ID - computer_code += winreg.QueryValueEx(key, "MachineId")[0].strip() - # 关闭注册表 - winreg.CloseKey(key) - - computer_code += str(subprocess.check_output('wmic csproduct get uuid').split(b'\n')[1].strip()) - - return computer_code - - def register(self): - - dialog = RegisterDialog() - if dialog.exec() != QDialog.Accepted: - return - - r = requests.post(BASE_URL + f"/register", data={ - "username":dialog.get用户名(), - "password":dialog.get密码(), - "code":self.edit3.text(), - "adminpassword":"qwe123456", - "truename":dialog.get姓名(), - "phone":dialog.get手机号(), - "company":dialog.get公司名(), - "address":dialog.get地址(), - }) - - if r.text == "success": - QMessageBox.information(self, "成功", "注册成功!") - - elif r.text == 'exist': - QMessageBox.critical(self, "错误", "用户已存在!") - - else: - QMessageBox.critical(self, "错误", f"注册失败!{r.text}") - - #记住密码 - def rem_user(self): - global tempdir - code = self.edit3.text() - - r = requests.post(BASE_URL + f"/query?code={code}") - with tempfile.TemporaryDirectory() as d: - dname = d - tempdir = dname + str(time.time()) - os.makedirs(tempdir) - - filepath = os.path.join(tempdir, "result.zip") - with open(filepath, 'wb') as f: - f.write(r.content) - - with zipfile.ZipFile(filepath, 'r') as zip_ref: - zip_ref.extractall(tempdir) - - with open(os.path.join(tempdir, "userinfo.txt"), 'r', encoding="utf-8") as f: - userinfo = f.read() - - if userinfo == 'error': - return - - self.edit1.setText(userinfo.split("\n")[0]) - self.edit2.setText(userinfo.split("\n")[1]) - - def slot_login(self): - global tempdir - user_name = self.edit1.text() - user_password = self.edit2.text() - code = self.edit3.text() - - # 判断缓存是否存在 - with open(os.path.join(tempdir, "userinfo.txt"), 'r', encoding="utf-8") as f: - userinfo = f.read() - if not (userinfo.split("\n")[0] == user_name and userinfo.split("\n")[1] == user_password): - r = requests.post(BASE_URL + f"/query?code={code}&username={user_name}&password={user_password}") - with tempfile.TemporaryDirectory() as d: - dname = d - tempdir = dname + str(time.time()) - os.makedirs(tempdir) - - filepath = os.path.join(tempdir, "result.zip") - with open(filepath, 'wb') as f: - f.write(r.content) - - with zipfile.ZipFile(filepath, 'r') as zip_ref: - zip_ref.extractall(tempdir) - - with open(os.path.join(tempdir, "userinfo.txt"), 'r', encoding="utf-8") as f: - userinfo = f.read() - - if userinfo == 'error': - QMessageBox.critical(self, "错误", "机器码或账号密码错误!") - return - - with zipfile.ZipFile(os.path.join(tempdir, "data.zip"), 'r') as zip_ref: - zip_ref.extractall(tempdir) - - #print(tempdir) - - cwd = os.getcwd() - sys.path.insert(0, tempdir) - os.chdir(tempdir) - - import piece_decorative - piece_decorative.config = configparser.ConfigParser() - - os.chdir(cwd) - piece_decorative.config.read('config.ini', encoding='utf-8') - piece_decorative.PSname = piece_decorative.config.get('程序配置', 'PSname') - os.chdir(tempdir) - - import newMark - #self.hide() - self.window = newMark.MainWindow() - self.window.show() - self.close() - #print("run") - #newMark.run() - - - def show_warning_message(self): - # 弹出警告消息框 - QMessageBox.critical(self, "错误", "请联系管理员 17520145271!") - # warning_message = QMessageBox() - # warning_message.setIcon(QMessageBox.Warning) - # warning_message.setWindowTitle("警告") - # warning_message.setText("请联系管理员 17520145271") - # warning_message.exec_() - -from PyQt5.QtWidgets import QDialogButtonBox, QFormLayout -from PyQt5.QtGui import QIntValidator -import re -class RegisterDialog(QDialog): - '''注册对话框''' - def __init__(self): - super(RegisterDialog,self).__init__() - self.init_gui() - - def init_gui(self): - #设置dialog窗口标题 - self.setWindowTitle("注册") - # 设置界面尺寸大小 - self.resize(500, 260) - - self.用户名QLineEdit = QLineEdit() - self.密码QLineEdit = QLineEdit() - self.密码QLineEdit.setEchoMode(QLineEdit.Password) - self.确认密码QLineEdit = QLineEdit() - self.确认密码QLineEdit.setEchoMode(QLineEdit.Password) - self.姓名QLineEdit = QLineEdit() - self.手机号QLineEdit = QLineEdit() - #self.手机号QLineEdit.setValidator(QIntValidator()) - self.公司名QLineEdit = QLineEdit() - self.地址QLineEdit = QLineEdit() - - self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) - self.buttons.accepted.connect(self.check) - self.buttons.rejected.connect(self.reject) - - # 表单布局,当然也可以使用其它布局方式 - layout = QFormLayout(self) - layout.addRow('用户名(用于登录):', self.用户名QLineEdit) - layout.addRow('密码(用于登录):', self.密码QLineEdit) - layout.addRow('确认密码:', self.确认密码QLineEdit) - layout.addRow('姓名:', self.姓名QLineEdit) - layout.addRow('手机号(+86):', self.手机号QLineEdit) - layout.addRow('公司名:', self.公司名QLineEdit) - layout.addRow('地址:', self.地址QLineEdit) - layout.addRow(self.buttons) - - def get用户名(self): - return self.用户名QLineEdit.text().strip() - - def get密码(self): - return self.密码QLineEdit.text().strip() - - def get确认密码(self): - return self.确认密码QLineEdit.text().strip() - - def get姓名(self): - return self.姓名QLineEdit.text().strip() - - def get手机号(self): - return self.手机号QLineEdit.text().strip() - - def get公司名(self): - return self.公司名QLineEdit.text().strip() - - def get地址(self): - return self.地址QLineEdit.text().strip() - - def check(self): - if self.get用户名() == '' or self.get密码() == '' or self.get姓名() == '' or self.get手机号() == '' or self.get公司名() == '' or self.get地址() == '': - QMessageBox.critical(self, "错误", "信息不完整!") - return - - if self.get密码() != self.get确认密码(): - QMessageBox.critical(self, "错误", "两次密码不一致!") - return - - t = re.compile(r'[1-9][0-9]{10}') - s = re.search(t, self.get手机号()) - if (not s) or (not self.get手机号().startswith('1')) or (len(self.get手机号()) != 11): - QMessageBox.critical(self, "错误", "手机号格式错误!") - return - - self.accept() - - -def main(): - - app3 = QApplication(sys.argv) - sys.excepthook = exception_hook # 设置全局异常处理 - - splash = QSplashScreen() - splash.setPixmap(QPixmap('./splash.png')) - splash.show() - app3.processEvents() - - qdarktheme.setup_theme( - custom_colors={ - "[dark]": { - "background": "#4d4d4d", - "foreground": "#ffffff", - "primary": "#ffffff", - "border": "#717070", - } - } - ) - login_dialog = LoginDialog() - login_dialog.show() - splash.finish(login_dialog) # 启动画面完成启动 - # window = MainWindow() - # window.show() - r = app3.exec_() - time.sleep(1) - os.chdir("C:") - try: - if tempdir != "": - shutil.rmtree(tempdir, ignore_errors=True) - #print("temp dir remove ok:", tempdir) - except Exception as e: - print(e) - - sys.exit(r) - - -if __name__ == '__main__': - main() - - diff --git a/temp_backup/Server_redundant/tempdemo/client/run.spec b/temp_backup/Server_redundant/tempdemo/client/run.spec deleted file mode 100644 index b77b5d6..0000000 --- a/temp_backup/Server_redundant/tempdemo/client/run.spec +++ /dev/null @@ -1,51 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- - - -block_cipher = None - - -a = Analysis( - ['run.py'], - pathex=[], - binaries=[], - datas=[], - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False, -) -pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) - -exe = EXE( - pyz, - a.scripts, - [], - exclude_binaries=True, - name='run', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=False, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon=['newapp.ico'], -) -coll = COLLECT( - exe, - a.binaries, - a.zipfiles, - a.datas, - strip=False, - upx=True, - upx_exclude=[], - name='run', -) diff --git a/temp_backup/Server_redundant/tempdemo/client/splash.png b/temp_backup/Server_redundant/tempdemo/client/splash.png deleted file mode 100644 index b2d7f74..0000000 Binary files a/temp_backup/Server_redundant/tempdemo/client/splash.png and /dev/null differ diff --git a/temp_backup/Server_redundant/tempdemo/psmark/JSX25.py b/temp_backup/Server_redundant/tempdemo/psmark/JSX25.py deleted file mode 100644 index 5df194f..0000000 --- a/temp_backup/Server_redundant/tempdemo/psmark/JSX25.py +++ /dev/null @@ -1,6 +0,0 @@ -dxf25_jscode = """ - -alert("接口测试") - - -""" \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdemo/psmark/Tab6.py b/temp_backup/Server_redundant/tempdemo/psmark/Tab6.py deleted file mode 100644 index d2b3cb9..0000000 --- a/temp_backup/Server_redundant/tempdemo/psmark/Tab6.py +++ /dev/null @@ -1,226 +0,0 @@ -import json -import os -#import replicate -import requests -from PyQt5 import QtWidgets, QtGui, QtCore - -# from dotenv import load_dotenv -import os - -# load_dotenv() # 加载 .env 文件中的环境变量 -url = 'http://43.139.183.222:5000' - - - - -class ImportPDFDialog6(QtWidgets.QWidget): - def __init__(self): - super().__init__() - self.initUI() - self.processed_image_path = None # 存储处理后的图片路径 - - def initUI(self): - self.setWindowTitle('图像处理参数输入') - - # 布局 - layout = QtWidgets.QVBoxLayout() - - # 文件选择行 - self.file_input = QtWidgets.QLineEdit(self) - # self.file_input.setPlaceholderText("选择文件路径 (如 1.jpg)") - layout.addWidget(self.file_input) - - self.browse_button = QtWidgets.QPushButton('浏览', self) - self.browse_button.clicked.connect(self.browse_file) - layout.addWidget(self.browse_button) - - self.prompt_input = QtWidgets.QLineEdit(self) - self.prompt_input.setPlaceholderText("提示词 ") - layout.addWidget(self.prompt_input) - - self.creativity_input = QtWidgets.QDoubleSpinBox(self) - self.creativity_input.setRange(0, 1) - self.creativity_input.setSingleStep(0.01) - self.creativity_input.setValue(0.35) # 默认值 - layout.addWidget(QtWidgets.QLabel("创造力 (0 - 3):")) - layout.addWidget(self.creativity_input) - - self.resemblance_input = QtWidgets.QDoubleSpinBox(self) - self.resemblance_input.setRange(0, 3) - self.resemblance_input.setSingleStep(0.01) - self.resemblance_input.setValue(0.6) # 默认值 - layout.addWidget(QtWidgets.QLabel("相似度 (0 - 3):")) - layout.addWidget(self.resemblance_input) - - self.scale_factor_input = QtWidgets.QSpinBox(self) - self.scale_factor_input.setRange(2, 8) - self.scale_factor_input.setValue(2) # 默认值 - layout.addWidget(QtWidgets.QLabel("放大倍数:")) - layout.addWidget(self.scale_factor_input) - - self.submit_button = QtWidgets.QPushButton('提交', self) - self.submit_button.clicked.connect(self.submit) - layout.addWidget(self.submit_button) - - # 合并图片显示和处理结果区域 - self.output_area = QtWidgets.QVBoxLayout() - self.image_label = QtWidgets.QLabel(self) - # self.image_label.setText("加载的图片将显示在这里") - self.image_label.setAlignment(QtCore.Qt.AlignCenter) - self.output_area.addWidget(self.image_label) - - self.result_display = QtWidgets.QTextEdit(self) - self.result_display.setReadOnly(True) - self.output_area.addWidget(QtWidgets.QLabel("处理结果:")) - self.output_area.addWidget(self.result_display) - - layout.addLayout(self.output_area) - - # 下载按钮 - self.download_button = QtWidgets.QPushButton('下载', self) - self.download_button.clicked.connect(self.download_image) - self.download_button.setEnabled(False) # 初始不可用 - layout.addWidget(self.download_button) - - self.setLayout(layout) - - def browse_file(self): - options = QtWidgets.QFileDialog.Options() - file_name, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择图像文件", "", "Image Files (*.png *.jpg *.jpeg *.bmp)", options=options) - if file_name: - self.file_input.setText(file_name) - self.display_image(file_name) # 显示选中的图片 - - def display_image(self, file_path): - pixmap = QtGui.QPixmap(file_path) - self.image_label.setPixmap(pixmap.scaled(300, 300, QtCore.Qt.KeepAspectRatio)) - - def upload_image(self, url, file_path, json_data): - imgurl = url + "/upload" - with open(file_path, 'rb') as file: - files = {'file': file} - data = {'data': json.dumps(json_data)} # 将 JSON 数据转换为字符串 - response = requests.post(imgurl, files=files, data=data) - - print(response.status_code) - response_json = response.json() # 先解析 JSON 响应 - - print(response_json) # 打印响应内容以检查其格式 - - # 确保响应是一个列表,并且至少有一个元素 - if isinstance(response_json, list) and len(response_json) > 0: - self.processed_image_path = response_json[0] # 从列表中获取 URL - else: - # 处理不符合预期的情况 - print("Unexpected response format:", response_json) - return - - self.result_display.setPlainText(str(response_json)) # 显示处理结果 - self.download_button.setEnabled(True) # 启用下载按钮 - self.display_processed_image() # 显示处理后的图片 - - def submit(self): - try: - creativity = self.creativity_input.value() - file_path = self.file_input.text() - urlprompt = self.prompt_input.text() + " best quality, highres, " - prompt = urlprompt - resemblance = self.resemblance_input.value() - scale_factor = self.scale_factor_input.value() - - if not os.path.exists(file_path): - raise ValueError("文件不存在,请选择有效的文件。") - - input_data = { - "seed": 1337, - "prompt": prompt, - "dynamic": 6, - "handfix": "disabled", - "pattern": False, - "sharpen": 0, - "sd_model": "juggernaut_reborn.safetensors [338b85bc4f]", - "scheduler": "DPM++ 3M SDE Karras", - "creativity": creativity, - "lora_links": "", - "downscaling": False, - "resemblance": resemblance, - "scale_factor": scale_factor, - "tiling_width": 112, - "tiling_height": 144, - "output_format": "png", - "custom_sd_model": "", - "negative_prompt": "(worst quality, low quality, normal quality:2) JuggernautNegative-neg", - "num_inference_steps": 18, - "downscaling_resolution": 768 - } - - # 确保调用时只传递三个参数 - self.upload_image(url, file_path, input_data) - - except Exception as e: - QtWidgets.QMessageBox.critical(self, "错误", str(e)) - - - def run(url): - - newurl = url + "/data" - data = {'key': 'value'} # 你要发送的数据 - response = requests.post(newurl, json=data) - - print(response.status_code) # 打印状态码 - print(response.json()) # 打印返回的 JSON 数据 - - def run2(url): - - newurl = url + "/dataimg" - data = {'key': 'value'} # 你要发送的数据 - response = requests.post(newurl, json=data) - - print(response.status_code) # 打印状态码 - print(response.json()) # 打印返回的 JSON 数据 - - - # if __name__ == '__main__': - # upload_image(url, '1.jpg', {'key': 'value'}) - - - - def display_processed_image(self): - # 下载并显示处理后的图片 - response = requests.get(self.processed_image_path) - if response.status_code == 200: - pixmap = QtGui.QPixmap() - pixmap.loadFromData(response.content) - self.image_label.setPixmap(pixmap.scaled(300, 300, QtCore.Qt.KeepAspectRatio)) - - def download_image(self): - if self.processed_image_path: - image_url = self.processed_image_path - - file_name, _ = QtWidgets.QFileDialog.getSaveFileName(self, "保存处理后的图片", "", "Image Files (*.png *.jpg *.jpeg)") - if file_name: - try: - response = requests.get(image_url) - response.raise_for_status() # 检查请求是否成功 - with open(file_name, 'wb') as f: - f.write(response.content) - QtWidgets.QMessageBox.information(self, "成功", "图片下载完成!") - except requests.exceptions.RequestException as e: - QtWidgets.QMessageBox.critical(self, "错误", f"下载失败:{e}") - except Exception as e: - QtWidgets.QMessageBox.critical(self, "错误", f"文件保存失败:{e}") - - -if __name__ == '__main__': - import sys - - app = QtWidgets.QApplication(sys.argv) - - # 创建并显示登录界面 - # login_dialog = LoginDialog() - # if login_dialog.exec_() == QtWidgets.QDialog.Accepted: - # 只有在登录成功后才执行以下代码 - ex = ImportPDFDialog6() - ex.show() - - sys.exit(app.exec_()) \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdemo/psmark/icons/newapp.ico b/temp_backup/Server_redundant/tempdemo/psmark/icons/newapp.ico deleted file mode 100644 index b0c3a96..0000000 Binary files a/temp_backup/Server_redundant/tempdemo/psmark/icons/newapp.ico and /dev/null differ diff --git a/temp_backup/Server_redundant/tempdemo/psmark/newapp.ico b/temp_backup/Server_redundant/tempdemo/psmark/newapp.ico deleted file mode 100644 index b0c3a96..0000000 Binary files a/temp_backup/Server_redundant/tempdemo/psmark/newapp.ico and /dev/null differ diff --git a/temp_backup/Server_redundant/tempdemo/psmark/程序配置.ini b/temp_backup/Server_redundant/tempdemo/psmark/程序配置.ini deleted file mode 100644 index 39de412..0000000 --- a/temp_backup/Server_redundant/tempdemo/psmark/程序配置.ini +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- - -[程序配置] -ps应用名 = Photoshop.Application diff --git a/temp_backup/Server_redundant/tempdemo/serveradmin/adminpassword.txt b/temp_backup/Server_redundant/tempdemo/serveradmin/adminpassword.txt deleted file mode 100644 index 5c62a18..0000000 --- a/temp_backup/Server_redundant/tempdemo/serveradmin/adminpassword.txt +++ /dev/null @@ -1 +0,0 @@ -qwe123456 \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdemo/serveradmin/server.py b/temp_backup/Server_redundant/tempdemo/serveradmin/server.py deleted file mode 100644 index 453b764..0000000 --- a/temp_backup/Server_redundant/tempdemo/serveradmin/server.py +++ /dev/null @@ -1,177 +0,0 @@ -from flask import * - -import os -import pymysql -import tempfile -import shutil -from zipfile import ZipFile -import datetime - -#================================================================================================== - -app = Flask(__name__) - -ADMIN_USERNAME = "admin" -ADMIN_PASSWORD = "fo847543jfrgowjfa8otu43" - -#================================================================================================== -def get_connect(): - host = "rm-bp1s36ps814qp23b7uo.mysql.rds.aliyuncs.com" - user = "zw1847930177" - password = "Zuowei1216" - database = "program" - charset = "utf8" - port = 3306 - conn = pymysql.connect(host=host, user=user, password=password, database=database, charset=charset, port=port) - return conn - -def getallusers(): - try: - conn = get_connect() - cur = conn.cursor(pymysql.cursors.DictCursor) - cur.execute(f'select * from user;') - user_data = cur.fetchall() - return user_data - - finally: - cur.close() - conn.close() - -def new_users(username, password, code): - conn = get_connect() - cur = conn.cursor(pymysql.cursors.DictCursor) - cur.execute(f"""INSERT INTO `program`.`user` (`username`, `password`, `code`, `expiredate`) VALUES ('{username}', '{password}', '{code}', '{(datetime.datetime.now() + datetime.timedelta(days=14)).strftime("%Y-%m-%d %H:%M:%S")}');""") - conn.commit() - - -#================================================================================================== - -def 无code(): - userinfo_filepath = os.path.join("tmp", "userinfo.txt") - with open(userinfo_filepath, 'w') as f: - f.write("error") - with ZipFile(os.path.join("tmp", 'result.zip'), 'w') as z: - z.write(userinfo_filepath, arcname="userinfo.txt") - - return send_from_directory("tmp", "result.zip", as_attachment=True) - -def 错误的用户名或密码(): - userinfo_filepath = os.path.join("tmp", "userinfo.txt") - with open(userinfo_filepath, 'w') as f: - f.write("error") - with ZipFile(os.path.join("tmp", 'result.zip'), 'w') as z: - z.write(userinfo_filepath, arcname="userinfo.txt") - return send_from_directory("tmp", "result.zip", as_attachment=True) - -#================================================================================================== -def 返回正常数据(username, password): - - userinfo_filepath = os.path.join("tmp", "userinfo.txt") - with open(userinfo_filepath, 'w', encoding='utf-8') as f: - f.write(f"{username}\n{password}") - - with open("using.txt", 'r') as f: - shutil.copyfile(f"archives/{f.read()}.zip", os.path.join("tmp", "data.zip")) - - with ZipFile(os.path.join("tmp", 'result.zip'), 'w') as z: - z.write(userinfo_filepath, arcname="userinfo.txt") - z.write(os.path.join("tmp", "data.zip"), arcname="data.zip") - - return send_from_directory("tmp", "result.zip", as_attachment=True) - - -#================================================================================================== -@app.route("/query", methods=["POST"]) -def query(): - username = request.args.get("username", "") - password = request.args.get("password", "") - code = request.args.get("code", "") - - allusers = getallusers() - - if code == "": - return 无code() - - if username == "" and password == "": - for user in allusers: - if code == user["code"] and (user["expiredate"] - datetime.datetime.now()).total_seconds() > 0: - return 返回正常数据(user["username"], user["password"]) - else: - for user in allusers: - if username == user["username"] and password == user["password"] and code == user["code"] and (user["expiredate"] - datetime.datetime.now()).total_seconds() > 0: - return 返回正常数据(user["username"], user["password"]) - - return 错误的用户名或密码() - -#================================================================================================== -# 设置使用的档案 -@app.route("/set_using_archives", methods=["POST"]) -def set_using_archives(): - # 检查权限 - username = request.form.get("username", "") - password = request.form.get("password", "") - - if not (username == ADMIN_USERNAME and password == ADMIN_PASSWORD): - abort(403) - - result = request.form.get("result") - - if result not in [os.path.basename(a).split('.')[0] for a in os.listdir("archives")]: - return 'error' - - with open("using.txt", 'w') as f: - f.write(result) - - return 'OK' -#================================================================================================== -# 获取正在使用的档案名称 -@app.route("/get_using_archives_name", methods=["GET"]) -def get_using_archives_name(): - with open("using.txt", 'r') as f: - return f.read() -#================================================================================================== -# 注册 -@app.route("/register", methods=["POST"]) -def register(): - if request.method == "POST": - username = request.form.get("username") - password = request.form.get("password") - code = request.form.get("code") - adminpassword = request.form.get("adminpassword") - - with open("adminpassword.txt", 'r') as f: - true_adminpassword = f.read().strip() - - if adminpassword != true_adminpassword: - return "error" - - else: - new_users(username, password, code) - return 'success' - -#================================================================================================== -@app.route("/archives", methods=["GET", "POST"]) -def archives(): - if request.method == "GET": - # 获取档案列表 - archives = os.listdir("archives") - archives = [os.path.basename(a).split(".")[0] for a in archives] - return jsonify(archives) - - elif request.method == "POST": - # 上传档案 - username = request.form.get("username") - password = request.form.get("password") - - if not (username == ADMIN_USERNAME and password == ADMIN_PASSWORD): - abort(403) - - file = request.files['file'] - file.save(f"./archives/{str(datetime.datetime.now()).split('.')[0].replace(':', '')}.zip") - - return 'OK' - -if __name__ == "__main__": - app.run(host="0.0.0.0", port=5001, debug=True) - - diff --git a/temp_backup/Server_redundant/tempdemo/serveradmin/using.txt b/temp_backup/Server_redundant/tempdemo/serveradmin/using.txt deleted file mode 100644 index d315e97..0000000 --- a/temp_backup/Server_redundant/tempdemo/serveradmin/using.txt +++ /dev/null @@ -1 +0,0 @@ -2023-09-09 010039 \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdemo/update_version.py.bak b/temp_backup/Server_redundant/tempdemo/update_version.py.bak deleted file mode 100644 index 2437fb3..0000000 --- a/temp_backup/Server_redundant/tempdemo/update_version.py.bak +++ /dev/null @@ -1,11 +0,0 @@ -import sqlite3 -conn = sqlite3.connect('designercep.db') - -# Update plugin_groups table - column is current_version_file not version -conn.execute("UPDATE plugin_groups SET current_version_file = 'core-v1.3.0.zip' WHERE id=1") -conn.commit() -print('Updated Default group to core-v1.0.5.zip') - -cursor = conn.execute('SELECT * FROM plugin_groups') -print(list(cursor)) -conn.close() diff --git a/temp_backup/Server_redundant/tempdocs/API_DOCUMENTATION.md b/temp_backup/Server_redundant/tempdocs/API_DOCUMENTATION.md deleted file mode 100644 index c31e085..0000000 --- a/temp_backup/Server_redundant/tempdocs/API_DOCUMENTATION.md +++ /dev/null @@ -1,113 +0,0 @@ -# DesignerCEP 认证模块接口文档 - -本文档描述了后端新增的邮箱注册验证与密码重置相关接口。 - -## 1. 注册 (Register) - -支持传入邮箱进行注册。如果传入邮箱,系统将发送验证码邮件。 - -- **URL**: `/api/v1/auth/register` -- **Method**: `POST` -- **Request Body**: - ```json - { - "username": "user1", - "password": "password123", - "confirm_password": "password123", - "email": "user1@gmail.com", // [新增] 可选,推荐填写 - "device_id": "device_unique_id" - } - ``` -- **Response**: - - Success (200): - ```json - { - "access_token": "eyJhbGciOiJIUzI1NiIsIn...", - "token_type": "bearer", - "username": "user1" - } - ``` - - Error (400): 用户名已存在 / 邮箱已存在 / 密码不一致 - -## 2. 验证邮箱 (Verify Email) - -用户收到验证码邮件后,在前端输入验证码进行验证。 - -- **URL**: `/api/v1/auth/verify-email` -- **Method**: `POST` -- **Request Body**: - ```json - { - "username": "user1", - "code": "123456" // 邮件中的6位数字验证码 - } - ``` -- **Response**: - - Success (200): - ```json - { - "detail": "验证成功" - } - ``` - - Error (400): 验证码错误 - -## 3. 忘记密码 (Forgot Password) - -用户输入注册邮箱,请求重置密码。 - -- **URL**: `/api/v1/auth/forgot-password` -- **Method**: `POST` -- **Request Body**: - ```json - { - "email": "user1@gmail.com" - } - ``` -- **Response**: - - Success (200): - ```json - { - "detail": "如果邮箱存在,重置邮件已发送" - } - ``` - -## 4. 重置密码 (Reset Password) - -用户点击邮件中的链接(或手动输入Token),设置新密码。 - -- **URL**: `/api/v1/auth/reset-password` -- **Method**: `POST` -- **Request Body**: - ```json - { - "token": "reset_token_from_email", - "new_password": "new_password123", - "confirm_password": "new_password123" - } - ``` -- **Response**: - - Success (200): - ```json - { - "detail": "密码重置成功" - } - ``` - - Error (400): Token 无效 / Token 已过期 / 密码不一致 - -## 流程说明 - -1. **注册流程**: - - 用户填写注册信息(含邮箱)。 - - 提交 `/register`。 - - 如果成功,后端自动登录并返回 Token。 - - 如果填写了邮箱,后端会发送一封验证邮件。 - - 前端提示用户查收邮件并输入验证码。 - - 用户输入验证码,前端调用 `/verify-email`。 - -2. **找回密码流程**: - - 用户点击“忘记密码”。 - - 输入邮箱,前端调用 `/forgot-password`。 - - 用户收到邮件,包含重置 Token。 - - 前端提供重置密码界面,用户输入新密码。 - - 前端调用 `/reset-password`(带上 Token 和新密码)。 - - 重置成功后,跳转至登录页。 diff --git a/temp_backup/Server_redundant/tempdocs/API密钥使用指南.md b/temp_backup/Server_redundant/tempdocs/API密钥使用指南.md deleted file mode 100644 index 44272bb..0000000 --- a/temp_backup/Server_redundant/tempdocs/API密钥使用指南.md +++ /dev/null @@ -1,339 +0,0 @@ -# API Key 使用指南 - -## ✅ 已启用 API Key 验证 - -现在所有对 `/api/v1/jsx_demo/calculate` 的请求都需要提供有效的 API Key。 - ---- - -## 🔑 当前可用的 API Keys - -### 1. 测试密钥(开发使用) -``` -API Key: demo_key_123 -名称: 测试密钥 -权限: calculate -限制: 100次/小时 -``` - -### 2. 生产密钥(生产环境) -``` -API Key: prod_key_xyz789abc -名称: 生产密钥 -权限: calculate, admin -限制: 1000次/小时 -``` - ---- - -## 📝 日志示例 - -启用 API Key 后,后端日志会显示: - -``` -============================================================ -📥 收到计算请求 - 时间: 2024-12-16 15:30:45 - 表达式: 87-98 - API Key: demo_key_123 -============================================================ -✅ API Key 验证通过 | 名称: 测试密钥 | 权限: ['calculate'] -🛡️ 安全检查: 验证表达式格式... -✅ 表达式格式验证通过 -🔒 开始执行核心算法... -✅ 计算完成: 87-98 = -11 -============================================================ -``` - -### 如果 API Key 无效: - -``` -============================================================ -📥 收到计算请求 - 时间: 2024-12-16 15:30:45 - 表达式: 87-98 - API Key: invalid_key_xxx -============================================================ -❌ API Key 验证失败: invalid_key_xxx -``` - -**前端会收到:** `403 Forbidden: 无效的 API Key` - ---- - -## 🔧 管理 API Keys - -### 查看所有 Keys - -打开 `Server/app/core/api_keys.py`: - -```python -VALID_KEYS: Dict[str, dict] = { - "demo_key_123": { - "name": "测试密钥", - "created": "2024-12-16", - "permissions": ["calculate"], - "rate_limit": 100 - }, - # ... 更多 keys -} -``` - -### 添加新的 API Key - -**方法 1:直接编辑配置文件** - -在 `api_keys.py` 中添加: - -```python -"your_new_key_456": { - "name": "客户A的密钥", - "created": "2024-12-16", - "permissions": ["calculate"], - "rate_limit": 200 -} -``` - -**方法 2:使用 Python 代码** - -```python -from app.core.api_keys import APIKeyManager - -# 添加新 Key -APIKeyManager.add_key( - api_key="customer_key_789", - name="客户B的密钥", - permissions=["calculate", "export"] -) -``` - -### 删除 API Key - -```python -from app.core.api_keys import APIKeyManager - -# 删除 Key -APIKeyManager.remove_key("old_key_123") -``` - -### 检查权限 - -```python -from app.core.api_keys import APIKeyManager - -# 检查是否有权限 -has_permission = APIKeyManager.check_permission("demo_key_123", "calculate") -``` - ---- - -## 🔒 前端配置 - -### 当前配置(已设置) - -`Designer/src/api/jsxApi/inline/hybrid-demo.ts`: - -```typescript -const response = await fetch(`${config.apiBaseUrl}/jsx_demo/calculate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': 'demo_key_123' // 🔐 使用测试密钥 - }, - body: JSON.stringify({ - expression: layerName - }) -}); -``` - -### 切换到生产密钥 - -修改 API Key: - -```typescript -'X-API-Key': 'prod_key_xyz789abc' // 使用生产密钥 -``` - -### 从配置文件读取(推荐) - -创建 `Designer/src/config/apiKeys.ts`: - -```typescript -export const API_KEYS = { - development: 'demo_key_123', - production: 'prod_key_xyz789abc' -}; - -// 根据环境自动选择 -export const getCurrentApiKey = () => { - return import.meta.env.DEV - ? API_KEYS.development - : API_KEYS.production; -}; -``` - -然后在 `hybrid-demo.ts` 中使用: - -```typescript -import { getCurrentApiKey } from '@/config/apiKeys'; - -const response = await fetch(`${config.apiBaseUrl}/jsx_demo/calculate`, { - headers: { - 'X-API-Key': getCurrentApiKey() // 自动选择正确的 Key - } -}); -``` - ---- - -## 🧪 测试 API Key 验证 - -### 测试 1:使用有效的 Key - -1. 创建图层名称:`87-98` -2. 点击"智能配色" -3. **预期结果:** ✅ 成功计算 - -**后端日志:** -``` -✅ API Key 验证通过 | 名称: 测试密钥 -``` - ---- - -### 测试 2:使用无效的 Key - -临时修改前端,使用错误的 Key: - -```typescript -'X-API-Key': 'wrong_key_xxx' -``` - -**预期结果:** ❌ 403 错误 - -**后端日志:** -``` -❌ API Key 验证失败: wrong_key_xxx -``` - -**前端错误:** -``` -Message.error('无效的 API Key') -``` - ---- - -### 测试 3:不提供 Key - -注释掉 API Key: - -```typescript -// 'X-API-Key': 'demo_key_123' -``` - -**预期结果:** ❌ 403 错误 - -**后端日志:** -``` -❌ API Key 验证失败: None -``` - ---- - -## 🛡️ 安全最佳实践 - -### ✅ 应该做的 - -1. **不同环境使用不同的 Key** - - 开发环境:`demo_key_123` - - 生产环境:`prod_key_xyz789abc` - -2. **定期更换 Key** - ```python - # 每季度更新一次 - "new_key_2024_q1": {...} - ``` - -3. **使用环境变量** - ```python - import os - API_KEY = os.getenv('DESIGNER_API_KEY', 'demo_key_123') - ``` - -4. **记录所有请求** - - 已实现:所有请求都会记录 API Key - -5. **限制调用频率** - - 已配置:每个 Key 都有 rate_limit - -### ❌ 不应该做的 - -1. ❌ 把 Key 硬编码在公开的代码中 -2. ❌ 在 Git 中提交包含生产 Key 的文件 -3. ❌ 多个客户共用同一个 Key -4. ❌ 永远不更换 Key - ---- - -## 🚀 进一步加强 - -### 1. 数据库存储 API Keys - -```python -# models/api_key.py -class APIKey(Base): - __tablename__ = "api_keys" - - key = Column(String, primary_key=True) - name = Column(String) - permissions = Column(JSON) - rate_limit = Column(Integer) - created_at = Column(DateTime) - expires_at = Column(DateTime) - is_active = Column(Boolean, default=True) -``` - -### 2. Key 过期时间 - -```python -"demo_key_123": { - "expires": "2025-12-31", # Key 会过期 -} -``` - -### 3. 使用量统计 - -```python -"demo_key_123": { - "usage_count": 0, - "last_used": None, -} -``` - -### 4. IP 绑定 - -```python -"demo_key_123": { - "allowed_ips": ["192.168.1.100", "127.0.0.1"] -} -``` - ---- - -## 📊 总结 - -| 功能 | 状态 | 说明 | -|------|------|------| -| API Key 验证 | ✅ 已启用 | 所有请求必须提供有效 Key | -| 多 Key 支持 | ✅ 已实现 | 可配置多个不同权限的 Key | -| 权限控制 | ✅ 已实现 | 每个 Key 可配置不同权限 | -| 日志记录 | ✅ 已实现 | 记录所有 Key 使用情况 | -| Key 管理器 | ✅ 已实现 | 提供增删改查 API | -| 限流配置 | 🔧 已配置 | 待实现实际限流逻辑 | -| 数据库存储 | ⚠️ 未实现 | 当前使用配置文件 | -| Key 过期 | ⚠️ 未实现 | 可以扩展 | - ---- - -**当前 API Key 已启用!所有请求都会被验证和记录!** - diff --git a/temp_backup/Server_redundant/tempdocs/AdminTool配置管理开发文档.md b/temp_backup/Server_redundant/tempdocs/AdminTool配置管理开发文档.md deleted file mode 100644 index 3c3df1e..0000000 --- a/temp_backup/Server_redundant/tempdocs/AdminTool配置管理开发文档.md +++ /dev/null @@ -1,397 +0,0 @@ -# AdminTool 系统配置管理开发文档 - -## 📋 开发需求 - -AdminTool需要集成系统配置管理功能,用于可视化管理: -1. 功能配置(积分价格、启用/禁用) -2. VIP配置(价格、配额、倍数) -3. 签到配置(连续天数奖励) -4. 数据统计(今日统计、功能使用排行) - ---- - -## 🎨 技术方案 - -### 方案A:使用 qfluentwidgets(推荐) - -#### 1. 安装依赖 - -```bash -pip install PyQt-Fluent-Widgets -``` - -#### 2. 改造现有代码 - -**主窗口改造** (`admin_gui.py`): -```python -from qfluentwidgets import FluentWindow, FluentIcon, NavigationItemPosition - -class AdminWindow(FluentWindow): # 改为继承 FluentWindow - def __init__(self): - super().__init__() - - # 启用 Mica 效果 - self.setMicaEffectEnabled(True) - - # 添加配置管理页面 - self.config_interface = ConfigInterface(self.api_client, self) - - self.addSubInterface( - self.config_interface, - icon=FluentIcon.SETTING, - text="系统配置", - position=NavigationItemPosition.BOTTOM - ) -``` - -**配置管理界面** (`config_interface.py`,新建): -```python -from PyQt5.QtWidgets import QWidget, QVBoxLayout -from qfluentwidgets import ( - Pivot, PushButton, TableWidget, CardWidget, - MessageBox, InfoBar -) - -class ConfigInterface(QWidget): - """配置管理主界面""" - - def __init__(self, api_client, parent=None): - super().__init__(parent) - self.api_client = api_client - - # 创建Pivot导航 - self.pivot = Pivot(self) - - # 添加子页面 - self.features_tab = FeaturesConfigTab(api_client) - self.vip_tab = VIPConfigTab(api_client) - self.checkin_tab = CheckInConfigTab(api_client) - self.stats_tab = StatsTab(api_client) - - # 添加到Pivot - self.pivot.addItem('features', '功能配置', self.features_tab) - self.pivot.addItem('vip', 'VIP配置', self.vip_tab) - self.pivot.addItem('checkin', '签到配置', self.checkin_tab) - self.pivot.addItem('stats', '数据统计', self.stats_tab) - - -class FeaturesConfigTab(QWidget): - """功能配置标签页""" - - def __init__(self, api_client, parent=None): - super().__init__(parent) - self.api_client = api_client - - # 表格 - self.table = TableWidget(self) - self.table.setColumnCount(6) - self.table.setHorizontalHeaderLabels([ - "功能名称", "普通价格", "VIP价格", "SVIP价格", "状态", "操作" - ]) - - # 按钮 - self.btn_add = PushButton("新增功能", self) - self.btn_refresh = PushButton("刷新", self) - - self.load_data() - - def load_data(self): - """从API加载数据""" - try: - resp = requests.get( - f"{self.api_client.base_url}/admin/config/features", - headers=self.api_client.get_headers() - ) - data = resp.json() - # 填充表格... - InfoBar.success("加载成功", f"已加载 {len(data)} 个功能") - except Exception as e: - MessageBox("错误", f"加载失败: {e}", self).exec() -``` - ---- - -### 方案B:使用现有PyQt5(快速实现) - -如果不想安装新依赖,可以在现有 `admin_gui.py` 基础上: - -#### 1. 在 `setup_` 中添加新标签页 - -```python -def __init__(self): - # ... 现有代码 ... - - # 新增第4个标签页 - self.config_tab = QWidget() - self.setup_config_tab() - self.tabs.addTab(self.config_tab, "系统配置") - -def setup_config_tab(self): - """设置系统配置标签页""" - layout = QVBoxLayout(self.config_tab) - - # 子标签页 - sub_tabs = QTabWidget() - - # 功能配置 - features_widget = QWidget() - self.setup_features_config(features_widget) - sub_tabs.addTab(features_widget, "功能配置") - - # VIP配置 - vip_widget = QWidget() - self.setup_vip_config(vip_widget) - sub_tabs.addTab(vip_widget, "VIP配置") - - # 签到配置 - checkin_widget = QWidget() - self.setup_checkin_config(checkin_widget) - sub_tabs.addTab(checkin_widget, "签到配置") - - # 统计 - stats_widget = QWidget() - self.setup_stats(stats_widget) - sub_tabs.addTab(stats_widget, "数据统计") - - layout.addWidget(sub_tabs) -``` - -#### 2. 实现各个子界面 - -```python -def setup_features_config(self, widget): - """功能配置界面""" - layout = QVBoxLayout(widget) - - # 操作按钮 - btn_layout = QHBoxLayout() - btn_add = QPushButton("新增功能") - btn_add.clicked.connect(self.add_feature_config) - btn_refresh = QPushButton("刷新") - btn_refresh.clicked.connect(self.refresh_features_config) - btn_layout.addWidget(btn_add) - btn_layout.addWidget(btn_refresh) - btn_layout.addStretch() - layout.addLayout(btn_layout) - - # 表格 - self.features_table = QTableWidget() - self.features_table.setColumnCount(7) - self.features_table.setHorizontalHeaderLabels([ - "功能名称", "分类", "普通价格", "VIP价格", "SVIP价格", "状态", "操作" - ]) - self.features_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - layout.addWidget(self.features_table) - - # 加载数据 - self.refresh_features_config() - -def refresh_features_config(self): - """刷新功能配置""" - try: - resp = requests.get( - f"{self.api_client.base_url}/admin/config/features", - headers=self.api_client.get_headers() - ) - resp.raise_for_status() - data = resp.json() - - self.features_table.setRowCount(len(data)) - for i, feature in enumerate(data): - self.features_table.setItem(i, 0, QTableWidgetItem(feature['feature_name'])) - self.features_table.setItem(i, 1, QTableWidgetItem(feature['category'])) - self.features_table.setItem(i, 2, QTableWidgetItem(str(feature['points_cost']))) - self.features_table.setItem(i, 3, QTableWidgetItem(str(feature['vip_points_cost']))) - self.features_table.setItem(i, 4, QTableWidgetItem(str(feature['svip_points_cost']))) - self.features_table.setItem(i, 5, QTableWidgetItem("✓" if feature['enabled'] else "✗")) - - # 操作按钮 - btn_edit = QPushButton("编辑") - btn_edit.clicked.connect(lambda checked, f=feature: self.edit_feature_config(f)) - self.features_table.setCellWidget(i, 6, btn_edit) - - QMessageBox.information(self, "成功", f"已加载 {len(data)} 个功能配置") - except Exception as e: - QMessageBox.critical(self, "错误", f"加载失败: {e}") - -def edit_feature_config(self, feature): - """编辑功能配置""" - dialog = QDialog(self) - dialog.setWindowTitle(f"编辑功能: {feature['feature_name']}") - layout = QFormLayout(dialog) - - # 输入框 - points_input = QSpinBox() - points_input.setRange(0, 9999) - points_input.setValue(feature['points_cost']) - layout.addRow("普通用户积分:", points_input) - - vip_points_input = QSpinBox() - vip_points_input.setRange(0, 9999) - vip_points_input.setValue(feature['vip_points_cost']) - layout.addRow("VIP积分:", vip_points_input) - - svip_points_input = QSpinBox() - svip_points_input.setRange(0, 9999) - svip_points_input.setValue(feature['svip_points_cost']) - layout.addRow("SVIP积分:", svip_points_input) - - enabled_check = QCheckBox() - enabled_check.setChecked(feature['enabled']) - layout.addRow("启用:", enabled_check) - - # 按钮 - buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - buttons.accepted.connect(dialog.accept) - buttons.rejected.connect(dialog.reject) - layout.addRow(buttons) - - if dialog.exec() == QDialog.Accepted: - # 提交更新 - try: - resp = requests.put( - f"{self.api_client.base_url}/admin/config/features/{feature['feature_key']}", - json={ - "points_cost": points_input.value(), - "vip_points_cost": vip_points_input.value(), - "svip_points_cost": svip_points_input.value(), - "enabled": enabled_check.isChecked() - }, - headers=self.api_client.get_headers() - ) - resp.raise_for_status() - QMessageBox.information(self, "成功", "更新成功") - self.refresh_features_config() - except Exception as e: - QMessageBox.critical(self, "错误", f"更新失败: {e}") -``` - ---- - -## 📊 API接口参考 - -### 功能配置API - -```python -# 获取所有功能 -GET /api/v1/admin/config/features -Headers: x-admin-token: admin-secret-token - -# 新增功能 -POST /api/v1/admin/config/features -Body: { - "feature_key": "new_feature", - "feature_name": "新功能", - "category": "ai", - "points_cost": 60, - "vip_points_cost": 0, - "svip_points_cost": 0 -} - -# 更新功能 -PUT /api/v1/admin/config/features/{feature_key} -Body: { - "points_cost": 80, - "enabled": true -} -``` - -### VIP配置API - -```python -# 获取VIP配置 -GET /api/v1/admin/config/vip - -# 更新VIP配置 -PUT /api/v1/admin/config/vip/vip -Body: { - "price": 35.00, - "daily_quota": 25, - "points_multiplier": 1.60 -} -``` - -### 签到配置API - -```python -# 获取签到配置 -GET /api/v1/admin/config/checkin - -# 新增档位 -POST /api/v1/admin/config/checkin -Body: { - "consecutive_days": 60, - "base_points": 10, - "bonus_points": 150, - "total_points": 160 -} - -# 更新档位 -PUT /api/v1/admin/config/checkin/7 -Body: { - "bonus_points": 25, - "total_points": 35 -} -``` - -### 统计API - -```python -# 今日统计 -GET /api/v1/admin/stats/today - -# 功能使用排行 -GET /api/v1/admin/stats/feature-usage?days=7 - -# 积分趋势 -GET /api/v1/admin/stats/points-trend?days=7 -``` - ---- - -## ✅ 开发检查清单 - -- [ ] 安装依赖(如使用方案A) -- [ ] 改造主窗口类 -- [ ] 创建配置管理界面 -- [ ] 实现功能配置CRUD -- [ ] 实现VIP配置编辑 -- [ ] 实现签到配置编辑 -- [ ] 实现数据统计展示 -- [ ] 连接后端API -- [ ] 错误处理和提示 -- [ ] 测试所有功能 - ---- - -## 📝 注意事项 - -1. **权限验证**: 所有管理接口都需要 `x-admin-token: admin-secret-token` -2. **错误处理**: 使用 try-except 捕获网络异常 -3. **用户友好**: 操作前确认,操作后提示 -4. **数据刷新**: 修改后自动刷新列表 -5. **布局美观**: 合理使用Grid/Box布局 - ---- - -## 🎯 优先级 - -### P0(必须) -- 功能配置查看和编辑 -- VIP配置编辑 -- 签到配置编辑 - -### P1(重要) -- 功能配置新增/删除 -- 签到配置新增/删除 -- 数据统计展示 - -### P2(可选) -- Fluent Design 风格改造 -- 图表可视化 -- 高级筛选和搜索 - ---- - -**开发愉快!如有问题请参考主文档或API文档。** - diff --git a/temp_backup/Server_redundant/tempdocs/Caddy部署指南.md b/temp_backup/Server_redundant/tempdocs/Caddy部署指南.md deleted file mode 100644 index d89a7fb..0000000 --- a/temp_backup/Server_redundant/tempdocs/Caddy部署指南.md +++ /dev/null @@ -1,820 +0,0 @@ -# 🚀 DesignerCEP Caddy 部署指南 - -## 为什么选择 Caddy? - -✅ **自动 HTTPS**:无需手动申请证书,自动从 Let's Encrypt 获取并续期 -✅ **配置简单**:比 Nginx 简单 10 倍,一看就懂 -✅ **开箱即用**:自动处理 HTTP/2, GZIP 压缩 -✅ **完美支持 Cloudflare**:自动识别并配置 - ---- - -## 📦 1. 安装 Caddy - -### Ubuntu/Debian - -```bash -# 安装依赖 -sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https - -# 添加 Caddy 官方仓库 -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list - -# 更新并安装 -sudo apt update -sudo apt install caddy - -# 验证安装 -caddy version -``` - -### CentOS/RHEL - -```bash -# 添加 Caddy 官方仓库 -dnf install 'dnf-command(copr)' -dnf copr enable @caddy/caddy -dnf install caddy - -# 启动服务 -sudo systemctl enable caddy -sudo systemctl start caddy -``` - ---- - -## 📁 2. 准备项目目录 - -```bash -# 创建项目目录 -sudo mkdir -p /var/www/DesignerCEP/Server/static/{shell,core,downloads} - -# 设置权限 -sudo chown -R $USER:$USER /var/www/DesignerCEP -chmod -R 755 /var/www/DesignerCEP -``` - ---- - -## ⚙️ 3. 配置 Caddy - -### 方案 A: 标准部署(Let's Encrypt 自动证书) - -**适用于**:独立域名,不使用 Cloudflare 代理 - -```bash -# 创建 Caddyfile -sudo nano /etc/caddy/Caddyfile -``` - -```caddy -# /etc/caddy/Caddyfile - -# ========== 主站配置 ========== -your-domain.com, www.your-domain.com { - # ✅ Caddy 会自动处理 HTTPS 证书 - - # ========== API 请求 → FastAPI ========== - handle /api/* { - reverse_proxy localhost:8000 { - # 传递真实 IP - header_up X-Real-IP {remote_host} - header_up X-Forwarded-For {remote_host} - header_up X-Forwarded-Proto {scheme} - } - } - - # ========== Shell 在线登录页 ========== - handle /shell/* { - root * /var/www/DesignerCEP/Server/static/shell - try_files {path} {path}/ /shell/index.html - file_server - - # HTML 不缓存 - @html { - path *.html - } - header @html Cache-Control "no-cache, no-store, must-revalidate" - - # JS/CSS 长期缓存 - @assets { - path *.js *.css - } - header @assets Cache-Control "public, max-age=31536000, immutable" - } - - # ========== Core 核心应用 ========== - handle /core/* { - root * /var/www/DesignerCEP/Server/static/core - file_server - - # HTML 不缓存 - @html { - path *.html - } - header @html Cache-Control "no-cache, no-store, must-revalidate" - - # JS/CSS 长期缓存 - @assets { - path *.js *.css - } - header @assets Cache-Control "public, max-age=31536000, immutable" - } - - # ========== 下载文件 ========== - handle /downloads/* { - root * /var/www/DesignerCEP/Server/static/downloads - file_server - - # 启用断点续传 - header Accept-Ranges bytes - - # 缓存 1 天 - header Cache-Control "public, max-age=86400" - } - - # ========== 根路径重定向 ========== - handle / { - redir /shell/ permanent - } - - # ========== 通用配置 ========== - # 自动 GZIP 压缩 - encode gzip zstd - - # 安全头 - header { - X-Frame-Options "SAMEORIGIN" - X-Content-Type-Options "nosniff" - X-XSS-Protection "1; mode=block" - -Server # 隐藏服务器信息 - } - - # 日志 - log { - output file /var/log/caddy/designer-cep.log { - roll_size 100mb - roll_keep 10 - } - } -} -``` - -### 方案 B: Cloudflare 代理部署(推荐) - -**适用于**:域名使用 Cloudflare 橙云代理 - -```bash -sudo nano /etc/caddy/Caddyfile -``` - -```caddy -# /etc/caddy/Caddyfile (Cloudflare 版本) - -{ - # ✅ 关闭自动 HTTPS(Cloudflare 已经提供) - auto_https off - - # 或者使用内部证书 - # auto_https disable_redirects -} - -# ========== HTTP 配置(Cloudflare 会加 HTTPS)========== -http://your-domain.com, http://www.your-domain.com { - - # ========== API 请求 → FastAPI ========== - handle /api/* { - reverse_proxy localhost:8000 { - # ✅ 从 Cloudflare 获取真实 IP - header_up X-Real-IP {header.CF-Connecting-IP} - header_up X-Forwarded-For {header.CF-Connecting-IP} - header_up X-Forwarded-Proto https - } - } - - # ========== Shell 在线登录页 ========== - handle /shell/* { - root * /var/www/DesignerCEP/Server/static/shell - try_files {path} {path}/ /shell/index.html - file_server - - @html path *.html - header @html Cache-Control "no-cache, no-store, must-revalidate" - - @assets path *.js *.css - header @assets Cache-Control "public, max-age=31536000, immutable" - } - - # ========== Core 核心应用 ========== - handle /core/* { - root * /var/www/DesignerCEP/Server/static/core - file_server - - @html path *.html - header @html Cache-Control "no-cache, no-store, must-revalidate" - - @assets path *.js *.css - header @assets Cache-Control "public, max-age=31536000, immutable" - } - - # ========== 下载文件 ========== - handle /downloads/* { - root * /var/www/DesignerCEP/Server/static/downloads - file_server - header Accept-Ranges bytes - header Cache-Control "public, max-age=86400" - } - - # ========== 根路径重定向 ========== - handle / { - redir /shell/ permanent - } - - # ========== 通用配置 ========== - encode gzip zstd - - header { - X-Frame-Options "SAMEORIGIN" - X-Content-Type-Options "nosniff" - X-XSS-Protection "1; mode=block" - -Server - } - - log { - output file /var/log/caddy/designer-cep.log { - roll_size 100mb - roll_keep 10 - } - } -} -``` - ---- - -## 🔧 4. 修改后端代码(支持 CEP 环境) - -### 4.1 修改 FastAPI 的 CORS 配置 - -```python -# Server/app/main.py -from fastapi import FastAPI, Request -from fastapi.middleware.cors import CORSMiddleware -import os - -app = FastAPI(title=settings.PROJECT_NAME) - -# 环境判断 -IS_DEV = os.getenv("ENV", "development") == "development" - -# ========== CORS 配置 ========== -if IS_DEV: - # 开发环境:宽松配置 - app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) -else: - # 生产环境:严格配置 - allowed_origins = os.getenv("ALLOWED_ORIGINS", "").split(",") - - app.add_middleware( - CORSMiddleware, - allow_origins=allowed_origins, - allow_credentials=True, - allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allow_headers=["*"], - ) - - # ✅ 特殊处理 CEP 环境(Origin: null) - @app.middleware("http") - async def cep_cors_middleware(request: Request, call_next): - origin = request.headers.get("origin") - - # CEP 环境的 Origin 是 null 或 cep:// - if origin in ["null", None] or (origin and origin.startswith("cep://")): - response = await call_next(request) - response.headers["Access-Control-Allow-Origin"] = "*" - response.headers["Access-Control-Allow-Credentials"] = "true" - response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" - response.headers["Access-Control-Allow-Headers"] = "*" - return response - - return await call_next(request) - -# ========== API 路由(保持不变)========== -app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth", tags=["authentication"]) -app.include_router(client.router, prefix=f"{settings.API_V1_STR}/client", tags=["client"]) -app.include_router(admin.router, prefix=f"{settings.API_V1_STR}/admin", tags=["admin"]) -app.include_router(analytics.router, prefix=f"{settings.API_V1_STR}/analytics", tags=["analytics"]) -app.include_router(jsx_demo.router, prefix=f"{settings.API_V1_STR}/jsx_demo", tags=["jsx_demo"]) - -# ❌ 删除静态文件挂载(交给 Caddy 处理) -# app.mount("/download", ...) # 删除 -# app.mount("/shell", ...) # 删除 -# app.mount("/core", ...) # 删除 - -@app.get("/") -def read_root(): - return {"message": "DesignerCEP API Server", "version": "1.0.0"} - -@app.get("/health") -def health_check(): - return {"status": "healthy"} - -@app.on_event("startup") -def on_startup(): - init_db() -``` - -### 4.2 配置环境变量 - -```bash -# Server/.env -ENV=production -PROJECT_NAME=DesignerCEP -API_V1_STR=/api/v1 -SECRET_KEY=your-secret-key-here -DATABASE_URL=mysql://user:password@localhost:3306/designer_cep - -# 生产环境允许的来源 -ALLOWED_ORIGINS=https://your-domain.com,https://www.your-domain.com - -# 是否由 FastAPI 提供静态文件(生产环境设为 false) -SERVE_STATIC=false -``` - ---- - -## 🚀 5. 部署 FastAPI 服务 - -### 5.1 使用 Systemd 管理服务 - -```bash -# 创建服务文件 -sudo nano /etc/systemd/system/designer-cep.service -``` - -```ini -[Unit] -Description=DesignerCEP FastAPI Application -After=network.target - -[Service] -Type=simple -User=www-data -Group=www-data -WorkingDirectory=/var/www/DesignerCEP/Server -Environment="PATH=/var/www/DesignerCEP/Server/venv/bin" -ExecStart=/var/www/DesignerCEP/Server/venv/bin/gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 - -Restart=always -RestartSec=10 - -[Install] -WantedBy=multi-user.target -``` - -### 5.2 安装依赖并启动 - -```bash -# 1. 创建虚拟环境 -cd /var/www/DesignerCEP/Server -python3 -m venv venv -source venv/bin/activate - -# 2. 安装依赖 -pip install -r requirements.txt -pip install gunicorn uvicorn[standard] - -# 3. 测试运行 -uvicorn app.main:app --host 127.0.0.1 --port 8000 - -# 4. 启动服务 -sudo systemctl daemon-reload -sudo systemctl enable designer-cep -sudo systemctl start designer-cep - -# 5. 检查状态 -sudo systemctl status designer-cep -``` - ---- - -## 📤 6. 部署前端文件 - -### 6.1 配置前端环境 - -```bash -# Designer/.env.production -VITE_API_SERVER=https://your-domain.com -``` - -### 6.2 构建前端 - -```bash -cd Designer -npm install -npm run build -``` - -### 6.3 上传到服务器 - -#### 方法 A: 手动上传 - -```bash -# 在本地执行 -cd Designer/dist - -# 上传 Shell -scp -r Shell/* user@your-server:/var/www/DesignerCEP/Server/static/shell/ - -# 上传 Core -scp -r Designer/* user@your-server:/var/www/DesignerCEP/Server/static/core/1.0.6/ - -# 打包并上传 Shell.zip -zip -r shell-1.0.6.zip Shell/ -scp shell-1.0.6.zip user@your-server:/var/www/DesignerCEP/Server/static/downloads/ -``` - -#### 方法 B: 使用自动化脚本 - -```bash -# 在项目根目录执行 -cd AdminTool - -# 首次配置 -python auto_deploy_core.py --version 1.0.6 --setup - -# 输入配置信息: -# - 服务器地址: your-domain.com -# - SSH 端口: 22 -# - 用户名: root -# - 密码: ****** -# - 远程路径: /var/www/DesignerCEP/Server/static - -# 部署 -python auto_deploy_core.py --version 1.0.6 --deploy --update-db -``` - ---- - -## ✅ 7. 启动 Caddy - -```bash -# 检查配置语法 -sudo caddy validate --config /etc/caddy/Caddyfile - -# 重启 Caddy -sudo systemctl restart caddy - -# 查看状态 -sudo systemctl status caddy - -# 查看日志 -sudo journalctl -u caddy -f -``` - ---- - -## 🧪 8. 测试部署 - -### 8.1 测试静态文件 - -```bash -# 测试 Shell -curl -I https://your-domain.com/shell/ - -# 期望输出: -# HTTP/2 200 -# content-type: text/html - -# 测试 Core -curl -I https://your-domain.com/core/1.0.6/ - -# 测试下载 -curl -I https://your-domain.com/downloads/shell-1.0.6.zip -``` - -### 8.2 测试 API - -```bash -# 测试健康检查 -curl https://your-domain.com/api/v1/health - -# 期望输出: -# {"status":"healthy"} - -# 测试登录接口 -curl -X POST https://your-domain.com/api/v1/client/login \ - -H "Content-Type: application/json" \ - -d '{"username":"test","password":"test","device_id":"test-device"}' -``` - -### 8.3 测试 CEP CORS - -```bash -# 模拟 CEP 环境的预检请求 -curl -X OPTIONS https://your-domain.com/api/v1/client/login \ - -H "Origin: null" \ - -H "Access-Control-Request-Method: POST" \ - -v - -# 期望输出: -# Access-Control-Allow-Origin: * -# Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS -``` - -### 8.4 浏览器测试 - -1. 打开 `https://your-domain.com/shell/` -2. 输入用户名密码登录 -3. 按 F12 打开开发者工具 -4. 查看 Network 标签: - - ✅ 所有请求都是 HTTPS - - ✅ API 请求有 `Authorization: Bearer xxx` - - ✅ 没有 CORS 错误 - ---- - -## 🔍 9. 常见问题 - -### Q1: Caddy 自动证书失败 - -**原因**:域名 DNS 没有解析到服务器 - -**解决**: -```bash -# 检查 DNS 解析 -nslookup your-domain.com - -# 确保 A 记录指向服务器 IP -dig your-domain.com -``` - -### Q2: API 请求 502 Bad Gateway - -**原因**:FastAPI 服务没有启动 - -**解决**: -```bash -# 检查 FastAPI 状态 -sudo systemctl status designer-cep - -# 查看日志 -sudo journalctl -u designer-cep -f - -# 重启服务 -sudo systemctl restart designer-cep -``` - -### Q3: 静态文件 404 - -**原因**:文件路径不对 - -**解决**: -```bash -# 检查文件是否存在 -ls -la /var/www/DesignerCEP/Server/static/shell/ -ls -la /var/www/DesignerCEP/Server/static/core/1.0.6/ - -# 检查权限 -sudo chown -R www-data:www-data /var/www/DesignerCEP -sudo chmod -R 755 /var/www/DesignerCEP -``` - -### Q4: Cloudflare 无限重定向 - -**原因**:Cloudflare SSL 模式设置错误 - -**解决**: -1. 进入 Cloudflare 控制台 -2. SSL/TLS → Overview -3. 选择 **"Flexible"** 模式(因为 Caddy 配置的是 HTTP) - -或者修改 Caddyfile 使用 HTTPS: - -```caddy -# 方法 1: 自签名证书 -your-domain.com { - tls internal - # ... 其他配置 -} - -# 方法 2: Cloudflare Origin Certificate -your-domain.com { - tls /etc/caddy/certs/cloudflare-origin.pem /etc/caddy/certs/cloudflare-origin.key - # ... 其他配置 -} -``` - ---- - -## 🎯 10. Cloudflare 最佳实践 - -### 10.1 SSL/TLS 配置 - -``` -Cloudflare 控制台 → SSL/TLS → Overview - -选择模式: -- ❌ Off - 不使用 HTTPS -- ✅ Flexible - Cloudflare ←HTTPS→ 用户,Cloudflare ←HTTP→ 源站(推荐简单部署) -- ⚠️ Full - 双向 HTTPS,但不验证源站证书 -- ✅ Full (Strict) - 双向 HTTPS,验证证书(推荐生产环境) -``` - -**推荐方案**: - -#### Flexible 模式(最简单) - -```caddy -# Caddyfile -{ - auto_https off -} - -http://your-domain.com { - # ... 配置 -} -``` - -Cloudflare 设置:`Flexible` - -#### Full (Strict) 模式(最安全) - -1. 生成 Cloudflare Origin Certificate: -``` -Cloudflare 控制台 → SSL/TLS → Origin Server → Create Certificate -``` - -2. 下载证书并上传到服务器: -```bash -sudo mkdir -p /etc/caddy/certs -sudo nano /etc/caddy/certs/cloudflare-origin.pem # 粘贴证书 -sudo nano /etc/caddy/certs/cloudflare-origin.key # 粘贴私钥 -sudo chmod 600 /etc/caddy/certs/* -``` - -3. 修改 Caddyfile: -```caddy -your-domain.com { - tls /etc/caddy/certs/cloudflare-origin.pem /etc/caddy/certs/cloudflare-origin.key - - # ... 其他配置 -} -``` - -4. Cloudflare 设置:`Full (Strict)` - -### 10.2 性能优化 - -``` -Cloudflare 控制台设置: - -1. Speed → Optimization - - ✅ Auto Minify: HTML, CSS, JS - - ✅ Brotli 压缩 - -2. Caching → Configuration - - ✅ Caching Level: Standard - - ✅ Browser Cache TTL: Respect Existing Headers - -3. Network - - ✅ HTTP/2 - - ✅ HTTP/3 (QUIC) -``` - ---- - -## 📊 11. 监控和日志 - -### 查看 Caddy 日志 - -```bash -# 实时日志 -sudo journalctl -u caddy -f - -# 访问日志 -sudo tail -f /var/log/caddy/designer-cep.log - -# 错误日志 -sudo journalctl -u caddy --since "1 hour ago" | grep -i error -``` - -### 查看 FastAPI 日志 - -```bash -# 实时日志 -sudo journalctl -u designer-cep -f - -# 最近的错误 -sudo journalctl -u designer-cep --since "1 hour ago" | grep -i error -``` - -### 性能监控 - -```bash -# 检查服务器资源 -htop - -# 检查端口监听 -sudo netstat -tlnp | grep -E '(8000|80|443)' - -# 检查 Caddy 进程 -ps aux | grep caddy -``` - ---- - -## 🔄 12. 更新部署 - -### 更新前端 - -```bash -# 方法 A: 手动 -cd Designer -npm run build -scp -r dist/Shell/* user@server:/var/www/DesignerCEP/Server/static/shell/ -scp -r dist/Designer/* user@server:/var/www/DesignerCEP/Server/static/core/1.0.7/ - -# 方法 B: 自动化 -cd AdminTool -python auto_deploy_core.py --version 1.0.7 --deploy --update-db -``` - -### 更新后端 - -```bash -# 1. SSH 到服务器 -ssh user@your-server - -# 2. 拉取最新代码 -cd /var/www/DesignerCEP/Server -git pull - -# 3. 更新依赖 -source venv/bin/activate -pip install -r requirements.txt - -# 4. 重启服务 -sudo systemctl restart designer-cep - -# 5. 检查状态 -sudo systemctl status designer-cep -``` - -### 更新 Caddy 配置 - -```bash -# 1. 修改配置 -sudo nano /etc/caddy/Caddyfile - -# 2. 验证配置 -sudo caddy validate --config /etc/caddy/Caddyfile - -# 3. 重新加载(不中断服务) -sudo systemctl reload caddy -``` - ---- - -## 🎉 完成! - -访问地址: -- **Shell 登录页**:`https://your-domain.com/shell/` -- **Core 应用**:`https://your-domain.com/core/1.0.6/` -- **API 文档**:`https://your-domain.com/api/v1/docs` - ---- - -## 📋 部署检查清单 - -- [ ] Caddy 已安装并启动 -- [ ] Caddyfile 配置正确 -- [ ] FastAPI 服务运行正常 -- [ ] 前端文件已上传 -- [ ] 环境变量配置正确 -- [ ] CORS 支持 CEP 环境 -- [ ] MySQL 数据库已更新 -- [ ] HTTPS 证书正常 -- [ ] 静态文件缓存正确 -- [ ] API 请求正常 -- [ ] CEP 扩展测试通过 -- [ ] 浏览器访问正常 - ---- - -**Caddy 的优势总结**: -- ✅ 配置只有 Nginx 的 1/3 长度 -- ✅ 自动 HTTPS,无需 Certbot -- ✅ 自动续期证书 -- ✅ 内置 GZIP/Brotli 压缩 -- ✅ 配置更直观易懂 -- ✅ 错误提示更友好 - -**下一步**:运行 `python auto_deploy_core.py --version 1.0.6 --deploy --update-db` 一键部署! - diff --git a/temp_backup/Server_redundant/tempdocs/JSX加载失败问题分析与解决方案.md b/temp_backup/Server_redundant/tempdocs/JSX加载失败问题分析与解决方案.md deleted file mode 100644 index 96b2087..0000000 --- a/temp_backup/Server_redundant/tempdocs/JSX加载失败问题分析与解决方案.md +++ /dev/null @@ -1,193 +0,0 @@ -# JSX 加载失败问题分析与解决方案 - -## 📋 问题描述 - -在 Shell + Core 架构分离后,Core 应用中的 JSX 脚本无法正常运行,报错: - -``` -Error: EvalScript error. -``` - -尽管 JSX 文件路径找到了(`C:/Users/35780/AppData/Roaming/DesignerCache/v1.0.5/jsx/index.js`),但 `evalScript` 执行失败。 - -## 🔍 根本原因 - -### 问题1:JSX 构建格式错误 - -**位置**:`Designer/plugins/buildJsx/index.ts` 第 118 行 - -```typescript -await bundle.write({ - file: output, - format: 'cjs' // ❌ 问题所在! -}); -``` - -**影响**:生成的 JSX 文件使用了 **CommonJS 格式**,包含: - -```javascript -Object.defineProperty(exports, "__esModule", { value: true }); -var index_1 = require("./function/index"); // ❌ ExtendScript 不支持 require() -var ActionManager = require("./utils/ActionManager"); -``` - -### 问题2:ExtendScript 环境限制 - -**ExtendScript (Adobe JSX 引擎) 不支持:** -- ❌ CommonJS 的 `require()` 和 `exports` -- ❌ ES6 的 `import/export` -- ❌ `'use strict'` 严格模式 - -**ExtendScript 只支持:** -- ✅ 全局函数 -- ✅ 立即执行函数表达式 (IIFE) -- ✅ ES3/ES5 语法 - -## ✅ 解决方案 - -### 方案 1:修改构建配置(长期方案) - -修改 `Designer/plugins/buildJsx/index.ts`: - -```typescript -await bundle.write({ - file: output, - format: 'iife', // ✅ 改为 IIFE 格式 - name: 'JSXBundle', - strict: false // ✅ 禁用严格模式 -}); -``` - -**同时修改 TypeScript 配置**: - -```typescript -typescript({ - compilerOptions: { - target: 'es5', - strict: false, - moduleResolution: 'node', - esModuleInterop: true, - skipLibCheck: true, - // ... - }, - tsconfig: false, -}), -``` - -### 方案 2:临时修复(已应用) - -**已完成的操作:** - -1. ✅ 创建了简化版本的 JSX 文件 (`index_fixed.js`) -2. ✅ 移除了所有 CommonJS 语法 -3. ✅ 将依赖项(Logger, ActionManager)内联到单文件中 -4. ✅ 备份原文件为 `index.js.backup` -5. ✅ 替换为修复后的版本 - -**文件位置**: -- 修复后:`Designer/dist_core/jsx/index.js` -- 备份:`Designer/dist_core/jsx/index.js.backup` - -## 🧪 测试步骤 - -### 1. 清除客户端缓存 - -```powershell -Remove-Item -Recurse -Force "$env:APPDATA\DesignerCache" -ErrorAction SilentlyContinue -``` - -### 2. 重启插件 - -在 Photoshop 中: -1. 关闭当前的 DesignerCEP 插件 -2. 重新打开插件 -3. 登录账号 - -### 3. 检查控制台 - -打开浏览器开发者工具(F12),查看: - -**预期成功日志:** -``` -[__LDX] Detected Core version v1.0.5 -[__LDX] Success: C:/Users/35780/AppData/Roaming/DesignerCache/v1.0.5/jsx/index.js -宿主APP名称:Adobe Photoshop 2024 -``` - -**如果仍然失败,查看:** -- 是否有 `EvalScript error` -- ExtendScript 控制台的详细错误信息 - -### 4. 测试功能 - -在插件主界面点击"测试 JSX 调用"按钮,验证: -- ✅ `getAppName()` 返回 "Adobe Photoshop" -- ✅ `createLayer()` 可以创建新图层 -- ✅ `testMergeLayers()` 可以合并图层 - -## 📝 后续工作 - -### 短期(紧急) -- [ ] 测试修复后的 JSX 是否正常工作 -- [ ] 如果测试通过,将修复后的文件上传到服务器 - -### 中期(优化) -- [ ] 修复构建流程,确保未来构建自动生成正确格式 -- [ ] 解决 `g_logger` 和 `ActionManager` 的依赖打包问题 -- [ ] 更新 `deploy_core.py` 脚本,包含 JSX 构建步骤 - -### 长期(架构改进) -- [ ] 评估是否需要保留完整的 Logger 和 ActionManager -- [ ] 考虑使用 Rollup 的 `inlineDynamicImports` 选项 -- [ ] 编写自动化测试验证 JSX 在 ExtendScript 环境中的兼容性 - -## 🔗 相关文件 - -| 文件路径 | 说明 | -|:---------|:-----| -| `Designer/plugins/buildJsx/index.ts` | JSX 构建配置(已修改format为iife) | -| `Designer/dist_core/jsx/index.js` | 修复后的 JSX 文件 | -| `Designer/dist_core/jsx/index.js.backup` | 原始的 CommonJS 格式备份 | -| `Designer/build_jsx_simple.mjs` | 简化的构建脚本(待完善) | - -## 💡 技术要点 - -### ExtendScript 兼容性清单 - -```javascript -✅ 允许: -- var, function, 普通对象 -- IIFE: (function(){ ... })(); -- 全局赋值: $.global.xxx = function(){} -- ES5 方法: Array.forEach, Object.keys - -❌ 禁止: -- 'use strict' -- require() / exports / module.exports -- import / export -- const / let (部分版本不支持) -- Promise / async/await (需 polyfill) -- 箭头函数 (部分版本) -``` - -### Rollup 输出格式对比 - -| 格式 | ExtendScript | 说明 | -|:-----|:------------|:-----| -| `cjs` | ❌ | CommonJS,使用 require/exports | -| `esm` | ❌ | ES Module,使用 import/export | -| `iife` | ✅ | 立即执行函数,所有代码在一个作用域 | -| `umd` | ⚠️ | 通用模块,体积较大但兼容性好 | - -## 📞 联系与支持 - -如果测试中遇到问题,请提供: -1. 浏览器控制台的完整错误日志 -2. ExtendScript Toolkit 的错误信息(如果有) -3. Photoshop 版本和操作系统信息 - ---- - -**报告生成时间**:2025-12-16 -**问题状态**:✅ 已修复(待测试验证) - diff --git a/temp_backup/Server_redundant/tempdocs/JSX方法测试指南.md b/temp_backup/Server_redundant/tempdocs/JSX方法测试指南.md deleted file mode 100644 index 2db6de8..0000000 --- a/temp_backup/Server_redundant/tempdocs/JSX方法测试指南.md +++ /dev/null @@ -1,128 +0,0 @@ -# JSX 方法测试指南 - -## 🎯 目标 - -测试 5 种不同的 JSX 实现方法,找出在 ExtendScript 环境中能正常运行的方式。 - -## 📋 测试方法列表 - -| 方法 | 实现方式 | 特点 | -|:-----|:---------|:-----| -| **方法1** | DOM API | 最简单,直接使用 PS 的 DOM 对象 | -| **方法2** | ActionManager | 使用 ActionDescriptor,更底层 | -| **方法3** | Object Helper | 使用对象字面量封装 | -| **方法4** | ES3 Class | 使用原型链的类实现 | -| **方法5** | PSApi Style | 模仿完整的 PSApi 结构 | - -## 🧪 快速测试步骤 - -### 1. 替换 JSX 文件 - -```powershell -# 方式A:直接复制到缓存(推荐) -Copy-Item Designer\test_jsx_methods.js "$env:APPDATA\DesignerCache\v1.0.7\jsx\index.js" -Force - -# 方式B:或者重新打包上传 -# (如果方式A不行,说明缓存路径不对) -``` - -### 2. 在浏览器控制台测试 - -打开 Photoshop 插件,按 F12 打开控制台,逐个测试: - -```javascript -// 测试方法1(DOM API) -cep.evalScript("createLayerMethod1('测试图层1')").then(r => console.log('方法1:', r)) - -// 测试方法2(ActionManager) -cep.evalScript("createLayerMethod2('测试图层2')").then(r => console.log('方法2:', r)) - -// 测试方法3(Object Helper) -cep.evalScript("createLayerMethod3('测试图层3')").then(r => console.log('方法3:', r)) - -// 测试方法4(ES3 Class) -cep.evalScript("createLayerMethod4('测试图层4')").then(r => console.log('方法4:', r)) - -// 测试方法5(PSApi Style) -cep.evalScript("createLayerMethod5('测试图层5')").then(r => console.log('方法5:', r)) - -// 测试获取图层数量 -cep.evalScript("getLayerCount()").then(r => console.log('图层数量:', r)) -``` - -### 3. 观察结果 - -**成功的结果示例:** -```json -{ - "success": true, - "method": "DOM API", - "layerName": "测试图层1" -} -``` - -**失败的结果示例:** -```json -{ - "error": "..." -} -``` - -## 📊 预期哪个会成功? - -根据 ExtendScript 的特性,**最可能成功的是**: - -1. ✅ **方法1(DOM API)** - 最简单直接 -2. ✅ **方法3(Object Helper)** - 使用对象字面量 -3. ⚠️ **方法2(ActionManager)** - 可能因为 API 调用问题失败 -4. ⚠️ **方法4(ES3 Class)** - 依赖原型链 -5. ⚠️ **方法5(PSApi Style)** - 最复杂,可能有嵌套问题 - -## 🔧 如果都失败了 - -如果所有方法都失败,可能的原因: - -1. **JSX 文件没有被加载** - - 检查控制台是否有 `Test JSX Methods Loaded` 日志 - -2. **路径不对** - - 检查 `[__LDX]` 日志显示的路径 - - 手动找到该路径,确认文件内容 - -3. **ExtendScript 语法错误** - - 在 ExtendScript Toolkit 中打开文件检查 - -## 💡 成功后的下一步 - -找到能工作的方法后: - -1. 📝 **记录成功的方法**(如"方法1成功") -2. 🔄 **使用该方法重写所有 JSX 函数** -3. 📦 **重新构建和打包 Core** -4. 🚀 **发布到服务器** - -## 🎨 添加前端测试按钮(可选) - -在 `Home.vue` 中添加测试按钮: - -```vue -测试方法1 -测试方法2 -测试方法3 -测试方法4 -测试方法5 -``` - -```typescript -const testMethod1 = async () => { - const res = await jsxApi.evalScript("createLayerMethod1('测试1')"); - console.log('方法1结果:', res); - Message.info(res); -}; -// ... 类似地添加其他方法 -``` - ---- - -**现在开始测试吧!** 告诉我哪个方法能成功 🎯 - diff --git a/temp_backup/Server_redundant/tempdocs/PSApi功能测试指南.md b/temp_backup/Server_redundant/tempdocs/PSApi功能测试指南.md deleted file mode 100644 index 12cf05c..0000000 --- a/temp_backup/Server_redundant/tempdocs/PSApi功能测试指南.md +++ /dev/null @@ -1,212 +0,0 @@ -# PSApi 功能测试指南 - -## 📋 已完成的修改 - -### 1. JSX 端(`src/jsx/index.ts`) - -**添加的内容:** -```typescript -import { PSApi } from "./function/ps/api" // 导入 PSApi 类 - -const psApi = new PSApi() // 实例化 PSApi - -// 新增测试函数 -export function testPSApi() { - try { - const selectLength = psApi.layer.getSelectLength(); // 调用 PSApi 的方法 - - return JSON_EX.stringify({ - success: true, - message: "PSApi 调用成功!", - selectLength: selectLength, - info: "当前选中的图层数量: " + selectLength - }); - } catch (error: any) { - return JSON_EX.stringify({ error: error.toString() }); - } -} - -// 暴露到全局 -($.global as any).testPSApi = testPSApi; -``` - -### 2. 前端 API(`src/api/jsxApi/evalJSX.ts`) - -**添加的内容:** -```typescript -testPSApi: async () => { - const jsonStr = await cep.evalScript("testPSApi()"); - const res = JSON.parse(jsonStr); - return res; -} -``` - -### 3. 前端界面(`src/view/Home.vue`) - -**添加的内容:** -- ✅ 新增"测试 PSApi"按钮 -- ✅ 添加 `handleTestPSApi()` 处理函数 - -## 🧪 测试步骤 - -### 步骤 1:重新构建(如果使用简化版) - -如果您还在使用临时的简化版 JSX,现在可以: - -**选项 A:使用简化版测试(推荐先测)** -```powershell -# 当前的 dist_core/jsx/index.js 已经包含简化版 -# 直接测试即可 -``` - -**选项 B:重新构建完整版(包含 PSApi)** -```powershell -cd D:\main\DesignerCEP\Designer - -# 重新构建 Core(会包含新的 testPSApi 函数) -npm run build:core - -# 如果构建失败,需要先修复构建流程 -# 或者手动更新 dist_core/jsx/index.js -``` - -### 步骤 2:清除缓存 - -```powershell -Remove-Item -Recurse -Force "$env:APPDATA\DesignerCache" -ErrorAction SilentlyContinue -``` - -### 步骤 3:在 Photoshop 中测试 - -1. **打开 Photoshop** -2. **打开 DesignerCEP 插件** -3. **登录账号**(会下载最新的 Core) -4. **在主界面点击"测试 PSApi"按钮** - -### 步骤 4:观察结果 - -**预期成功的结果:** - -**控制台日志:** -``` -[__LDX] Detected Core version v1.0.5 -[__LDX] Success: C:/Users/.../jsx/index.js -Call testPSApi - Testing PSApi from api.ts -``` - -**前端界面:** -- 弹出成功提示:`PSApi 调用成功! - 当前选中的图层数量: 1` -- 显示选中图层数(如果没选图层则为 0) - -**如果失败:** -- 查看浏览器控制台的错误信息 -- 查看 ExtendScript Toolkit 的错误(如果有) - -## 📊 测试场景 - -### 场景 1:没有选中图层 -- **操作**:不选择任何图层,点击"测试 PSApi" -- **预期**:显示"选中图层数: 0" - -### 场景 2:选中 1 个图层 -- **操作**:在 PS 中选中 1 个图层,点击"测试 PSApi" -- **预期**:显示"选中图层数: 1" - -### 场景 3:选中多个图层 -- **操作**:按住 Ctrl/Cmd 选中多个图层,点击"测试 PSApi" -- **预期**:显示"选中图层数: N"(N 为实际选中数量) - -## 🎯 测试的意义 - -### 如果测试成功,证明: - -1. ✅ **可以在 JSX 中使用完整的 `api.ts`** -2. ✅ **PSApi 类的方法可以正常调用** -3. ✅ **面向对象的写法在 ExtendScript 中运行正常** -4. ✅ **可以放心使用 api.ts 中的所有功能** - -### 如果测试成功,您可以: - -```typescript -// 在 src/jsx/index.ts 中使用任何 PSApi 的功能 - -// 示例 1:图层操作 -export function selectLayerById(id: number) { - psApi.layer.onIdSelectLayer(id); - return JSON_EX.stringify({ success: true }); -} - -// 示例 2:文档操作 -export function getDocumentSize() { - const size = psApi.doc.getSize(); - return JSON_EX.stringify({ - width: size.cx, - height: size.cy - }); -} - -// 示例 3:颜色操作 -export function setFillColor(hex: string) { - const col = new SolidColor(); - col.rgb.hexValue = hex; - psApi.activeLayer.shape.setFillColor(true, col); - return JSON_EX.stringify({ success: true }); -} - -// 示例 4:字体操作 -export function changeFontFamily(postScriptName: string, name: string, style: string) { - psApi.font.setFontName(postScriptName, name, style); - return JSON_EX.stringify({ success: true }); -} -``` - -## 🚨 常见问题 - -### Q1: 点击按钮没有反应 -**原因:** JSX 未加载或函数未暴露到全局 -**解决:** -- 检查控制台是否有 `[__LDX] Success` 日志 -- 确认 `testPSApi` 已添加到 `$.global` - -### Q2: 报错 "PSApi is not defined" -**原因:** 构建时未包含 `api.ts` -**解决:** -- 确认 `src/jsx/index.ts` 中有 `import { PSApi } from "./function/ps/api"` -- 重新构建或检查构建配置 - -### Q3: 报错 "getSelectLength is not a function" -**原因:** PSApi 的方法没有正确编译 -**解决:** -- 检查 `api.ts` 是否有语法错误 -- 确认构建格式为 IIFE(我们已修改) -- 查看 `dist_core/jsx/index.js` 是否包含 PSApi 的代码 - -### Q4: 构建时报错 "g_logger is not exported" -**原因:** 模块打包问题(我们之前遇到的) -**解决:** -- 暂时使用简化版测试 -- 或者手动修复构建流程 -- 或者等待我们修复完整版构建 - -## 💡 下一步计划 - -### 如果测试通过: -1. ✅ 确认可以使用完整的 `api.ts` -2. 🔄 修复完整版的构建流程 -3. 📦 重新打包包含所有功能的 Core -4. 🚀 上传到服务器供用户使用 - -### 如果测试失败: -1. 📝 记录详细的错误信息 -2. 🔍 分析是构建问题还是代码问题 -3. 🔧 逐步调试修复 - ---- - -**准备好了吗?开始测试吧!** 🚀 - -测试完成后,请告诉我: -- ✅ 测试成功还是失败 -- 📋 控制台的完整日志 -- 💬 遇到的任何问题或错误信息 - diff --git a/temp_backup/Server_redundant/tempdocs/README.md b/temp_backup/Server_redundant/tempdocs/README.md deleted file mode 100644 index 0496cc0..0000000 --- a/temp_backup/Server_redundant/tempdocs/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# 🚀 DesignerCEP 快速部署 - -## 📐 架构 - -``` -app.aidg168.uk → 前端(Caddy) -backend.aidg168.uk → 后端 API(FastAPI + MySQL) -``` - ---- - -## 🎯 快速部署(3 步) - -### 步骤 1:本地构建 - -```powershell -# 构建前端 -cd Designer -npm run build:core - -# 复制到 Server -cd .. -xcopy /E /Y Designer\dist_core\* Server\static\app\ - -# 打包 Server -Compress-Archive -Path Server\* -DestinationPath Server.zip -Force -``` - -### 步骤 2:上传到服务器 - -```powershell -# 上传文件 -scp Server.zip root@103.97.201.136:/root/ -scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile -``` - -### 步骤 3:服务器部署 - -```bash -# SSH 登录 -ssh root@103.97.201.136 - -# 解压 -cd /root -unzip -o Server.zip -d server - -# 启动服务 -cd server -docker-compose up -d - -# 查看日志 -docker-compose logs -f -``` - ---- - -## ✅ 验证 - -访问:`https://app.aidg168.uk/` - ---- - -## 📁 服务器目录结构 - -``` -/root/server/ -├── app/ ← 后端代码 -├── static/ ← 前端文件 -│ └── app/ ← 前端构建产物 -│ ├── index.html -│ └── assets/ -├── docker-compose.yml -├── Dockerfile -└── .env -``` - ---- - -详细文档:查看 `Server/部署到服务器.md` - diff --git a/temp_backup/Server_redundant/tempdocs/Shell架构改造任务清单.md b/temp_backup/Server_redundant/tempdocs/Shell架构改造任务清单.md deleted file mode 100644 index 547136a..0000000 --- a/temp_backup/Server_redundant/tempdocs/Shell架构改造任务清单.md +++ /dev/null @@ -1,83 +0,0 @@ -# Shell 架构改造任务清单 (增强版) - -基于您提供的 `serveradmin` 和 `upload` 逻辑,我们引入了 **“用户分组 (Gray Release)”** 和 **“一键发布 (CI/CD)”** 机制。 - -## 1. 插件端 (Frontend - Shell) - -Shell 端不需要太大变化,主要是版本检查接口需要携带用户信息。 - -- `src/launcher/utils/` - - [ ] **增强版版本检查**: - - 请求 `POST /api/check_update` - - 参数: `{ username: "当前登录用户" }` - - 逻辑: 服务端会根据用户所在的组,返回不同的版本。普通用户返回 `v1.0`,测试组用户返回 `v1.1-beta`。 - -## 2. 服务端 (Backend - Python) - -参考 `serveradmin` 逻辑进行改造。 - -### 2.1 数据库结构升级 - -需要支持不同用户获取不同版本。 - -- **表 `psmark_group` (用户组)**: - - - `id`: int (主键) - - `name`: string (组名,如 "Stable", "Beta") - - `current_version`: string (该组当前使用的版本文件名,如 "release_v1.0.zip") - - `comment`: string - -- **表 `user` (原有表增强)**: - - `group_id`: int (外键,关联 psmark_group) - -### 2.2 接口逻辑增强 - -- `POST /api/check_update`: - 1. 根据 `username` 查 `group_id`。 - 2. 查 `psmark_group` 表获取该组的 `current_version`。 - 3. 返回该版本的下载地址。 - - **优势**: 您可以在后台把某个测试用户切到 "DevGroup",他重启插件就会立刻下载最新的测试版,而其他用户不受影响。 - ---- - -## 3. 发布流程 (Publishing Workflow) - -为了实现“上传时编译”,我们将编写一个自动化脚本。 - -### 3.1 自动化发布脚本 (`scripts/publish.ts`) - -这个脚本将在您的开发机上运行,一键完成所有操作。 - -- **执行流程**: - - 1. **Compile**: 运行 `npm run build:core` (生成 `dist/core`)。 - 2. **Package**: 使用 `adm-zip` 将 `dist/core` 压缩为 `code_{timestamp}.zip`。 - 3. **Upload**: 调用服务端接口 `POST /archives` 将 ZIP 上传。 - 4. **Register (可选)**: 自动调用接口将新版本注册到数据库(可选)。 - -- **命令**: - ```bash - npm run publish # 一键发布 - ``` - -### 3.2 服务端支持 - -- 确保 `POST /archives` 接口能接收文件并保存到 `archives/` 目录 (参考 `server.py` 已有逻辑)。 - ---- - -## 4. 后台管理工具 (Admin Tool) - -您可以直接复用或升级现有的 PyQt 工具 (`upload/admin.py`)。 - -- **功能需求**: - - [ ] **用户分理**: 设置用户的 `group_id`。 - - [ ] **版本指派**: 设置某个 Group 使用哪个 ZIP 版本。 - ---- - -## 5. 执行路线图 - -1. **Day 1 (Publishing)**: 写好 `scripts/publish.ts`,确保能一键编译并上传 ZIP 到您的服务器。 -2. **Day 2 (Backend)**: 改造 Python 后端,加入 Group 表,在此基础上实现“根据用户返回版本”的接口。 -3. **Day 3 (Shell)**: 开发插件 Shell 的下载器,对接上述接口。 diff --git a/temp_backup/Server_redundant/tempdocs/Shell架构改造计划.md b/temp_backup/Server_redundant/tempdocs/Shell架构改造计划.md deleted file mode 100644 index 095743b..0000000 --- a/temp_backup/Server_redundant/tempdocs/Shell架构改造计划.md +++ /dev/null @@ -1,88 +0,0 @@ -# 壳架构 (Shell Architecture) 改造计划 - -为了实现“登录即更新”和“代码保护”,我们将把现有的 `DesignerCEP` 单体项目拆分为 **壳 (Shell)** 和 **核 (Core)** 两部分。 - -## 1. 架构概览 - -| 模块 | 名称 | 职责 | 部署位置 | 更新频率 | -| :-------- | :---------------- | :--------------------------------------------------------------------------------------------------- | :--------------------------------------- | :------------------------------- | -| **Shell** | 启动器 (Launcher) | 1. 负责 CEP 扩展的安装与注册
2. 负责用户登录鉴权
3. **下载并解压** Core 包
4. 跳转加载 Core | **本地用户电脑**
(安装在 PS 扩展目录) | 极低
(仅当下载逻辑变更时更新) | -| **Core** | 业务核 (Business) | 1. 包含所有 Vue 业务页面
2. 包含核心 JSX 脚本
3. 通过 Shell 注入的变量与宿主交互 | **远程服务器**
(ZIP 压缩包) | 极高
(随时发布新功能) | - ---- - -## 2. 目录结构改造建议 - -目前的 `Designer/` 目录将作为**核心业务仓库**,我们需要在其中增加一个专门构建 Shell 的入口。 - -``` -Designer/ - ├── package.json - ├── vite.config.ts # [Core配置] 构建业务代码 (输出 dist/core) - ├── vite.shell.config.ts # [Shell配置] 构建启动器代码 (输出 dist/shell) - │ - ├── src/ - │ ├── main.ts # [Core入口] 业务主入口 (现在的代码) - │ ├── App.vue # [Core] 业务主界面 - │ │ - │ └── launcher/ # [Shell] 启动器模块 (NEW) - │ ├── main.ts # [Shell入口] - │ ├── App.vue # [Shell] 登录与更新进度条界面 - │ ├── updater.ts # [Shell] 下载/解压/校验逻辑 (Node.js) - │ └── login.ts # [Shell] 登录逻辑 - │ - └── dist/ - ├── shell/ # 打包结果:这是给用户安装的 ZXP - │ ├── CSXS/manifest.xml - │ ├── index.html (登录器) - │ └── node_modules (含 fs/adm-zip 等必要依赖) - │ - └── core/ # 打包结果:这是传到服务器的 UPDATE.zip - ├── index.html (业务界面) - ├── assets/ - └── jsx/ (加密后的 JSX) -``` - -## 3. 核心运行流程 (Workflow) - -### 3.1 启动阶段 (Shell) - -1. 用户点击 PS 菜单,加载本地的 `dist/shell/index.html`。 -2. **Shell App** 启动,不再加载复杂的业务组件,只显示登录框。 -3. 用户输入账号密码 -> 请求服务器 `/api/login`。 -4. 登录成功 -> 获取 Token 和 **最新 Core 版本号** (比如 `v1.0.2`)。 - -### 3.2 更新阶段 (Updater) - -1. 检查本地 `C:/Users/xxx/AppData/Roaming/DesignerCache/v1.0.2/` 是否存在。 -2. **不存在 (有更新)**: - - 显示进度条。 - - 从 CDN/服务器下载 `core-v1.0.2.zip`。 - - 使用 Node.js (`adm-zip`) 解压到上述目录。 -3. **存在**: 直接跳过。 - -### 3.3 注入阶段 (Launch) - -1. **加载 JSX**: - - Shell 调用 `CSInterface.evalScript`。 - - 读取缓存目录下的 `v1.0.2/jsx/index.jsx` 内容。 - - 执行 `$.evalFile("C:/.../v1.0.2/jsx/index.jsx")`,把业务函数注入此 ExtendScript 上下文。 -2. **加载 UI**: - - Shell 执行 `window.location.href = "file:///C:/.../v1.0.2/index.html"`。 -3. **接管**: - - 浏览器跳转,页面变成业务界面。 - - 此时 `window.cep` 对象依然存在,业务界面可以继续调用刚刚注入的 JSX 函数。 - -## 4. 兼容性评估 - -**现有框架可以完全兼容,只需做以下调整**: - -1. **Vite 配置拆分**: 需要新增一个 `vite.shell.config.ts`,专门用来打包轻量级的 Shell。 -2. **Node.js 依赖**: Shell 需要打包进 `adm-zip` (解压用) 和 `axios` (下载用)。由于 CEP 支持 Node.js,这完全没问题。 -3. **路由模式**: 业务代码 (Core) 读取本地文件时,路由最好使用 `Hash` 模式 (`createWebHashHistory`),避免 file 协议下的路径问题。 - -## 5. 下一步行动计划 - -1. **[Shell]** 创建 `src/launcher` 目录,编写简单的登录+下载器 Demo。 -2. **[Build]** 配置 `vite.shell.config.ts`,尝试打包出一个只包含登录功能的 ZXP。 -3. **[Test]** 模拟远程更新,手动把现在的业务代码打包成 ZIP 放在本地服务器,测试 Shell 能否下载并跳转。 diff --git a/temp_backup/Server_redundant/tempdocs/psmark脚本分析报告.md b/temp_backup/Server_redundant/tempdocs/psmark脚本分析报告.md deleted file mode 100644 index ed75d5b..0000000 --- a/temp_backup/Server_redundant/tempdocs/psmark脚本分析报告.md +++ /dev/null @@ -1,89 +0,0 @@ -# psmark 脚本分析与功能报告 - -## 1. 概述 - -在 `psmark` 目录下发现的 `JSX*.py` 文件(JSX2.py - JSX9.py)主要承担了**Photoshop 自动化脚本容器**的角色。 -这些 Python 文件本身不包含图像处理逻辑,而是作为 Adobe ExtendScript (JSX) 代码的“包装壳”。所有的核心自动化逻辑(如图层操作、裁片缩放、排版等)都由嵌入的 JSX 字符串实现。 - -## 2. 文件功能详细清单 - -| 文件名 | 核心功能 | 详细描述 | -| :----------- | :-------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **JSX2.py** | **裁片射出宽高缩放** | - 遍历文档图层,根据图层名称(包含尺寸信息)进行精确缩放。
- 包含像素与毫米的自动换算。
- 处理 90 度/180 度 旋转逻辑。
- 使用 `ActionManager` 进行高效的选区和变换操作。 | -| **JSX3.py** | **设置花样组顺序居中** | - 专用于印花对位。
- 自动识别 "P" 开头的花样图层。
- 将花样层对齐到“大货裁片”组的中心位置。
- 包含蒙版选区获取和坐标计算逻辑。 | -| **JSX4.py** | **图像切割** | - 根据特定图层的边界对文档进行裁剪。
- 包含出血/边距处理(例如自动从选区扩展一定像素)。
- 适用于从大图中提取独立裁片。 | -| **JSX5.py** | **图像切割 (变体)** | - 功能与 JSX4 类似,侧重于特定图层组的裁剪和蒙版应用。 | -| **JSX6.py** | **裁片射出宽高缩放 (变体)** | - 与 JSX2 类似,提供裁片缩放和定位功能。
- 强调了“前景色修改”和“图层选择”等辅助操作。 | -| **JSX7.py** | **裁片射出缩放模板** | - **关键特性**:引入了“**缩放定位点**”图层概念。
- 不以图层中心为原点,而是根据“缩放定位点”图层的选区中心进行缩放变换。
- 包含 `烧花线添加` 功能,用于绘制剪口和标记线。 | -| **JSX8.py** | **批量化替换外链新 (UI)** | - **全自动化工作流脚本**。
- **内置 UI**:包含一个 ScriptUI 编写的对话框,用于选择文件夹路径。
- **功能**:
1. 批量打开文件。
2. 自动替换智能对象链接(换花型)。
3. `码标添加`:自动生成包含文件名的尺寸标记。
4. `花样标准化`:统一花样大小并添加白底。
5. 自动另存为 TIF 格式并归档。 | -| **JSX9.py** | **按中心点比例缩放** | - 结合了 JSX2 和 JSX7 的特性。
- 专注于按“缩放定位点”进行**等比例**或**宽高独立**缩放。
- 包含详细的 `ActionManager` 变换代码(`transform` 命令)。 | -| **JSX16.py** | **花样图层导出** | - 遍历图层组(特别是“填充底图”),将子图层导出为 TIF。
- 处理“最大白边值”图层以确定裁剪边界。
- 包含智能对象转换、重新链接、蒙版合并等复合操作。 | -| **JSX17.py** | **定位码批量快速换图 (UI)** | - **带 ScriptUI**。
- 全自动批量流程:选择模板路径、素材路径、输出路径。
- 遍历素材图片,打开模板,替换智能对象(`placedLayerRelinkToFile`),应用预设图案填充,合并图层并另存。
- 支持读取 JSON 数据来匹配图案名称。 | -| **JSX18.py** | **龙服快速换图 (UI)** | - **带 ScriptUI**(定制版本)。
- 读取文件夹文件列表,允许用户在 UI 中输入“数量”信息。
- 根据输入信息更新图层文本内容,替换裁片智能对象链接,合并并保存。 | -| **JSX19.py** | **裁片抓取与导入** | - 批量置入 PDF 文件。
- **自动旋转特性**:通过解析文件名(如包含 `_180`)自动判断是否需要旋转 180 度导入。
- 自动建立“大货裁片”组并归档。 | -| **JSX20.py** | **混合裁片导出** | - 遍历包含“大货裁片”名称的图层组。
- 逐个提取子图层,应用蒙版,裁切到边界,导出为 TIF 文件。
- 使用历史记录回退(`historyState`)来恢复状态以处理下一个图层。 | -| **JSX21.py** | **裁片排版基础** | - 基础排版功能库。
- `创建裁片排版文档`:按毫米创建新画布。
- `置入链接的智能对象`:将外部文件作为链接对象置入。
- `裁片排版_lay`:提供基于毫米坐标的精确位移功能。 | -| **JSX22.py** | **模特换衣功能 (UI)** | - **带 ScriptUI**。
- 针对模特展示图的批量替换。
- 遍历素材目录,替换模板中名为“替换对象”的智能对象。
- 支持保持原始目录结构导出,支持切片导出(Web 切片)。 | -| **JSX23.py** | **S/O 样自动连晒 (UI)** | - **带 ScriptUI**。
- 自动生成连晒(米样)效果。
- 将图片定义为图案,填充到指定宽高的文档中(平铺),并添加对应的文件名文字标签。
- 保存两份:一份纯拼贴,一份带文字标签。 | -| **JSX24.py** | **自动米样拼贴 (UI)** | - **带 ScriptUI**。
- 与 JSX23 类似但逻辑不同,这是真正的**拼图**(Collage)。
- 读取文件夹所有图片,按高度排序。
- 自动计算总画布大小,将图片紧凑排列(换行逻辑)拼贴到一个大文档中。 | -| **JSX26.py** | **模特多色换图** | - 利用**快照**(Snapshot)机制进行批量处理。
- 遍历文件夹素材,替换“贴图位置”组内的图层内容。
- 支持对替换后的图案进行位移(Offset)以制作不同花位效果。
- 导出 TIF 后回退到快照状态。 | -| **JSX27.py** | **新的米样缩放 (UI)** | - **带 ScriptUI**。
- 批量调整图片尺寸到指定的厘米数(Resize Image)。
- 随后进行画布扩展和文字标签添加,用于制作标准化的缩放样图。 | - -## 3. 技术架构特点 - -### 3.1 Python 包装器模式 - -实际上是“伪 Python”代码。 - -```python -# 典型结构 -dxf7_jscode = """ -function 核心功能() { - // 实际的 ExtendScript (JavaScript) 代码 - var doc = app.activeDocument; - ... -} -""" -``` - -这种结构是为了便于 Python 后端(可能是旧的自动化系统)直接将 JS 代码发送给 Photoshop 执行。迁移时应直接提取 `"""` 内部的内容。 - -### 3.2 ActionManager (AM) 代码 - -脚本极度依赖 Photoshop 的底层 ActionManager API(`executeAction`, `ActionDescriptor`)。 - -- **优点**:执行速度快,能实现 DOM API(普通 JS 对象)无法实现的功能(如“再次变换”、“应用图层样式”、“特定算法的选区运算”)。 -- **缺点**:代码可读性差,维护难度大(充斥着 `stringIDToTypeID`)。 - -### 3.3 命名约定 - -脚本逻辑强依赖于图层和组的命名规范: - -- `P...`:识别为花样图层。 -- `-大货裁片`:识别为标准的裁片组模板。 -- `缩放定位点`:用于计算变换中心的辅助图层。 -- `_` 分隔符:用于从图层名中提取尺寸参数(如 `名称_宽度_高度`)。 - -## 4. 迁移与集成建议 (DesignerCEP) - -为了将这些资产整合到当前的 `DesignerCEP` (Vue + TypeScript + CEP) 项目中,建议采取以下步骤: - -1. **代码提取 (Extract)**: - - - 废弃 `.py` 文件。 - - 将字符串内的 JS 代码提取并在 `src/jsx/` 目录下建立对应的 `.jsx` 文件(建议按功能重命名,如 `ResizeUtils.jsx`, `BatchProcess.jsx`)。 - -2. **模块化重构 (Refactor)**: - - - 原脚本大量使用全局变量,容易造成污染。需要将其封装为独立的函数,例如 `function scaleLayerByAnchor(layerName, anchorLayerName) { ... }`。 - - 将通用的 `ActionManager` 辅助函数(如 `executeAction` 的封装)移动到统一的工具库中。 - -3. **UI 重写 (Modernize UI)**: - - - **重点**:`JSX8.py` 中的 ScriptUI 弹窗(灰色原生界面)应完全废弃。 - - 使用 **Vue + Element Plus/Arco Design** 重写批量处理界面。 - - 前端收集用户输入的路径和选项,通过 `cep.ts` 桥接层传递给 JSX 执行核心逻辑。 - -4. **功能桥接 (Bridge)**: - - 在 `src/jsx/index.ts` 中暴露新的接口,供前端调用。 - - 例如:`canvas_cut_image` (对应 JSX4), `auto_resize_layer` (对应 JSX2)。 diff --git a/temp_backup/Server_redundant/tempdocs/zhihu_articles.json b/temp_backup/Server_redundant/tempdocs/zhihu_articles.json deleted file mode 100644 index 0ad1a55..0000000 --- a/temp_backup/Server_redundant/tempdocs/zhihu_articles.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "title": "【CEP教程-17】插件的打包和发布", - "url": "https://zhuanlan.zhihu.com/p/27361054277" - }, - { - "title": "【CEP教程-16】JSX的工程化", - "url": "https://zhuanlan.zhihu.com/p/22605290525" - }, - { - "title": "【UXP教程-2】UXP插件开发起步", - "url": "https://zhuanlan.zhihu.com/p/20904402159" - }, - { - "title": "【CEP教程-15】前端框架在插件面板中的应用", - "url": "https://zhuanlan.zhihu.com/p/683712943" - }, - { - "title": "我给三年级女儿开发了一个打字网站", - "url": "https://zhuanlan.zhihu.com/p/676856628" - }, - { - "title": "【CEP教程-14】数据存储相关", - "url": "https://zhuanlan.zhihu.com/p/675795467" - }, - { - "title": "【CEP教程-13】nodejs在插件开发中的应用", - "url": "https://zhuanlan.zhihu.com/p/661392566" - }, - { - "title": "【CEP教程-12】如何从Ps中导出图片", - "url": "https://zhuanlan.zhihu.com/p/658067352" - }, - { - "title": "【CEP教程-11】生成器", - "url": "https://zhuanlan.zhihu.com/p/643541900" - }, - { - "title": "【CEP教程-10】图层处理那些事", - "url": "https://zhuanlan.zhihu.com/p/617477492" - }, - { - "title": "【CEP教程-10】Action Manager完全指南 - 下篇", - "url": "https://zhuanlan.zhihu.com/p/608104095" - }, - { - "title": "【CEP教程-9】Action Manager完全指南 - 中篇", - "url": "https://zhuanlan.zhihu.com/p/601014597" - }, - { - "title": "【Adobe UXP插件开发中文教程】- 1. 简介", - "url": "https://zhuanlan.zhihu.com/p/600569875" - }, - { - "title": "【CEP教程-8】Action Manager完全指南 - 上篇", - "url": "https://zhuanlan.zhihu.com/p/600014746" - }, - { - "title": "Photoshop插件开发教程 - (7)JSX脚本指南 - DOM篇", - "url": "https://zhuanlan.zhihu.com/p/596166382" - }, - { - "title": "Photoshop插件开发教程 - (6)面板与宿主之间的交互", - "url": "https://zhuanlan.zhihu.com/p/566983957" - }, - { - "title": "Photoshop插件开发教程 - (5)插件面板的样式", - "url": "https://zhuanlan.zhihu.com/p/563847844" - }, - { - "title": "Photoshop插件开发教程 - (4)开发工具选择和调试", - "url": "https://zhuanlan.zhihu.com/p/559290141" - }, - { - "title": "Photoshop插件开发教程 - (3)CEP插件面板结构介绍", - "url": "https://zhuanlan.zhihu.com/p/555070606" - }, - { - "title": "Photoshop插件开发教程 - (2)开发环境搭建", - "url": "https://zhuanlan.zhihu.com/p/532152091" - }, - { - "title": "Photoshop插件开发教程 - (1)插件类型", - "url": "https://zhuanlan.zhihu.com/p/518229060" - } -] \ No newline at end of file diff --git a/temp_backup/Server_redundant/tempdocs/修复命令.md b/temp_backup/Server_redundant/tempdocs/修复命令.md deleted file mode 100644 index 07083b3..0000000 --- a/temp_backup/Server_redundant/tempdocs/修复命令.md +++ /dev/null @@ -1,44 +0,0 @@ -# 🔧 服务器修复命令 - -## 在服务器执行以下命令: - -```bash -# 1. 创建日志目录 -mkdir -p /var/log/caddy - -# 2. 设置权限(让 Caddy 能写入) -chown -R caddy:caddy /var/log/caddy -chmod 755 /var/log/caddy - -# 3. 重新上传 docker-compose.yml(已修改端口映射) -# 在本地执行: -# scp Server/docker-compose.yml root@103.97.201.136:/root/server/ - -# 4. 重新上传 Caddyfile(已修改反向代理) -# 在本地执行: -# scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile - -# 5. 重启 Docker 容器(应用端口映射) -cd /root/server -docker-compose down -docker-compose up -d - -# 6. 启动 Caddy -systemctl restart caddy - -# 7. 查看状态 -systemctl status caddy -docker-compose ps - -# 8. 测试 -curl http://localhost:8000/health -curl -I http://localhost/ -``` - -## ✅ 全部成功后访问 - -``` -https://app.aidg168.uk/ -https://backend.aidg168.uk/health -``` - diff --git a/temp_backup/Server_redundant/tempdocs/修复说明.md b/temp_backup/Server_redundant/tempdocs/修复说明.md deleted file mode 100644 index 6ed2fda..0000000 --- a/temp_backup/Server_redundant/tempdocs/修复说明.md +++ /dev/null @@ -1,131 +0,0 @@ -# ✅ 修复完成:使用 JSON 文件替代 MySQL - -## 🔧 问题与解决 - -### 原问题 -启动时弹出错误:`Can't connect to MySQL server on 'localhost'` - -### 根本原因 -- MySQL 运行在 Docker 容器中,端口未映射到宿主机 -- 远程 MySQL 连接复杂,需要 SSH 隧道 - -### 最终方案 ✅ -**使用 SSH + JSON 文件存储版本信息** - -- ✅ 不需要配置 MySQL -- ✅ 不需要额外的库(sshtunnel, pymysql) -- ✅ 更简单、更可靠 -- ✅ 版本信息存储在服务器:`/var/www/app_versions/.deployments.json` - ---- - -## 📦 当前依赖(精简版) - -``` -PyQt5 # GUI 界面 -requests # API 请求 -paramiko # SSH 连接 -``` - ---- - -## 🗄️ 数据存储方式 - -### JSON 文件位置 -``` -/var/www/app_versions/.deployments.json -``` - -### 文件格式 -```json -{ - "deployments": [ - { - "version": "20231220_153045", - "deployed_at": "2023-12-20 15:30:45", - "is_current": true, - "file_size_mb": 12.5, - "comment": "修复主题同步bug" - }, - { - "version": "20231220_102030", - "deployed_at": "2023-12-20 10:20:30", - "is_current": false, - "file_size_mb": 12.3, - "comment": "初始版本" - } - ] -} -``` - ---- - -## 🚀 现在可以正常使用 - -### 1. 启动工具 -```bash -cd AdminTool -python admin_gui.py -``` - -**不会再弹出数据库错误!** ✅ - -### 2. 测试系统 -```bash -cd AdminTool -python test_version_system.py -``` - -应该看到: -``` -✅ 测试完成!版本管理系统一切正常 -``` - -### 3. 开始部署 -1. 构建前端:`cd Designer && npm run build:core` -2. 打开 GUI,切换到"自动化部署" -3. 选择 `dist_core` 目录 -4. 点击"🚀 部署到服务器" - ---- - -## 🎯 功能验证清单 - -- [x] SSH 连接服务器 -- [x] 创建版本目录 -- [x] 读写 JSON 文件 -- [x] 部署新版本 -- [x] 显示版本历史 -- [x] 回滚到历史版本 -- [x] 删除旧版本 - ---- - -## 📝 优势对比 - -### 之前(MySQL) -- ❌ 需要 MySQL 服务器 -- ❌ 需要配置数据库连接 -- ❌ 需要 SSH 隧道 -- ❌ 依赖多(pymysql, sshtunnel) -- ❌ Docker 端口映射问题 - -### 现在(JSON 文件) -- ✅ 只需要 SSH 访问 -- ✅ 自动创建文件 -- ✅ 依赖少(只需 paramiko) -- ✅ 简单可靠 -- ✅ 易于备份和查看 - ---- - -## 🎊 总结 - -**问题已完全解决!** 现在可以: -1. 正常启动 GUI(不会弹窗) -2. 部署新版本 -3. 管理版本历史 -4. 随时回滚 - -**下一步**:开始使用部署功能! - diff --git a/temp_backup/Server_redundant/tempdocs/全量接口文档.md b/temp_backup/Server_redundant/tempdocs/全量接口文档.md deleted file mode 100644 index 54f4041..0000000 --- a/temp_backup/Server_redundant/tempdocs/全量接口文档.md +++ /dev/null @@ -1,412 +0,0 @@ -# Server API 全量文档 - -## 概述 - -- **基础地址**:`http://localhost:8000` -- **版本前缀**:`/api/v1` -- **认证方式**: - - Header: `Authorization: Bearer ` (用于普通用户接口) - - Header: `x-admin-token: admin-secret-token` (用于管理员接口) - - Header: `x-api-key: ` (用于部分工具接口) - ---- - -## 📚 1. 认证模块 (Auth) - -**Base Path**: `/api/v1/auth` - -### 1.1 注册 - -- **URL**: `POST /register` -- **功能**: 用户注册 -- **请求体**: - -```json -{ - "username": "user1", - "password": "password123", - "confirm_password": "password123", - "email": "user1@example.com", // 可选 - "code": "123456", // 验证码(可选) - "device_id": "device_001" // 可选,默认 unknown_device -} -``` - -- **响应**: - -```json -{ - "access_token": "eyJhbG...", - "token_type": "bearer", - "username": "user1" -} -``` - -### 1.2 登录 - -- **URL**: `POST /login` -- **功能**: 用户登录,获取 Token -- **请求体**: - -```json -{ - "username": "user1", - "password": "password123", - "device_id": "device_001" -} -``` - -- **响应**: 同注册接口 - -### 1.3 发送验证码 - -- **URL**: `POST /send-verification-code` -- **功能**: 发送注册/验证邮件验证码 -- **请求体**: - -```json -{ - "email": "user1@example.com" -} -``` - -### 1.4 验证邮箱 - -- **URL**: `POST /verify-email` -- **功能**: 验证邮箱验证码 -- **请求体**: - -```json -{ - "username": "user1", - "code": "123456" -} -``` - -### 1.5 忘记密码 - -- **URL**: `POST /forgot-password` -- **功能**: 发送重置密码邮件 -- **请求体**: - -```json -{ - "email": "user1@example.com" -} -``` - -### 1.6 重置密码 - -- **URL**: `POST /reset-password` -- **功能**: 使用 Token 重置密码 -- **请求体**: - -```json -{ - "email": "user1@example.com", - "token": "123456", - "new_password": "newpassword123", - "confirm_password": "newpassword123" -} -``` - -### 1.7 登出 - -- **URL**: `POST /logout` -- **功能**: 退出当前设备登录 -- **请求体**: - -```json -{ - "username": "user1", - "device_id": "device_001" -} -``` - -### 1.8 许可证验证 (Verify) - -- **URL**: `POST /verify` -- **功能**: 验证当前 Token 和会话是否有效(用于应用启动检查) -- **Headers**: `Authorization: Bearer ` -- **请求体**: - -```json -{ - "username": "user1", - "device_id": "device_001" -} -``` - -- **响应**: - -```json -{ - "valid": true, - "username": "user1", - "expire_date": "2025-12-31T23:59:59" // 若有过期时间 -} -``` - -### 1.9 心跳 (Heartbeat) - -- **URL**: `POST /heartbeat` -- **功能**: 维持会话活跃状态 -- **请求体**: - -```json -{ - "username": "user1", - "device_id": "device_001" -} -``` - -### 1.10 获取在线时长 - -- **URL**: `GET /online-time/{username}` -- **功能**: 获取用户累计在线时长 -- **响应**: - -```json -{ - "username": "user1", - "total_seconds": 3600, // 历史累计 - "active_seconds": 120 // 当前会话 -} -``` - ---- - -## 🖥️ 2. 客户端模块 (Client) - -**Base Path**: `/api/v1/client` - -### 2.1 检查更新 - -- **URL**: `POST /check_update` -- **功能**: 检查插件是否有新版本 -- **请求体**: - -```json -{ - "username": "user1" // 用于检查用户所在组的特定版本 -} -``` - -### 2.2 客户端登录 - -- **URL**: `POST /login` -- **功能**: 客户端专用登录,返回更多用户信息 -- **请求体**: 同 Auth 登录 -- **响应**: - -```json -{ - "code": 200, - "message": "success", - "data": { - "token": "eyJ...", - "username": "user1", - "expire_date": "2025-12-31", - "permissions": ["plugin.use"] - } -} -``` - ---- - -## 👤 3. 用户资料 (User Profile) - -**Base Path**: `/api/v1` - -### 3.1 获取资料 - -- **URL**: `GET /user/profile?username=user1` -- **功能**: 获取用户详细资料(积分、VIP 状态、签到信息等) -- **Headers**: `Authorization: Bearer ` - -### 3.2 更新资料 - -- **URL**: `PUT /user/profile` -- **功能**: 更新昵称、头像等 -- **请求体**: - -```json -{ - "username": "user1", - "nickname": "New Nickname", - "avatar": "http://example.com/avatar.jpg" -} -``` - -### 3.3 积分历史 - -- **URL**: `GET /points/history` -- **功能**: 分页获取积分变动记录 -- **Query Params**: `username`, `type` (可选: checkin/consume/reward), `page`, `limit` - ---- - -## 📅 4. 签到模块 (Check-In) - -**Base Path**: `/api/v1/checkin` - -### 4.1 每日签到 - -- **URL**: `POST /daily` -- **功能**: 执行每日签到 -- **请求体**: `{"username": "user1"}` -- **响应**: - -```json -{ - "code": 200, - "data": { - "success": true, - "points_earned": 10, - "consecutive_days": 5, - "message": "签到成功..." - } -} -``` - -### 4.2 签到状态 - -- **URL**: `GET /status?username=user1` -- **功能**: 检查今日是否已签到 - -### 4.3 签到日历 - -- **URL**: `GET /calendar/{year}/{month}` -- **功能**: 获取指定月份的签到日期列表 -- **Query Params**: `username` - -### 4.4 签到记录 (列表) - -- **URL**: `GET /history?username=user1&page=1` -- **功能**: 分页获取签到记录 - -### 4.5 获取签到规则 - -- **URL**: `GET /config` -- **功能**: 获取签到奖励规则(公开接口,无需 Admin Token) -- **响应**: - -```json -{ - "code": 200, - "data": [ - { - "consecutive_days": 1, - "base_points": 10, - "bonus_points": 0, - "total_points": 10 - }, - { - "consecutive_days": 7, - "base_points": 10, - "bonus_points": 20, - "total_points": 30 - } - ] -} -``` - ---- - -## 🛠️ 5. 功能使用 (Feature) - -**Base Path**: `/api/v1/feature` - -### 5.1 使用功能的 (扣费接口) - -- **URL**: `POST /use` -- **功能**: 记录功能使用,扣除积分或 VIP 配额 -- **请求体**: - -```json -{ - "username": "user1", - "feature_key": "ai_remove_bg", - "device_id": "device_001" -} -``` - -- **响应**: - -```json -{ - "code": 200, - "data": { - "success": true, - "cost_type": "points", // 或 vip_quota, free - "points_cost": 10, - "message": "消耗10积分" - } -} -``` - ---- - -## 🧮 6. 工具演示 (JSX Demo) - -**Base Path**: `/api/v1/jsx_demo` - -### 6.1 计算表达式 - -- **URL**: `POST /calculate` -- **Headers**: `x-api-key: ` -- **请求体**: `{"expression": "1+1"}` - ---- - -## 📊 7. 统计与日志 (Analytics & Stats) - -**Base Path**: `/api/v1` - -### 7.1 上报日志 - -- **URL**: `POST /analytics/log` -- **功能**: 客户端上报行为日志 -- **请求体**: - -```json -{ - "username": "user1", - "device_id": "dev1", - "action": "click_button", - "timestamp": 1234567890 -} -``` - -### 7.2 获取用户统计 - -- **URL**: `GET /analytics/stats/{username}` - ---- - -## 👑 8. 管理员后台 (Admin) - -**Headers**: `x-admin-token: admin-secret-token` (部分接口兼容 Form 表单 token) - -### 8.1 基础管理 (Base Path: `/api/v1/admin`) - -- `POST /upload_version`: 上传新版本插件包 -- `GET /archives`: 列出历史版本 -- `POST /groups`: 创建用户组 -- `GET /groups`: 获取用户组列表 -- `PUT /groups/{id}`: 更新用户组 -- `GET /users`: 获取所有用户列表 -- `PUT /users/{id}/group`: 修改用户所属组 -- `PUT /users/{id}/permissions`: 修改用户权限 - -### 8.2 配置管理 (Base Path: `/api/v1/admin/config`) - -- **功能配置** (`/features`): GET(列表), POST(新增), PUT(/{key} 更新), DELETE(/{key} 删除) -- **VIP 配置** (`/vip`): GET(列表), PUT(/{type} 更新) -- **签到配置** (`/checkin`): GET(列表), POST(新增), PUT(/{days} 更新), DELETE(/{days} 删除) - -### 8.3 数据统计 (Base Path: `/api/v1/admin/stats`) - -- `GET /today`: 今日概览 (用户数、签到数、功能使用数) -- `GET /feature-usage`: 功能使用排行 (Top 10) -- `GET /points-trend`: 积分收支趋势 (近 7 天) diff --git a/temp_backup/Server_redundant/tempdocs/前端代码结构与功能说明.md b/temp_backup/Server_redundant/tempdocs/前端代码结构与功能说明.md deleted file mode 100644 index 3d1881f..0000000 --- a/temp_backup/Server_redundant/tempdocs/前端代码结构与功能说明.md +++ /dev/null @@ -1,82 +0,0 @@ -# 前端代码结构与功能说明 (DesignerCEP) - -本文档详细说明了 `DesignerCEP` 项目的前端代码结构,包括新引入的 **"Shell (启动器) + Core (业务核)"** 双层架构。 - ---- - -## 1. 核心架构说明 - -项目被设计为两个独立的部分,分别构建: - -1. **Shell (启动器)**: - - **职责**: 极轻量级,负责登录验证、检查版本、下载 ZIP、解压、动态加载 Core。 - - **代码位置**: `src/launcher/` - - **构建产物**: 生成 ZXP 安装包的主体。 -2. **Core (业务核)**: - - **职责**: 包含所有设计功能(Vue 界面 + JSX 脚本)。 - - **代码位置**: `src/` (除 `launcher` 外) - - **构建产物**: 被打包成 ZIP,由 Shell 下载并运行。 - ---- - -## 2. 目录结构详解 - -### 2.1 根目录配置 - -| 文件名 | 作用 | -| :--------------------- | :------------------------------------------------------------------------------------------------------------ | -| `package.json` | 项目依赖管理。包含 `npm run build:shell` (构建启动器) 和 `npm run build:core` (构建业务核) 等脚本。 | -| `vite.config.ts` | **Core 的构建配置**。用于开发环境 (`npm run dev`) 和业务核打包。配置了 API 代理和 Vue 插件。 | -| `vite.shell.config.ts` | **Shell 的构建配置**。专门用于构建启动器,指定入口为 `src/launcher/index.html`,并打包为独立的 CEP 插件结构。 | -| `prod.cep.config.ts` | CEP 插件的生产环境配置文件 (Manifest)。定义包括插件 ID、版本、窗口大小、支持的宿主 (PS, AI 等)。 | -| `tsconfig.json` | TypeScript 配置文件。定义了别名 (`@/`, `@plugins/`) 和编译选项。 | - -### 2.2 Shell 启动器 (`src/launcher/`) - -这是用户安装 ZXP 后第一时间运行的代码。 - -| 路径/文件名 | 作用 | -| :---------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`index.html`** | Shell 的 HTML 入口。引入 `CSInterface.js` 和 `main.ts`。 | -| **`main.ts`** | Shell 的 JS 入口。初始化 Vue 应用,挂载 `App.vue`。 | -| **`App.vue`** | Shell 的根组件。包含 ``,用于切换登录/更新界面。 | -| **`router.ts`** | Shell 的路由配置。定义了 `/login` (登录页) 和 `/register` (注册页)。 | -| **`view/Login.vue`** | **核心登录界面**。集成了 `Updater` 类,点击登录后自动执行:**登录 -> 检查更新 -> 下载 ZIP -> 解压 -> 跳转**。 | -| **`view/Register.vue`** | 注册界面。 | -| **`utils/updater.ts`** | **核心更新逻辑**。包含 `Updater` 类。负责调用后端 API (`check_update`),使用 `fs` 写入文件,使用 `adm-zip` 解压,最后修改 `window.location.href` 加载 Core。 | -| **`jsx/index.ts`** | Shell 的最小化 JSX 脚本。CEP 插件必须包含至少一个 JSX,这里仅返回版本号,不包含重型业务逻辑。 | - -### 2.3 Core 业务核 (`src/`) - -这是实际的业务软件,被下载后动态加载。 - -| 路径/目录 | 作用 | -| :------------------------------ | :----------------------------------------------------------------------------------------------------- | -| **`main.ts`** | Core 的入口文件。引入 Arco Design,全局样式等。 | -| **`App.vue`** | Core 的根组件。 | -| **`router/index.ts`** | Core 的路由配置。包含 `/home`, `/about` 等业务页面。(注意:已移除登录/注册路由,因为这由 Shell 接管)。 | -| **`view/Home.vue`** | 主页组件。包含主要的功能入口和测试按钮。 | -| **`jsx/`** | **Adobe ExtendScript (JSX) 脚本目录**。 | -|   `index.ts` | JSX 入口。导出所有供 Vue 调用的 Photoshop 接口函数。 | -|   `utils/ActionManager.ts` | action manager 底层封装 (如载入选区、填充、新建文档)。底层核心。 | -|   `utils/LayerUtils.ts` | 图层操作封装 (如遍历、查找、重命名)。 | -| **`utils/cep.ts`** | `CSInterface` 的 TS 封装。用于前端 Vue 调用后端 JSX (`evalScript`)。 | -| **`utils/request.ts`** | 基于 Umi-Request 或 Axios 的 HTTP 请求封装 (业务用)。 | - -### 2.4 构建插件 (`plugins/`) - -用于辅助 Vite 打包 CEP 环境的代码。 - -| 路径/文件名 | 作用 | -| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **`jsx/cepPlugin.ts`** | **构建核心**。Vite 插件。负责:
1. 监听 JSX 变化并重编译 (Dev)。
2. 生产环境调用 `rollup` 编译 JSX 为 `index.js`。
3. 复制 manifest.xml 和 index.html 到 `dist` 目录。 | -| **`buildJsx/index.ts`** | 单独的 Rollup 构建配置,专门用于将 `src/jsx/*.ts` 编译成 Photoshop 能跑的 ES3 格式 JS。 | -| **`template/`** | 存放 `manifest.xml`, `.debug` 等 CEP 配置文件的模板。 | - ---- - -## 3. 开发与发布流程总结 - -1. **开发 Shell**: 修改 `src/launcher` -> `npm run build:shell` -> 生成 ZXP。 -2. **开发 Core**: 修改 `src/view` 或 `src/jsx` -> `npm run build:core` -> 得到业务 ZIP 包。 -3. **用户视角**: 安装 ZXP -> 启动插件 -> 看到登录框 (Shell) -> 登录并下载最新 Core -> 自动跳转进入业务界面。 diff --git a/temp_backup/Server_redundant/tempdocs/前端安全升级接入指南.md b/temp_backup/Server_redundant/tempdocs/前端安全升级接入指南.md deleted file mode 100644 index 3b5d626..0000000 --- a/temp_backup/Server_redundant/tempdocs/前端安全升级接入指南.md +++ /dev/null @@ -1,126 +0,0 @@ -# 前端安全升级接入指南 - -为了提高安全性,后端鉴权机制已升级为 **Token + Device Binding + Session Enforcement**。 - -**⚠️ 核心变更:所有身份验证相关的接口现在都强制要求携带 `device_id`。** - -前端必须配合进行以下改动,否则接口将返回 `422 Unprocessable Entity` (参数缺失) 或 `401 Unauthorized` (设备不匹配)。 - ---- - -## 🛠️ 接口改造清单 - -请检查并修改以下所有接口的调用参数: - -### 1. 登录接口 (Login) -* **URL**: `/api/v1/auth/login` -* **变更**: 新增必填字段 `device_id`。 -* **说明**: 之前的文档描述有误,登录接口**必须**传此参数,否则无法建立会话。 - -**修改后示例:** -```typescript -const loginData = { - username: "user1", - password: "pwd", - device_id: getDeviceId() // ✅ 必传 -}; -``` - -### 2. 注册接口 (Register) -* **URL**: `/api/v1/auth/register` -* **变更**: 新增必填字段 `device_id`。 -* **说明**: 注册成功后会自动登录,因此必须绑定当前设备。 - -**修改后示例:** -```typescript -const registerData = { - username: "user1", - password: "pwd", - confirm_password: "pwd", - device_id: getDeviceId() // ✅ 必传 -}; -``` - -### 3. 登出接口 (Logout) -* **URL**: `/api/v1/auth/logout` -* **变更**: 新增必填字段 `device_id`。 -* **说明**: 用于精准注销当前设备的会话,而不影响用户在其他设备上的登录状态。 - -**修改后示例:** -```typescript -const logoutData = { - username: "user1", - device_id: getDeviceId() // ✅ 必传 -}; -``` - -### 4. 心跳保活接口 (Heartbeat) -* **URL**: `/api/v1/auth/heartbeat` -* **变更**: 新增必填字段 `device_id`。 -* **说明**: 用于维持当前设备 Session 的活跃状态。 - -**修改后示例:** -```typescript -const heartbeatData = { - username: "user1", - device_id: getDeviceId() // ✅ 必传 -}; -``` - -### 5. 许可证验证接口 (Verify) -* **URL**: `/api/v1/auth/verify` -* **变更**: 新增必填字段 `device_id`。 -* **说明**: 后端会校验 Token 中的设备 ID 是否与参数中的设备 ID 一致,且 Session 是否活跃。 - -**修改后示例:** -```typescript -const verifyData = { - username: "user1", - timestamp: Date.now(), - device_id: getDeviceId() // ✅ 必传 -}; -``` - ---- - -## 🚨 统一错误处理 (Interceptor) - -由于新的强校验机制,`401 Unauthorized` 可能会在任何接口出现(不仅仅是 Token 过期,也可能是被踢下线)。 - -前端拦截器需要统一处理 `401`,强制跳转到登录页。 - -**Axios 拦截器示例:** - -```typescript -axios.interceptors.response.use( - (response) => response, - (error) => { - if (error.response && error.response.status === 401) { - // 1. 清除本地 Token - localStorage.removeItem('access_token'); - - // 2. 提示用户 - const msg = error.response.data.detail || '登录已失效,请重新登录'; - // Message.error(msg); // Arco Design / Element UI - console.error(msg); - - // 3. 跳转登录页 - // 如果是 Shell 环境,跳转到 Shell 登录 - if (window.location.hash.indexOf('/login') === -1) { - window.location.href = '/shell/index.html#/login'; - } - } - return Promise.reject(error); - } -); -``` - ---- - -## 💡 关于 device_id 的说明 - -`device_id` 是用于标识客户端设备的唯一字符串。 - -* **生成方式**:建议在应用启动时检查 `LocalStorage`,如果没有则生成一个 UUID 并存入;如果有则直接读取。 -* **作用**:用于区分不同的客户端实例,实现单设备登录限制(互踢功能)。 -* **持久化**:必须确保存储在浏览器/CEP 环境的持久化存储中(如 `localStorage`),避免刷新页面后变化。 diff --git a/temp_backup/Server_redundant/tempdocs/后端API接口文档.md b/temp_backup/Server_redundant/tempdocs/后端API接口文档.md deleted file mode 100644 index 1f906c5..0000000 --- a/temp_backup/Server_redundant/tempdocs/后端API接口文档.md +++ /dev/null @@ -1,160 +0,0 @@ -# DesignerCEP 后端 API 接口文档 - -本文档描述了 DesignerCEP 后端服务的 API 接口规范,包括客户端插件接口和后台管理接口。 - -## 1. 基础信息 - -- **Base URL**: `http://localhost:8000/api/v1` -- **文件下载 Base URL**: `http://localhost:8000/download/` -- **鉴权方式**: - - **Client**: Bearer Token (JWT) - - **Admin**: 简单 Token (Header `x-admin-token` 或 Form `token`) - *开发阶段* - -## 2. 客户端接口 (Client) - -用于 Photoshop 插件端的交互。 - -### 2.1 登录 (Login) - -客户端登录,获取 Token、权限及过期时间。 - -- **URL**: `/client/login` -- **Method**: `POST` -- **Request Body**: - ```json - { - "username": "user1", - "password": "password123", - "device_id": "unique-device-id" - } - ``` -- **Response**: - ```json - { - "code": 200, - "data": { - "token": "eyJhbGciOiJIUzI1...", - "username": "user1", - "expire_date": "2025-12-31", - "permissions": ["batch_process", "export"] - }, - "message": "success" - } - ``` - -### 2.2 检查更新 (Check Update) - -根据用户所在组检查是否有新版本。 - -- **URL**: `/client/check_update` -- **Method**: `POST` -- **Request Body**: - ```json - { - "username": "user1" - } - ``` -- **Response**: - ```json - { - "code": 200, - "data": { - "version": "v1.0", - "download_url": "/download/plugin_v1.0.zip", - "force_update": false, - "is_expired": false - }, - "message": "success" - } - ``` - - `is_expired`: 若为 `true`,表示用户授权已过期,客户端应限制功能。 - - `download_url`: 拼接 Base URL 使用。 - ---- - -## 3. 管理端接口 (Admin) - -用于发布系统管理(CI/CD 或管理后台)。需在 Header 中携带 `x-admin-token: admin-secret-token` (默认开发Token)。 - -### 3.1 上传版本文件 (Upload Version) - -上传插件 ZIP 包到服务器。 - -- **URL**: `/admin/upload_version` -- **Method**: `POST` -- **Content-Type**: `multipart/form-data` -- **Form Data**: - - `file`: (Binary Zip File) - - `token`: "admin-secret-token" (作为 Form 字段兼容脚本) -- **Response**: - ```json - { - "code": 200, - "message": "File 'plugin_v1.0.zip' uploaded successfully", - "filename": "plugin_v1.0.zip" - } - ``` - -### 3.2 创建用户组 (Create Group) - -- **URL**: `/admin/groups` -- **Method**: `POST` -- **Request Body**: - ```json - { - "name": "Dev Group", - "current_version_file": "plugin_v1.0_beta.zip", - "comment": "开发测试组" - } - ``` -- **Response**: 返回创建的组对象。 - -### 3.3 更新用户组 (Update Group) - -用于切换组的版本。 - -- **URL**: `/admin/groups/{group_id}` -- **Method**: `PUT` -- **Request Body**: - ```json - { - "current_version_file": "plugin_v1.1_stable.zip" - } - ``` - -### 3.4 获取所有组 (List Groups) - -- **URL**: `/admin/groups` -- **Method**: `GET` -- **Response**: 组列表数组。 - -### 3.5 修改用户所属组 (Update User Group) - -- **URL**: `/admin/users/{user_id}/group` -- **Method**: `PUT` -- **Query Params**: - - `group_id`: 目标组 ID -- **Response**: - ```json - { - "code": 200, - "message": "User group updated" - } - ``` - ---- - -## 4. 数据库模型说明 - -### PluginGroup (用户组) -- `id`: ID -- `name`: 组名 (Unique) -- `current_version_file`: 当前关联的 ZIP 文件名 -- `comment`: 备注 - -### User (用户) -- `id`: ID -- `username`: 用户名 -- `group_id`: 所属组 ID (Foreign Key) -- `permissions`: 权限列表 (逗号分隔字符串) -- `expire_date`: 过期时间 diff --git a/temp_backup/Server_redundant/tempdocs/后端代码与工具说明.md b/temp_backup/Server_redundant/tempdocs/后端代码与工具说明.md deleted file mode 100644 index d3ad044..0000000 --- a/temp_backup/Server_redundant/tempdocs/后端代码与工具说明.md +++ /dev/null @@ -1,57 +0,0 @@ -# 后端代码与工具说明 (DesignerCEP) - -本文档详细说明了 `DesignerCEP` 项目的后端服务、测试脚本以及辅助管理工具。 - ---- - -## 1. 自动化发布 (`publish.py`) - -位于项目根目录 `d:\main\DesignerCEP\publish.py`。 - -- **类型**: Python 脚本。 -- **功能**: 实现 "一键发布" 流程。 - 1. **打包**: 自动将 `Designer` 目录压缩为 `.zip` 文件(自动排除 `.git`, `node_modules` 等无关文件)。 - 2. **上传**: 调用后端接口 `POST /api/v1/admin/upload_version` 将 ZIP 包上传到服务器。 - 3. **鉴权**: 使用 `token` 进行简单的管理员验证。 -- **使用方法**: - ```bash - python publish.py ./Designer --name "release_v1.0" - ``` - ---- - -## 2. 后端服务 (`Server/`) - -位于 `d:\main\DesignerCEP\Server\`,基于 Python FastAPI 框架。 - -### 核心文件 - -| 路径/文件名 | 作用 | -| :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`app/main.py`** | **程序入口**。初始化 FastAPI 应用,配置 CORS(允许跨域),挂载路由,初始化数据库。 | -| **`app/api/v1/client.py`** | **客户端接口**。处理插件端的请求:
- `/check_update`: 检查更新(含过期校验)。
- `/login`: 用户登录(返回 Token 和权限)。 | -| **`app/api/v1/admin.py`** | **管理接口**。供 AdminTool 使用:
- `/upload_version`: 接收发布的 ZIP 包。
- `/groups`: 管理用户组 (Stable/Dev)。
- `/users`: 管理用户及其所属组。 | -| **`app/models/`** | **数据库模型 (SQLAlchemy)**。定义 `User` 和 `PluginGroup` 表结构。 | -| **`tests/test_api.py`** | **集成测试**。包含完整的业务流程测试:
1. 创建用户组。
2. 上传 ZIP 包。
3. 将组指向该 ZIP。
4. 模拟客户端检查更新,验证返回版本是否正确。
5. 验证过期用户是否被拦截。 | - ---- - -## 3. 管理后台工具 (`AdminTool/`) - -位于 `d:\main\DesignerCEP\AdminTool\`,基于 PyQt5 的桌面应用程序。 - -- **功能**: 为不熟悉命令行的管理员提供图形化界面。 -- **主要能力**: - - **用户管理**: 增删改查用户,设置过期时间,分配用户组。 - - **版本管理**: 切换某个组当前使用的插件版本(实现灰度发布或回滚)。 - - **发布管理**: (可选) 集成文件上传功能。 - ---- - -## 总结 - -整个后端生态由这三部分组成闭环: - -1. **Server**: 提供数据存储和 API 服务。 -2. **publish.py**: 开发者用的“发货工具”。 -3. **AdminTool**: 管理员用的“控制台”。 diff --git a/temp_backup/Server_redundant/tempdocs/后端开发需求文档.md b/temp_backup/Server_redundant/tempdocs/后端开发需求文档.md deleted file mode 100644 index a512d99..0000000 --- a/temp_backup/Server_redundant/tempdocs/后端开发需求文档.md +++ /dev/null @@ -1,116 +0,0 @@ -# DesignerCEP 后端开发需求文档 - -请根据以下需求使用 Python (Flask/FastAPI) + MySQL 开发后端服务。 - -## 1. 核心需求概览 - -我们需要实现一个 **“灰度发布系统”**。 - -- **用户与权限**: 用户属于不同的“组” (Group),如 "Stable Group", "Dev Group"。 -- **版本控制**: 不同的组对应不同的插件版本 (ZIP 包)。 -- **客户端交互**: 客户端插件 (Shell) 登录时,根据用户所在的组,返回对应的 ZIP 包下载地址。 - ---- - -## 2. 数据库设计 (Database Schema) - -请创建以下两张核心表(基于 MySQL): - -### 2.1 用户组表 (`plugin_group`) - -用于管理不同的发布通道。 - -| 字段名 | 类型 | 描述 | 示例值 | -| :--------------------- | :------- | :----------------------- | :------------------ | -| `id` | INT (PK) | 组 ID | 1 | -| `name` | VARCHAR | 组名称 | "正式版用户组" | -| `current_version_file` | VARCHAR | **当前使用的版本文件名** | "plugin_v1.0.2.zip" | -| `comment` | TEXT | 备注 | "稳定版本通道" | - -### 2.2 用户表 (`user`) - -_需关联到组表_ - -| 字段名 | 类型 | 描述 | 示例值 | -| :------------ | :------- | :---------------------- | :------------------------- | -| `id` | INT (PK) | 用户 ID | 1001 | -| `username` | VARCHAR | 用户名 | "designer01" | -| `password` | VARCHAR | 密码 | "123456" | -| `group_id` | INT (FK) | **所属组 ID** | 1 (关联 `plugin_group.id`) | -| `permissions` | TEXT | **权限列表** (逗号分隔) | "batch_process,vip_export" | -| `expire_date` | DATETIME | **过期时间** | "2025-12-31 23:59:59" | - ---- - -## 3. API 接口规范 (API Specification) - -所有接口前缀建议为 `/api/v1`。 - -### 3.1 检查更新 (Client 接口) - -客户端插件启动时调用,查询自己应该下载哪个版本。 - -- **URL**: `POST /api/v1/client/check_update` -- **请求参数**: `{ "username": "..." }` -- **逻辑**: - 1. 检查用户是否过期 (`expire_date` < user.expire_date). 如果过期,返回 403 或特定状态码。 - 2. 根据 `username` 查询用户所在的 `group_id`。 - 3. 根据 `group_id` 查询 `plugin_group` 表,获取 `current_version_file`。 - 4. 拼接下载链接。 -- **返回示例**: - ```json - { - "code": 200, - "data": { - "version": "v1.0.2", - "download_url": "http://your-server.com/download/plugin_v1.0.2.zip", - "force_update": false, - "is_expired": false // 明确告知是否过期 - }, - "message": "success" - } - ``` - -### 3.2 登录验证 (Client 接口) - -- **URL**: `POST /api/v1/client/login` -- **请求参数**: `{ "username": "...", "password": "..." }` -- **逻辑**: 校验密码及过期状态。 -- **返回**: - ```json - { - "code": 200, - "data": { - "token": "...", - "username": "...", - "expire_date": "2025-12-31", - "permissions": ["batch_process", "vip_export"] // 返回权限数组 - } - } - ``` - -### 3.3 上传新版本 (Admin/CI 接口) - -用于发布脚本上传新的 ZIP 包。 - -- **请求参数**: `file` (multipart/form-data) -- **逻辑**: - 1. 校验管理员权限(可硬编码 Token 或密码)。 - 2. 将上传的文件保存到服务器的 `archives/` 目录。 - 3. 文件名通常包含版本号或时间戳,如 `plugin_v1.0.3_20251216.zip`。 - 4. (可选) 自动更新相关数据库记录。 - -### 3.4 文件下载 (Download) - -- **URL**: `GET /download/` -- **功能**: 提供静态文件下载服务(指向 `archives/` 目录)。 - ---- - -## 4. 后台管理功能 (Admin Tool 支持) - -后端需要提供基础的数据增删改查接口,以支持 PyQt 或 Web 管理后台: - -1. **用户管理**: 新增用户、修改用户所属组 (`group_id`)。 -2. **组管理**: 修改组指向的版本 (`current_version_file`)。 - - _场景_: 管理员发现 "v1.1-beta" 有 Bug,可以将 "Dev Group" 的 `current_version_file` 改回 "v1.0-stable",实现快速回滚。 diff --git a/temp_backup/Server_redundant/tempdocs/后端部署Shell指南.md b/temp_backup/Server_redundant/tempdocs/后端部署Shell指南.md deleted file mode 100644 index e8c238e..0000000 --- a/temp_backup/Server_redundant/tempdocs/后端部署Shell指南.md +++ /dev/null @@ -1,387 +0,0 @@ -# 后端部署 Shell 完整指南 - -## 🎯 目标 - -让服务器提供 Shell 登录页面,解决退出时无法跳转回登录页的问题。 - ---- - -## 📋 需要做的事情 - -### ✅ 后端代码已修改完成 - -`Server/app/main.py` 已经修改好了,包含: -1. 挂载 Shell 目录到 `/shell/` 路径 -2. 根路径重定向到 Shell 登录页 - ---- - -## 📦 需要上传的文件 - -### 1. 构建 Shell(在前端项目中执行) - -```bash -cd Designer -npm run build:shell -``` - -**生成位置:** `Designer/dist/` - -**生成内容:** -``` -Designer/dist/ -├── index.html ← Shell 入口文件 -├── assets/ -│ ├── index-xxx.js ← Shell 的 JS -│ ├── index-xxx.css ← Shell 的 CSS -│ └── ... -├── node_modules/ ← CEP 需要的依赖 -└── ... -``` - ---- - -### 2. 上传 Shell 到服务器 - -有两种方式: - -#### 方式 1:直接复制到服务器项目(推荐)⭐ - -```bash -# 在项目根目录执行 -# 把 Designer/dist/ 整个目录复制到服务器项目下 - -# Windows PowerShell -Copy-Item -Path "Designer\dist" -Destination "Server\Designer\dist" -Recurse -Force - -# Linux/Mac -cp -r Designer/dist Server/Designer/dist -``` - -最终服务器目录结构: -``` -Server/ -├── app/ -│ ├── main.py ← 已修改 -│ └── ... -├── Designer/ ← 新增! -│ └── dist/ ← Shell 文件 -│ ├── index.html -│ └── ... -└── ... -``` - -#### 方式 2:使用软链接(开发环境) - -```bash -# Windows(管理员权限) -cd Server -mklink /D Designer ..\Designer - -# Linux/Mac -cd Server -ln -s ../Designer Designer -``` - ---- - -## 🔧 后端代码说明 - -### main.py 的修改(已完成) - -```python -# 1. 导入 Path -from pathlib import Path - -# 2. 挂载 Shell 目录 -shell_dir = Path(__file__).parent.parent / "Designer" -if shell_dir.exists(): - app.mount("/shell", StaticFiles(directory=str(shell_dir), html=True), name="shell") - print(f"✓ Shell 已挂载: {shell_dir}") -else: - print(f"⚠️ Shell 目录不存在: {shell_dir}") - print(" 请先运行: cd Designer && npm run build:shell") - -# 3. 根路径重定向到 Shell -@app.get("/") -def read_root(): - from fastapi.responses import RedirectResponse - return RedirectResponse(url="/shell/index.html") -``` - ---- - -## 🚀 部署步骤 - -### Step 1: 构建 Shell - -```bash -# 在前端项目目录 -cd D:\main\DesignerCEP\Designer -npm run build:shell -``` - -**检查输出:** -- ✅ `dist/index.html` 文件存在 -- ✅ `dist/assets/` 目录存在 - ---- - -### Step 2: 复制 Shell 到服务器 - -**方法 A:在本地复制(推荐)** - -```bash -# 在项目根目录 -cd D:\main\DesignerCEP - -# 创建目标目录 -mkdir Server\Designer -Force - -# 复制文件 -Copy-Item -Path "Designer\dist" -Destination "Server\Designer\dist" -Recurse -Force -``` - -**方法 B:在服务器上从 Git 拉取(如果用了 Git)** - -```bash -# 在服务器上 -cd /path/to/DesignerCEP -git pull -cd Designer -npm run build:shell -``` - ---- - -### Step 3: 验证文件结构 - -```bash -cd Server -dir Designer\dist\index.html # Windows -# 或 -ls Designer/dist/index.html # Linux -``` - -**应该看到:** -``` -D:\main\DesignerCEP\Server\Designer\dist\index.html -``` - ---- - -### Step 4: 重启后端服务器 - -```bash -cd Server -python -m uvicorn app.main:app --reload -``` - -**启动日志应该显示:** -``` -✓ Shell 已挂载: D:\main\DesignerCEP\Server\Designer\dist -INFO: Uvicorn running on http://127.0.0.1:8000 -``` - -如果显示: -``` -⚠️ Shell 目录不存在: ... - 请先运行: cd Designer && npm run build:shell -``` - -说明文件没有正确复制,回到 Step 2。 - ---- - -### Step 5: 测试访问 - -#### 测试 1:根路径重定向 - -```bash -# 在浏览器访问 -http://127.0.0.1:8000/ -``` - -**预期:** 自动跳转到 `http://127.0.0.1:8000/shell/index.html` 并显示登录页 - -#### 测试 2:直接访问 Shell - -```bash -http://127.0.0.1:8000/shell/ -``` - -**预期:** 显示登录页面 - -#### 测试 3:登录并退出 - -1. 在 Shell 登录页输入账号密码 -2. 登录成功 → 跳转到 Core -3. 在 Core 点击退出 -4. **预期:** 跳转回 Shell 登录页 ✅ - ---- - -## 📁 完整目录结构 - -``` -D:\main\DesignerCEP\ -├── Designer/ -│ ├── src/ -│ │ ├── launcher/ ← Shell 源代码 -│ │ │ ├── view/ -│ │ │ │ └── Login.vue ← 登录页面源码 -│ │ │ └── utils/ -│ │ │ └── updater.ts -│ │ └── view/ -│ │ └── Home.vue ← Core 页面 -│ │ -│ └── dist/ ← 构建后的 Shell -│ ├── index.html ← 需要复制到服务器 -│ └── assets/ -│ -└── Server/ - ├── app/ - │ └── main.py ← 已修改 - │ - ├── Designer/ ← 新增目录 - │ └── dist/ ← 从 Designer/dist/ 复制过来 - │ ├── index.html ← Shell 登录页 - │ └── assets/ - │ - └── archives/ ← Core 下载包 - └── core-v1.2.4.zip -``` - ---- - -## 🔍 访问路径说明 - -| URL | 作用 | 文件位置 | -|-----|------|---------| -| `http://127.0.0.1:8000/` | 根路径,重定向到 Shell | - | -| `http://127.0.0.1:8000/shell/` | Shell 登录页 | `Server/Designer/dist/index.html` | -| `http://127.0.0.1:8000/core/v1.2.4/` | Core 业务页 | `C:/Users/.../DesignerCache/v1.2.4/` | -| `http://127.0.0.1:8000/download/` | 下载 Core 包 | `Server/archives/` | - ---- - -## ⚠️ 常见问题 - -### 问题 1:启动后显示 "Shell 目录不存在" - -**原因:** `Server/Designer/dist/` 目录不存在 - -**解决:** -```bash -# 检查目录 -cd D:\main\DesignerCEP\Server -dir Designer\dist - -# 如果不存在,重新复制 -cd .. -Copy-Item -Path "Designer\dist" -Destination "Server\Designer\dist" -Recurse -Force -``` - ---- - -### 问题 2:访问 `/shell/` 显示 404 - -**原因:** 文件没有正确挂载 - -**解决:** -1. 检查 `Server/Designer/dist/index.html` 是否存在 -2. 检查后端启动日志是否显示 "✓ Shell 已挂载" -3. 重启后端服务器 - ---- - -### 问题 3:访问 `/` 不重定向 - -**原因:** `main.py` 中的重定向代码没有生效 - -**解决:** -1. 确认 `main.py` 中有重定向代码: -```python -@app.get("/") -def read_root(): - from fastapi.responses import RedirectResponse - return RedirectResponse(url="/shell/index.html") -``` -2. 重启后端服务器 - ---- - -### 问题 4:Shell 页面加载失败 - -**原因:** 资源文件路径问题 - -**解决:** -1. 检查 `dist/index.html` 中的资源引用是否正确 -2. 确认 `assets/` 目录完整复制 -3. 清除浏览器缓存后重试 - ---- - -## 🔄 更新流程 - -当 Shell 代码有更新时: - -```bash -# 1. 重新构建 Shell -cd Designer -npm run build:shell - -# 2. 复制到服务器 -cd .. -Copy-Item -Path "Designer\dist" -Destination "Server\Designer\dist" -Recurse -Force - -# 3. 重启后端(如果使用 --reload 则自动重启) -# 或手动重启 -``` - ---- - -## ✅ 部署检查清单 - -部署完成后,检查以下项: - -- [ ] `Server/Designer/dist/index.html` 文件存在 -- [ ] 后端启动日志显示 "✓ Shell 已挂载" -- [ ] 访问 `http://127.0.0.1:8000/` 自动跳转到 Shell -- [ ] 访问 `http://127.0.0.1:8000/shell/` 显示登录页 -- [ ] Shell 页面可以正常登录 -- [ ] 登录后跳转到 Core -- [ ] Core 退出后跳转回 Shell 登录页 ✅ - ---- - -## 📝 快速命令汇总 - -```bash -# 1. 构建 Shell -cd D:\main\DesignerCEP\Designer -npm run build:shell - -# 2. 复制到服务器 -cd .. -Copy-Item -Path "Designer\dist" -Destination "Server\Designer\dist" -Recurse -Force - -# 3. 重启后端 -cd Server -python -m uvicorn app.main:app --reload - -# 4. 测试访问 -# 浏览器打开: http://127.0.0.1:8000/ -``` - ---- - -## 🎉 完成 - -部署完成后: -- ✅ 用户登录后使用 Core -- ✅ 退出时自动跳转回 Shell 登录页 -- ✅ 不再显示 `{"message":"Welcome to DesignerCEP Backend"}` - -**现在退出流程完美了!** 🎊 - diff --git a/temp_backup/Server_redundant/tempdocs/安全方案对比.md b/temp_backup/Server_redundant/tempdocs/安全方案对比.md deleted file mode 100644 index 4124313..0000000 --- a/temp_backup/Server_redundant/tempdocs/安全方案对比.md +++ /dev/null @@ -1,150 +0,0 @@ -# 安全方案对比 - -## 方案 A:前端内联 JSX(当前方案) - -### 优点 -- ✅ 离线可用 -- ✅ 响应快速 -- ✅ 开发简单 - -### 缺点 -- ❌ **代码完全暴露** -- ❌ **可以被逆向破解** -- ❌ **用户可以绕过验证** -- ❌ **核心算法可被复制** - -### 安全性 -``` -★☆☆☆☆ (1/5) -``` - -### 攻击方式 -```javascript -// 攻击者可以直接修改前端代码: -// 1. 删除 verifyLicense() 调用 -// 2. 直接调用 Layer.createLayer() -// 3. 复制 JSX 代码到自己的插件 -``` - ---- - -## 方案 B:服务器端 JSX(推荐) - -### 优点 -- ✅ **核心代码在服务器,无法被窃取** -- ✅ **强制在线验证** -- ✅ **可以随时更新逻辑** -- ✅ **支持按功能付费** -- ✅ **完整的用户行为追踪** - -### 缺点 -- ❌ 需要联网 -- ❌ 有延迟(通常 <100ms) -- ❌ 服务器成本 - -### 安全性 -``` -★★★★★ (5/5) -``` - -### 工作流程 -``` -客户端 服务器 -------- -------- -1. 点击按钮 → -2. 发送请求 → 验证许可证 - 验证设备绑定 - 检查用户等级 - 生成 JSX 代码 -3. 接收代码 ← 返回 JSX -4. 执行代码 -5. 显示结果 -``` - -### 破解难度 -- 前端只有 API 调用,没有核心逻辑 -- 即使破解前端,也无法获取服务器端的 JSX 模板 -- 服务器可以检测异常调用并封禁账号 - ---- - -## 方案 C:混合方案(平衡) - -### 策略 -- **基础功能** → 前端内联(离线可用) -- **核心功能** → 服务器端(保护算法) -- **高级功能** → 服务器端 + 付费验证 - -### 示例 -```typescript -// 基础功能:前端内联(免费,离线) -await Layer.createLayer('新图层'); - -// 核心功能:服务器端(付费,在线) -await ServerJSX.createLayerWithStyle('设计图层', 80, '#FF0000'); - -// 高级功能:服务器端(高级会员专属) -await ServerJSX.aiAutoDesign(params); -``` - -### 安全性 -``` -★★★☆☆ (3/5) -``` - ---- - -## 🎯 推荐配置 - -### 商业产品(强保护) -``` -✅ 使用方案 B(服务器端 JSX) -✅ 所有核心功能服务器化 -✅ 前端代码混淆 -✅ 设备指纹 + 硬件绑定 -✅ 许可证在线验证 -✅ 操作日志 + 异常检测 -``` - -### 免费/开源产品(轻保护) -``` -✅ 使用方案 A(前端内联 JSX) -✅ 基础代码混淆 -✅ 可选的在线功能 -``` - ---- - -## 💡 实现建议 - -### 1. 短期(快速上线) -使用方案 A + 基础保护: -- 代码混淆 -- 许可证验证 -- 行为记录 - -### 2. 中期(商业化) -迁移到方案 C: -- 保留基础功能在前端 -- 核心算法移到服务器 -- 实现付费功能 - -### 3. 长期(高价值产品) -完全方案 B: -- 所有核心功能服务器化 -- AI 功能集成 -- 多端同步 -- 企业级管理 - ---- - -## ⚠️ 重要提醒 - -**前端代码永远可以被破解!** - -真正的保护只有两种: -1. **服务器端执行** - 代码不在客户端 -2. **硬件加密** - 使用加密狗(CEP 插件不支持) - -其他所有前端保护(混淆、加密)都只是**增加破解难度**,不能完全防止。 - diff --git a/temp_backup/Server_redundant/tempdocs/完成报告.md b/temp_backup/Server_redundant/tempdocs/完成报告.md deleted file mode 100644 index 336a238..0000000 --- a/temp_backup/Server_redundant/tempdocs/完成报告.md +++ /dev/null @@ -1,364 +0,0 @@ -# 🎉 DesignerCEP 积分VIP签到系统 - 完成报告 - -## ✅ 已完成工作 - -### 1. 后端开发 (100% 完成) - -#### 📁 新增文件清单 -1. **`Server/migrations/001_add_points_vip_checkin.sql`** (145行) - - 完整的数据库迁移脚本 - - 7个新表结构 - - 初始配置数据 - -2. **`Server/app/api/v1/admin_config.py`** (314行) - - 管理员配置接口 - - 功能配置CRUD - - VIP配置管理 - - 签到配置管理 - -3. **`Server/app/api/v1/feature.py`** (134行) - - 核心业务逻辑 - - 动态扣费算法(SVIP/VIP/普通) - - VIP配额管理 - - 使用日志记录 - -4. **`Server/app/api/v1/checkin.py`** (212行) - - 每日签到功能 - - 连续天数计算 - - VIP倍数加成 - - 签到日历和历史 - -5. **`Server/app/api/v1/user_profile.py`** (118行) - - 用户资料管理 - - 积分历史查询 - - 分页支持 - -6. **`Server/app/api/v1/stats.py`** (106行) - - 今日统计 - - 功能使用排行 - - 积分趋势分析 - -7. **`Server/app/core/database.py`** (17行) - - 数据库连接管理 - -#### 🔧 修改文件 -- **`Server/app/main.py`**: 注册5个新路由 - -#### 📊 API接口统计 -- **管理员配置**: 10个接口 -- **功能使用**: 1个接口(核心) -- **签到**: 4个接口 -- **用户资料**: 3个接口 -- **统计**: 3个接口 -- **总计**: 21个新接口 - ---- - -### 2. 前端开发 (100% 完成) - -#### 📁 新增文件清单 -1. **`Designer/src/view/HomePage.vue`** (295行) - - 网格导航首页 - - 欢迎区和统计卡片 - - 功能网格展示 - - 快捷入口 - -2. **`Designer/src/view/Profile.vue`** (366行) - - 个人中心 - - 头像和基本信息 - - 统计数据展示 - - 编辑资料功能 - - 积分历史(带筛选和分页) - -3. **`Designer/src/view/CheckIn.vue`** (433行) - - 签到主界面 - - 奖励规则展示 - - 签到日历 - - 签到历史 - -#### 🔧 修改文件 -- **`Designer/src/router/index.ts`**: 添加3个新路由,调整默认重定向 - -#### 🎨 UI特性 -- 响应式布局 -- 流畅动画过渡 -- Hover交互效果 -- 统一配色风格 -- 符合 Arco Design 规范 - ---- - -### 3. 文档编写 (100% 完成) - -#### 📖 文档清单 -1. **`部署文档_积分VIP签到系统.md`** - - 完整部署步骤 - - 核心业务逻辑说明 - - 配置管理指南 - - 测试清单 - - 注意事项 - -2. **`AdminTool配置管理开发文档.md`** - - 给Python开发者的指南 - - 两种技术方案(qfluentwidgets / 原生PyQt5) - - 完整代码示例 - - API接口参考 - - 开发检查清单 - ---- - -### 4. 代码清理 (100% 完成) - -#### 🗑️ 已删除测试文件 -- `tempdemo/e2e_test.py` -- `tempdemo/test_client_login.py` -- `tempdemo/run.py` - ---- - -## 📊 代码统计 - -| 类型 | 文件数 | 代码行数 | 说明 | -|------|--------|----------|------| -| **后端API** | 6个文件 | ~900行 | Python + FastAPI | -| **前端页面** | 3个文件 | ~1100行 | Vue3 + TypeScript + Less | -| **数据库** | 1个文件 | 145行 | SQL迁移脚本 | -| **文档** | 2个文件 | 600+行 | Markdown文档 | -| **总计** | 12个文件 | ~2700行 | 高质量代码 | - ---- - -## 🎯 功能清单 - -### 用户端功能 ✅ -- [x] 首页网格导航 -- [x] 功能卡片展示 -- [x] 点击使用功能 -- [x] 积分/VIP状态展示 -- [x] 每日签到 -- [x] 签到日历 -- [x] 签到历史 -- [x] 个人中心 -- [x] 编辑资料 -- [x] 积分历史查询 - -### 后端功能 ✅ -- [x] 功能配置管理 -- [x] VIP配置管理 -- [x] 签到配置管理 -- [x] 动态扣费逻辑 -- [x] VIP配额管理 -- [x] 积分系统 -- [x] 签到系统 -- [x] 使用日志 -- [x] 数据统计 - -### 配置化 ✅ -- [x] 功能价格可配置 -- [x] VIP权益可配置 -- [x] 签到奖励可配置 -- [x] 功能开关可配置 -- [x] 实时生效无需重启 - ---- - -## 🔥 核心亮点 - -### 1. 完全配置化 ⭐⭐⭐ -- **零硬编码**: 所有业务规则从数据库读取 -- **灵活调整**: 价格、奖励、配额随时修改 -- **即时生效**: 无需重启服务 -- **分销友好**: 支持为不同分销商定制配置 - -### 2. 业务逻辑严谨 ⭐⭐⭐ -- **三级用户体系**: 普通/VIP/SVIP -- **智能扣费**: 自动判断免费/配额/积分 -- **连续签到**: 中断归零,持续激励 -- **VIP加成**: 签到积分倍数奖励 -- **配额重置**: 每日自动重置VIP配额 - -### 3. 代码质量高 ⭐⭐⭐ -- **符合规范**: 严格遵守开发准则 -- **类型安全**: TypeScript + Pydantic -- **日志完善**: 统一logger管理 -- **注释清晰**: 关键逻辑都有说明 -- **可维护性强**: 模块化设计 - -### 4. 用户体验好 ⭐⭐⭐ -- **界面精美**: 现代化设计风格 -- **交互流畅**: 动画过渡自然 -- **信息清晰**: 数据展示直观 -- **操作便捷**: 快捷入口齐全 -- **反馈及时**: 消息提示完善 - ---- - -## 📝 开发准则遵守情况 - -### ✅ 完全遵守 -- [x] Vue 3 Composition API + ` -``` - ---- - -#### Step 5: 部署新功能 - -```bash -# 1. 构建 Core -cd Designer -npm run build:core - -# 2. 发布新版本(使用自动部署脚本) -cd .. -python auto_deploy_core.py - -# 3. 用户登录后会自动下载新版本 -``` - ---- - -## 🔐 API Key 管理 - -### 添加新的 API Key - -**文件:** `Server/app/core/api_keys.py` - -```python -VALID_KEYS: Dict[str, dict] = { - "demo_key_123": { - "name": "测试密钥", - "permissions": ["calculate", "filter"], # 添加权限 - "rate_limit": 100 - }, - "customer_abc_456": { # 新客户 - "name": "客户 A", - "permissions": ["calculate"], - "rate_limit": 200 - } -} -``` - -### 权限检查 - -```python -@router.post("/calculate-filter") -async def calculate_filter(request, x_api_key: Optional[str] = Header(None)): - # 验证 Key - if not validate_api_key(x_api_key): - raise HTTPException(403, "无效的 API Key") - - # 检查权限 - if not APIKeyManager.check_permission(x_api_key, "filter"): - raise HTTPException(403, "没有滤镜功能权限") - - # 继续处理... -``` - ---- - -## 📊 日志监控 - -所有请求都会自动记录: - -``` -============================================================ -📥 收到滤镜计算请求 - 图层ID: Layer_123 - API Key: demo_key_123 -============================================================ -✅ API Key 验证通过 | 名称: 测试密钥 | 权限: ['calculate', 'filter'] -🔒 开始执行核心算法... -✅ 计算完成: blur=2.3, sharpen=0.7 -============================================================ -``` - ---- - -## 🚀 扩展方向 - -### 1. AI 功能 -```python -# Server 端 -@router.post("/ai-enhance") -async def ai_enhance(image: str, x_api_key: str): - # 调用 TensorFlow/PyTorch 模型 - result = ai_model.predict(image) - return result -``` - -### 2. 批量处理 -```python -@router.post("/batch-process") -async def batch_process(layers: List[str], x_api_key: str): - results = [] - for layer_id in layers: - result = process_layer(layer_id) - results.append(result) - return results -``` - -### 3. 数据分析 -```python -@router.post("/analyze-design") -async def analyze_design(doc_info: dict, x_api_key: str): - # 分析设计质量、配色方案等 - analysis = analyze_composition(doc_info) - return analysis -``` - -### 4. 实时协作 -```python -@router.websocket("/ws/collaborate") -async def collaborate(websocket: WebSocket, x_api_key: str): - # WebSocket 实时同步 - await websocket.accept() - # 多用户协作编辑 -``` - ---- - -## 🛡️ 安全最佳实践 - -### ✅ 已实现 -- API Key 鉴权 -- 输入验证 -- 详细日志 -- 核心算法保护 - -### ⚠️ 生产环境建议 -- 启用 HTTPS -- 添加限流(Rate Limiting) -- IP 白名单 -- 定期更换 API Key -- 数据库存储 Key(而非配置文件) - ---- - -## 📚 开发流程总结 - -```mermaid -graph TD - A[设计新功能] --> B[后端实现核心算法] - B --> C[前端调用 API] - C --> D[UI 界面集成] - D --> E[测试] - E --> F[构建 Core] - F --> G[自动部署] - G --> H[用户自动更新] -``` - ---- - -## 🎯 框架优势 - -| 特性 | 传统方案 | 本框架 | -|------|---------|--------| -| 核心算法保护 | ❌ 暴露在前端 | ✅ 服务器端执行 | -| 动态更新 | ❌ 需重装插件 | ✅ 自动下载更新 | -| 安全鉴权 | ❌ 无验证 | ✅ API Key + 日志 | -| 可扩展性 | ⚠️ 受限 | ✅ 易于添加功能 | -| 开发效率 | ⚠️ 中等 | ✅ 模板化开发 | - ---- - -## 🎉 总结 - -这个框架提供了: -1. **完整的三层架构**(Shell → Core → Server) -2. **安全的算法保护**(服务器端计算) -3. **灵活的更新机制**(动态加载 Core) -4. **标准的开发模式**(模板化添加功能) -5. **完善的监控日志**(追踪所有请求) - -**适用场景:** -- Adobe CEP 插件开发 -- 需要保护核心算法的应用 -- 需要频繁更新的软件 -- 需要鉴权和监控的服务 - ---- - -**现在你可以基于这个框架快速开发新功能了!** 🚀 - diff --git a/temp_backup/Server_redundant/tempdocs/混合架构快速开发模板.md b/temp_backup/Server_redundant/tempdocs/混合架构快速开发模板.md deleted file mode 100644 index 597ed3c..0000000 --- a/temp_backup/Server_redundant/tempdocs/混合架构快速开发模板.md +++ /dev/null @@ -1,355 +0,0 @@ -# 混合架构快速开发模板 - -## 🚀 5 分钟添加新功能 - -### 模板代码 - -复制下面的模板,替换 `YOUR_FEATURE` 为你的功能名称。 - ---- - -## 📝 Step 1: 后端 API(3 层) - -**文件:** `Server/app/api/v1/jsx_demo.py` - -```python -# ==================== 请求/响应模型 ==================== -class YourFeatureRequest(BaseModel): - """你的功能请求""" - param1: str - param2: int - -class YourFeatureResult(BaseModel): - """你的功能结果""" - success: bool - result_data: dict - message: str - -# ==================== API 端点 ==================== -@router.post("/your-feature", response_model=YourFeatureResult) -async def your_feature_endpoint( - request: YourFeatureRequest, - x_api_key: Optional[str] = Header(None) -): - """ - 🔒 服务器端核心计算 - 客户端只能拿到结果,看不到算法 - """ - - # 📝 日志:记录请求 - logger.info("="*60) - logger.info("📥 收到请求: YOUR_FEATURE") - logger.info(f" 参数1: {request.param1}") - logger.info(f" 参数2: {request.param2}") - logger.info(f" API Key: {x_api_key}") - logger.info("="*60) - - # 🔐 API Key 验证 - if not validate_api_key(x_api_key): - logger.warning(f"❌ API Key 验证失败") - raise HTTPException(status_code=403, detail="无效的 API Key") - - key_info = get_key_info(x_api_key) - logger.info(f"✅ API Key 验证通过 | 名称: {key_info['name']}") - - try: - # 🛡️ 输入验证 - logger.info("🛡️ 验证输入参数...") - if not request.param1 or request.param2 < 0: - logger.warning("❌ 参数验证失败") - return YourFeatureResult( - success=False, - result_data={}, - message="参数无效" - ) - logger.info("✅ 参数验证通过") - - # 🔒 核心算法(客户端看不到) - logger.info("🔒 开始执行核心算法...") - - # ===== 在这里写你的核心逻辑 ===== - result = { - "output1": f"处理结果: {request.param1}", - "output2": request.param2 * 2 - } - # ================================ - - logger.info(f"✅ 计算完成: {result}") - - # 📤 返回结果 - logger.info("="*60) - return YourFeatureResult( - success=True, - result_data=result, - message="处理成功" - ) - - except Exception as e: - logger.error(f"❌ 处理失败: {str(e)}") - return YourFeatureResult( - success=False, - result_data={}, - message=f"处理失败: {str(e)}" - ) -``` - ---- - -## 📝 Step 2: 前端 API(2 层) - -**文件:** `Designer/src/api/jsxApi/inline/your-feature.ts` - -```typescript -/** - * YOUR_FEATURE 功能 - * 混合方案:本地执行 + 服务器计算 - */ - -import { evalInlineJSX, JSXResponse } from './utils'; -import { config } from '@/config'; - -export async function yourFeatureFunction( - param1: string, - param2: number -): Promise { - try { - // 1. 💻 【可选】本地获取 PS 数据 - const getDataJsx = ` - try { - if (!$.global.JSXUtils.hasDocument()) { - return $.global.JSXUtils.stringify({ error: '没有打开的文档' }); - } - - var doc = $.global.JSXUtils.getDocument(); - - // 获取你需要的数据 - var layerName = doc.activeLayer ? doc.activeLayer.name : ''; - - return $.global.JSXUtils.stringify({ - success: true, - layerName: layerName - }); - } catch (error) { - return $.global.JSXUtils.stringify({ error: error.toString() }); - } - `; - - const psData = await evalInlineJSX(getDataJsx); - - if (psData.error) { - return psData; - } - - // 2. 🌐 发送到服务器计算(核心算法) - const response = await fetch(`${config.apiBaseUrl}/jsx_demo/your-feature`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': 'demo_key_123' // 🔐 API Key - }, - body: JSON.stringify({ - param1: param1, - param2: param2 - }) - }); - - if (!response.ok) { - return { error: '服务器错误' }; - } - - const serverResult = await response.json(); - - if (!serverResult.success) { - return { error: serverResult.message }; - } - - // 3. 💻 【可选】使用服务器结果执行 PS 操作 - const { output1, output2 } = serverResult.result_data; - - const applyJsx = ` - try { - var doc = $.global.JSXUtils.getDocument(); - - // 使用服务器计算的结果 - // 示例:创建文本图层显示结果 - var textLayer = doc.artLayers.add(); - textLayer.kind = LayerKind.TEXT; - textLayer.name = "${output1}"; - - return $.global.JSXUtils.stringify({ - success: true, - message: '操作完成' - }); - } catch (error) { - return $.global.JSXUtils.stringify({ error: error.toString() }); - } - `; - - return evalInlineJSX(applyJsx); - - } catch (error) { - return { error: String(error) }; - } -} -``` - ---- - -## 📝 Step 3: UI 界面(2 层) - -**文件:** `Designer/src/view/Home.vue` - -```vue - - - -``` - ---- - -## 🔄 开发流程 - -### 本地测试 -```bash -# Terminal 1: 启动后端 -cd Server -python -m uvicorn app.main:app --reload - -# Terminal 2: 启动前端 -cd Designer -npm run dev -``` - -### 发布新版本 -```bash -# 自动构建、打包、发布 -python auto_deploy_core.py -``` - ---- - -## 📋 检查清单 - -开发新功能时,确保: - -- [ ] 后端添加了 API Key 验证 -- [ ] 后端添加了详细日志 -- [ ] 后端添加了输入验证 -- [ ] 前端使用了正确的 API Key -- [ ] 前端添加了错误处理 -- [ ] UI 有加载提示和错误提示 -- [ ] 测试了成功和失败的情况 -- [ ] 更新了版本号 - ---- - -## 🎯 三种常见模式 - -### 模式 1:纯服务器计算 -``` -前端输入 → 服务器计算 → 前端显示结果 -(不涉及 PS 操作) -``` - -### 模式 2:服务器计算 + PS 应用 -``` -前端获取 PS 数据 → 服务器计算 → 前端应用到 PS -(当前示例) -``` - -### 模式 3:本地执行 + 服务器验证 -``` -前端执行操作 → 服务器验证权限 → 前端继续 -(需要权限控制的操作) -``` - ---- - -## 💡 快速参考 - -### 后端日志模板 -```python -logger.info("="*60) -logger.info("📥 收到请求") -logger.info("✅ 验证通过") -logger.info("🔒 开始计算") -logger.info("✅ 计算完成") -logger.info("="*60) -``` - -### 前端错误处理模板 -```typescript -try { - Message.loading('处理中...'); - const res = await yourFunction(); - if (res?.success) { - Message.success(res.message); - } else { - Message.error(res?.error || '失败'); - } -} catch (e: any) { - Message.error('调用失败: ' + e.message); -} -``` - -### JSX 模板 -```typescript -const jsx = ` - try { - if (!$.global.JSXUtils.hasDocument()) { - return $.global.JSXUtils.stringify({ error: '没有打开的文档' }); - } - - var doc = $.global.JSXUtils.getDocument(); - - // 你的 PS 操作代码 - - return $.global.JSXUtils.stringify({ - success: true, - message: '成功' - }); - } catch (error) { - return $.global.JSXUtils.stringify({ error: error.toString() }); - } -`; - -return evalInlineJSX(jsx); -``` - ---- - -## 🎉 完成! - -现在你可以: -1. 复制模板代码 -2. 替换功能名称 -3. 填写核心逻辑 -4. 测试 -5. 发布 - -**预计开发时间:5-15 分钟/功能** ⚡ - diff --git a/temp_backup/Server_redundant/tempdocs/生产环境部署实操指南.md b/temp_backup/Server_redundant/tempdocs/生产环境部署实操指南.md deleted file mode 100644 index 5d62343..0000000 --- a/temp_backup/Server_redundant/tempdocs/生产环境部署实操指南.md +++ /dev/null @@ -1,353 +0,0 @@ -# 🚀 DesignerCEP 生产环境部署实操指南 - -本文档为您提供从零开始部署 DesignerCEP 到 Linux 服务器(Ubuntu/Debian/CentOS)的完整操作步骤。 - ---- - -## 📋 1. 准备工作 - -### 1.1 服务器与域名 -- **服务器**: 建议 Ubuntu 20.04+ (已购买) -- **域名**: `your-domain.com` (已购买) -- **DNS 解析**: 请将域名 A 记录解析到服务器公网 IP。 - -### 1.2 本地文件准备 -在您的电脑上创建一个 `deployment` 文件夹,用于存放准备上传的文件。 - -#### A. 后端代码 -复制 `Server` 目录下的以下文件/文件夹到 `deployment/Server`: -- `app/` (文件夹) -- `requirements.txt` -- `.env` (稍后修改) -- `main.py` (如果有入口文件在根目录,或者确认入口是 `app.main`) - -#### B. 前端构建 -1. **配置生产环境地址**: - 修改 `Designer/.env.production`: - ```env - VITE_API_SERVER=https://your-domain.com - ``` - -2. **构建项目**: - 在 `Designer` 目录下运行: - ```bash - npm run build - ``` - 这将生成 `Designer/dist` 目录,包含 `Shell` 和 `Designer` (Core) 两个文件夹。 - -3. **打包 Shell**: - 将 `Designer/dist/Shell` 文件夹压缩为 `shell-1.0.1.zip` (版本号请参考 package.json)。 - -#### C. 最终上传清单 -您的 `deployment` 文件夹结构应如下: -``` -deployment/ -├── Server/ # 后端代码 -│ ├── app/ -│ └── requirements.txt -├── Shell/ # 前端 Shell (来自 dist/Shell) -├── Core/ # 前端 Core (来自 dist/Designer) -└── shell-1.0.1.zip # 压缩包 (来自 dist/Shell) -``` - ---- - -## 🖥️ 2. 服务器环境安装 - -使用 SSH 登录您的服务器: -```bash -ssh root@your-server-ip -``` - -### 2.1 安装基础软件 -```bash -# Ubuntu/Debian -sudo apt update -sudo apt install -y python3 python3-pip python3-venv unzip curl - -# 安装 Caddy (Web 服务器) -sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list -sudo apt update -sudo apt install caddy -``` - ---- - -## 📂 3. 上传与部署文件 - -### 3.1 创建目录结构 -```bash -# 创建应用根目录 -sudo mkdir -p /var/www/DesignerCEP/Server - -# 创建静态文件目录 -sudo mkdir -p /var/www/DesignerCEP/Server/static/shell -sudo mkdir -p /var/www/DesignerCEP/Server/static/core/1.0.1 -sudo mkdir -p /var/www/DesignerCEP/Server/static/downloads - -# 设置权限 -sudo chown -R www-data:www-data /var/www/DesignerCEP -sudo chmod -R 755 /var/www/DesignerCEP -``` - -### 3.2 上传文件 (在本地执行) -打开新的终端窗口(本地),执行上传命令: - -```bash -# 假设您在 deployment 目录的上级目录 -cd path/to/deployment - -# 1. 上传后端 -scp -r Server/* root@your-server-ip:/var/www/DesignerCEP/Server/ - -# 2. 上传 Shell 静态文件 -scp -r Shell/* root@your-server-ip:/var/www/DesignerCEP/Server/static/shell/ - -# 3. 上传 Core 静态文件 (注意:这里是上传特定版本) -# 如果您有多个版本,请重复此步骤,例如 1.0.0, 1.0.1 等 -scp -r Core/* root@your-server-ip:/var/www/DesignerCEP/Server/static/core/1.0.1/ - -# 4. 上传 Shell 压缩包 -scp shell-1.0.1.zip root@your-server-ip:/var/www/DesignerCEP/Server/static/downloads/ - -# 5. 上传历史版本 (如果您有 archives 文件夹) -# 假设您本地有一个 archives 文件夹包含 core-v1.0.0.zip 等 -# scp -r archives/* root@your-server-ip:/var/www/DesignerCEP/Server/archives/ -# 并在服务器上解压到 /var/www/DesignerCEP/Server/static/core/ -``` - -### 3.3 批量上传历史版本(可选) -如果您需要一次性部署多个历史版本,可以按照以下步骤操作: - -1. **在本地准备版本**: - 将所有需要部署的 `core-vX.X.X.zip` 文件放在一个文件夹中,例如 `all_versions`。 - -2. **上传到服务器**: - ```bash - scp -r all_versions/*.zip root@your-server-ip:/var/www/DesignerCEP/Server/archives/ - ``` - -3. **在服务器上解压**: - 登录服务器,运行以下命令批量解压: - ```bash - cd /var/www/DesignerCEP/Server/archives - # 安装 unzip (如果未安装) - sudo apt install unzip - - # 遍历解压所有 core zip 文件到 static/core - for f in core-v*.zip; do - # 提取版本号 (假设文件名格式为 core-v1.0.0.zip) - version=$(echo "$f" | sed 's/core-v//' | sed 's/.zip//') - - echo "Deploying version $version..." - sudo mkdir -p "/var/www/DesignerCEP/Server/static/core/$version" - sudo unzip -o "$f" -d "/var/www/DesignerCEP/Server/static/core/$version" - done - - # 修正权限 - sudo chown -R www-data:www-data /var/www/DesignerCEP/Server/static/core - ``` - -### 3.4 修正权限 (服务器端) -```bash -sudo chown -R www-data:www-data /var/www/DesignerCEP -``` - ---- - -## ⚙️ 4. 后端服务配置 - -### 4.1 安装 Python 依赖 -```bash -cd /var/www/DesignerCEP/Server - -# 创建虚拟环境 -python3 -m venv venv -source venv/bin/activate - -# 安装依赖 -pip install -r requirements.txt -pip install gunicorn uvicorn[standard] -``` - -### 4.2 配置环境变量 -创建 `.env` 文件: -```bash -nano .env -``` -粘贴以下内容(**已为您预填好域名**): -```env -ENV=production -PROJECT_NAME=DesignerCEP -API_V1_STR=/api/v1 -SECRET_KEY=generate-a-secure-random-key-here -ACCESS_TOKEN_EXPIRE_MINUTES=43200 -DATABASE_URL=sqlite:///./designercep.db - -# 关键:允许 CORS 的域名 -ALLOWED_ORIGINS=https://aidg168.uk,https://www.aidg168.uk,https://backend.aidg168.uk - -# 邮箱配置 (可选,如果您需要发送邮件) -SMTP_HOST=smtp.gmail.com -SMTP_PORT=587 -SMTP_USER=your-email@gmail.com -SMTP_PASSWORD=your-app-password -EMAILS_FROM_EMAIL=your-email@gmail.com -EMAILS_FROM_NAME=DesignerCEP -``` - -### 4.3 配置 Systemd 服务 -创建服务文件: -```bash -sudo nano /etc/systemd/system/designer-cep.service -``` -粘贴内容: -```ini -[Unit] -Description=DesignerCEP Backend -After=network.target - -[Service] -User=www-data -Group=www-data -WorkingDirectory=/var/www/DesignerCEP/Server -Environment="PATH=/var/www/DesignerCEP/Server/venv/bin" -ExecStart=/var/www/DesignerCEP/Server/venv/bin/gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 -Restart=always - -[Install] -WantedBy=multi-user.target -``` - -启动服务: -```bash -sudo systemctl daemon-reload -sudo systemctl enable designer-cep -sudo systemctl start designer-cep -sudo systemctl status designer-cep # 检查是否显示 Active: active (running) -``` - ---- - -## 🌐 5. Caddy 配置 (HTTPS & 反向代理) - -**⚠️ 关键提示:Cloudflare SSL 模式必须设置为 Full (Strict)** - -编辑 Caddy 配置文件: -```bash -sudo nano /etc/caddy/Caddyfile -``` -**清空原有内容,粘贴以下内容**: - -```caddy -# ========== 主域名 (Shell & Core & Downloads) ========== -aidg168.uk, www.aidg168.uk { - # 1. Shell 静态页面 - handle /shell/* { - root * /var/www/DesignerCEP/Server/static/shell - try_files {path} {path}/ /shell/index.html - file_server - } - - # 2. Core 核心应用 - handle /core/* { - root * /var/www/DesignerCEP/Server/static/core - file_server - } - - # 3. 下载文件 - handle /downloads/* { - root * /var/www/DesignerCEP/Server/static/downloads - file_server - } - - # 4. 根路径跳转到 Shell - handle / { - redir /shell/ permanent - } - - # 5. 压缩与日志 - encode gzip - log { - output file /var/log/caddy/designer-cep.log - } -} - -# ========== API 专用域名 (FastAPI) ========== -backend.aidg168.uk { - # 1. API 代理到后端 (FastAPI) - reverse_proxy 127.0.0.1:8000 - - # 2. 压缩与日志 - encode gzip - log { - output file /var/log/caddy/designer-cep-api.log - } -} -``` - -重启 Caddy: -```bash -sudo systemctl restart caddy -sudo systemctl status caddy -``` - ---- - -## 🔒 6. 安全与网络检查 (必做!) - -**1. 确认 Cloudflare SSL 模式** -- 登录 Cloudflare 控制台 -> SSL/TLS -> Overview -- **必须选择**: `Full (Strict)` -- *原因*: Caddy 会自动申请 Let's Encrypt 证书,Cloudflare 需要信任这个有效证书。 - -**2. 确认防火墙端口** -在服务器上执行: -```bash -sudo ufw allow 80 -sudo ufw allow 443 -sudo ufw reload -``` - -**3. 确认 Caddy 监听状态** -在服务器上执行: -```bash -sudo ss -lntp | grep 443 -``` -*预期输出*: 应该看到 `caddy` 进程正在监听 `*:443`。 - -**4. 快速自检 (在服务器上执行)** -```bash -# 1. 检查 DNS (应返回 Cloudflare IP) -dig backend.aidg168.uk +short - -# 2. 本机测试 API (绕过 Cloudflare) -curl -v http://127.0.0.1:8000/health - -# 3. 域名测试 (走公网) -curl -I https://backend.aidg168.uk/health -``` - ---- - -## ✅ 7. 验证部署 - -打开浏览器访问: -1. **API 健康检查**: `https://backend.aidg168.uk/health` (应返回 `{"status": "healthy"}`) -2. **Shell 页面**: `https://aidg168.uk/shell/` (应显示登录页) -3. **Core 版本**: `https://aidg168.uk/core/1.0.1/index.html` (确认版本存在) - ---- - -## 🔄 更新维护 - -### 更新前端 -1. 本地 `npm run build` -2. 上传新文件到对应目录 -3. 不需要重启服务 - -### 更新后端 -1. 上传新代码到 `/var/www/DesignerCEP/Server` -2. 重启服务:`sudo systemctl restart designer-cep` diff --git a/temp_backup/Server_redundant/tempdocs/知乎文章摘要.md b/temp_backup/Server_redundant/tempdocs/知乎文章摘要.md deleted file mode 100644 index d04e7f2..0000000 --- a/temp_backup/Server_redundant/tempdocs/知乎文章摘要.md +++ /dev/null @@ -1,56 +0,0 @@ -# EmptyKid 知乎专栏文章汇总与摘要 - -由于网络请求限制,以下整理了**EmptyKid**专栏的最新文章目录,并对部分能够获取内容的核心文章进行了摘要。 - -## 📂 文章索引 (按照最新发布排序) - -### PS 插件与 CEP 开发教程系列 -1. **[【CEP教程-17】插件的打包和发布](https://zhuanlan.zhihu.com/p/27361054277)** -2. [【CEP教程-16】JSX的工程化](https://zhuanlan.zhihu.com/p/22605290525) -3. [【CEP教程-15】前端框架在插件面板中的应用](https://zhuanlan.zhihu.com/p/683712943) -4. [【CEP教程-14】数据存储相关](https://zhuanlan.zhihu.com/p/675795467) -5. [【CEP教程-13】nodejs在插件开发中的应用](https://zhuanlan.zhihu.com/p/661392566) -6. [【CEP教程-12】如何从Ps中导出图片](https://zhuanlan.zhihu.com/p/658067352) -7. [【CEP教程-11】生成器](https://zhuanlan.zhihu.com/p/643541900) -8. [【CEP教程-10】图层处理那些事](https://zhuanlan.zhihu.com/p/617477492) -9. [【CEP教程-10】Action Manager完全指南 - 下篇](https://zhuanlan.zhihu.com/p/608104095) -10. [【CEP教程-9】Action Manager完全指南 - 中篇](https://zhuanlan.zhihu.com/p/601014597) -11. [【CEP教程-8】Action Manager完全指南 - 上篇](https://zhuanlan.zhihu.com/p/600014746) -12. [Photoshop插件开发教程 - (7)JSX脚本指南 - DOM篇](https://zhuanlan.zhihu.com/p/596166382) -13. [Photoshop插件开发教程 - (6)面板与宿主之间的交互](https://zhuanlan.zhihu.com/p/566983957) -14. [Photoshop插件开发教程 - (5)插件面板的样式](https://zhuanlan.zhihu.com/p/563847844) -15. [Photoshop插件开发教程 - (4)开发工具选择和调试](https://zhuanlan.zhihu.com/p/559290141) -16. [Photoshop插件开发教程 - (3)CEP插件面板结构介绍](https://zhuanlan.zhihu.com/p/555070606) -17. [Photoshop插件开发教程 - (2)开发环境搭建](https://zhuanlan.zhihu.com/p/532152091) -18. [Photoshop插件开发教程 - (1)插件类型](https://zhuanlan.zhihu.com/p/518229060) - -### UXP 开发系列 -1. [【UXP教程-2】UXP插件开发起步](https://zhuanlan.zhihu.com/p/20904402159) -2. [【Adobe UXP插件开发中文教程】- 1. 简介](https://zhuanlan.zhihu.com/p/600569875) - -### 其他分享 -1. [我给三年级女儿开发了一个打字网站](https://zhuanlan.zhihu.com/p/676856628) - ---- - -## 📝 精选摘要 - -### 1. 插件的打包和发布 (CEP教程-17) -**核心内容要点:** -* **格式**: CEP 插件最终需要打包为 `.zxp` 格式才能分发。 -* **工具**: 使用 Adobe 官方提供的 `ZXPSignCmd` 命令行工具。 -* **流程**: - 1. 准备好完整的插件目录(包含 `CSXS/manifest.xml`)。 - 2. 需要一个数字证书(`.p12`),可以使用 `ZXPSignCmd` 自行生成自签名证书。 - 3. 运行打包命令,将源码目录和证书合并生成 `.zxp` 文件。 -* **安装**: 用户可以使用第三方工具(如 ZXPInstaller)或专门的 Extension Manager 来安装 `.zxp` 文件。 - -### 2. 我给三年级女儿开发了一个打字网站 -**背景**: 作者因为目前国内访问国外的 TypingClub 困难,且学校要求练习打字,于是为还在上三年级的女儿开发了一个免费的打字练习网站。 -**特点**: -* 针对小学生优化。 -* 解决了访问速度和稳定性问题。 -* (推测) 包含基础的指法练习和进度记录。 - ---- -> **注意**: 由于知乎的访问安全策略,目前只能提取到文章列表。如需其他文章的详细内容,建议在该浏览器中保持登录状态并手动复制文本给我。 diff --git a/temp_backup/Server_redundant/tempdocs/紧急诊断.md b/temp_backup/Server_redundant/tempdocs/紧急诊断.md deleted file mode 100644 index 341cb10..0000000 --- a/temp_backup/Server_redundant/tempdocs/紧急诊断.md +++ /dev/null @@ -1,164 +0,0 @@ -# 🚨 紧急诊断:所有 JSX 方法都失败 - -## 😰 当前状况 - -**所有测试方法都失败了**,这说明问题很严重。让我们逐步排查。 - ---- - -## 🔍 诊断步骤 - -### 步骤 1:确认 JSX 文件是否被加载 - -**在浏览器控制台查看:** - -1. 是否有 `[__LDX] Success` 日志? -2. 是否有 `Ultra Simple JSX Loaded` 日志? - -**如果没有这些日志:** -- ❌ JSX 文件根本没被加载 -- 原因:路径不对或文件不存在 - -**如果有这些日志:** -- ✅ JSX 文件已加载 -- 但函数调用失败 - ---- - -### 步骤 2:测试最简单的函数 - -**在浏览器控制台执行:** - -```javascript -// 测试1:最简单的字符串返回 -cep.evalScript("test1()").then(r => console.log('Test1:', r)) - -// 测试2:简单计算 -cep.evalScript("test2()").then(r => console.log('Test2:', r)) - -// 测试3:获取 PS 名称 -cep.evalScript("test3()").then(r => console.log('Test3:', r)) - -// 测试4:检查文档 -cep.evalScript("test4()").then(r => console.log('Test4:', r)) - -// 测试5:创建图层 -cep.evalScript("test5()").then(r => console.log('Test5:', r)) -``` - -**预期结果:** -``` -Test1: "test1_success" -Test2: "1+1=2" -Test3: "app_name=Adobe Photoshop" -Test4: "has_document" 或 "no_document" -Test5: "layer_created" 或 "error=..." -``` - ---- - -### 步骤 3:如果还是全部失败 - -**可能的原因:** - -#### 原因 1:路径错误 - -控制台显示的路径是: -``` -C:/Users/35780/AppData/Roaming/DesignerCache/v1.0.7/jsx/index.js -``` - -**检查这个文件是否存在:** - -```powershell -# 在 PowerShell 中运行 -Get-Content "$env:APPDATA\DesignerCache\v1.0.7\jsx\index.js" -Head 5 -``` - -**应该看到:** -```javascript -/** - * 超级简化版 JSX 测试 - */ -``` - -**如果看不到或报错:** -- 文件不存在或内容不对 -- 需要重新复制 - -#### 原因 2:CEP 版本问题 - -**检查 CEP 版本:** - -```javascript -// 在控制台运行 -console.log('CEP Version:', (window as any).__adobe_cep__?.getCurrentImsUserId ? 'CEP 7+' : 'Unknown') -``` - -#### 原因 3:evalScript 本身有问题 - -**测试 evalScript 是否工作:** - -```javascript -// 最简单的测试 -cep.evalScript("1+1").then(r => console.log('Basic calc:', r)) - -// 测试 app 对象 -cep.evalScript("app.name").then(r => console.log('App name:', r)) - -// 测试返回字符串 -cep.evalScript("'hello world'").then(r => console.log('String:', r)) -``` - ---- - -## 🎯 请告诉我 - -测试完成后,请告诉我: - -### 1. JSX 是否被加载? -- [ ] 看到了 `[__LDX] Success` 日志 -- [ ] 看到了 `Ultra Simple JSX Loaded` 日志 -- [ ] 都没看到 - -### 2. 简单测试的结果 -``` -test1(): ______________ -test2(): ______________ -test3(): ______________ -test4(): ______________ -test5(): ______________ -``` - -### 3. evalScript 基本测试 -``` -1+1: ______________ -app.name: ______________ -'hello world': ______________ -``` - -### 4. 文件是否存在? -```powershell -Get-Content "$env:APPDATA\DesignerCache\v1.0.7\jsx\index.js" -Head 5 -``` -结果: ______________ - ---- - -## 💡 可能的解决方案 - -根据上面的测试结果,我们可以确定: - -### 如果 JSX 没被加载 -→ 路径问题,需要找到正确的路径 - -### 如果 JSX 被加载但函数失败 -→ evalScript 调用方式问题 - -### 如果 evalScript 基本测试也失败 -→ CEP 环境本身有问题 - ---- - -**现在请按照步骤 1-4 测试,并告诉我结果!** 🔍 - diff --git a/temp_backup/Server_redundant/tempdocs/线上部署指南.md b/temp_backup/Server_redundant/tempdocs/线上部署指南.md deleted file mode 100644 index dc693e7..0000000 --- a/temp_backup/Server_redundant/tempdocs/线上部署指南.md +++ /dev/null @@ -1,634 +0,0 @@ -# DesignerCEP 线上部署指南 - -## 📋 部署架构概览 - -本项目包含三个主要部分: -1. **Shell(登录壳)**: 本地 CEP 扩展,负责登录和版本管理 -2. **Core(核心应用)**: 通过后端服务器提供的 Web 应用 -3. **Backend(后端服务)**: FastAPI 服务器,提供 API 和静态文件服务 - ---- - -## 🚀 一、前端部署 - -### 1.1 构建前准备 - -#### ✅ 关闭生产环境日志 - -在 `main.ts` 或应用入口添加: - -```typescript -import { logger } from '@/utils/logger'; - -// 生产环境关闭日志 -if (import.meta.env.PROD) { - logger.disable(); -} else { - logger.enable(); -} -``` - -或者在 `logger.ts` 中修改默认状态: - -```typescript -class Logger { - // 生产环境默认关闭,开发环境默认开启 - private _enabled: boolean = import.meta.env.DEV; - // ... -} -``` - -#### ✅ 配置生产环境 API 地址 - -创建 `.env.production` 文件: - -```env -# 生产环境配置 -VITE_API_BASE_URL=https://your-domain.com/api/v1 -VITE_API_SERVER=https://your-domain.com -``` - -修改 `config.ts`: - -```typescript -export const config = { - // 从环境变量读取 - apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://127.0.0.1:8000/api/v1', - apiServer: import.meta.env.VITE_API_SERVER || 'http://127.0.0.1:8000', - - // ...其他配置 -}; -``` - -### 1.2 构建命令 - -```bash -# 进入 Designer 目录 -cd Designer - -# 安装依赖(如果还没安装) -npm install - -# 构建生产版本 -npm run build - -# 构建完成后,产物在 dist/ 目录 -``` - -### 1.3 构建产物说明 - -``` -Designer/dist/ - ├── Shell/ # Shell 登录壳(本地 CEP 扩展使用) - │ ├── index.html - │ ├── assets/ - │ └── ... - └── Designer/ # Core 核心应用(上传到服务器) - ├── index.html - ├── assets/ - └── ... -``` - -**重要说明:** -- `dist/Shell/` → 需要部署到服务器的两个地方: - - 打包为 `.zip` 供 CEP 扩展下载:`static/shell/shell-{version}.zip` - - 部署为在线登录页:`static/shell/` (直接部署文件) -- `dist/Designer/` → 上传到服务器的 `static/core/{version}/` 目录 - ---- - -## 🖥️ 二、后端部署 - -### 2.1 服务器要求 - -- **操作系统**: Linux (推荐 Ubuntu 20.04+) 或 Windows Server -- **Python 版本**: Python 3.9+ -- **内存**: 最低 1GB,推荐 2GB+ -- **磁盘**: 至少 10GB 可用空间(用于存储版本文件) -- **域名**: 需要一个域名并配置 DNS -- **SSL 证书**: 建议使用 Let's Encrypt 免费证书 - -### 2.2 部署步骤 - -#### 步骤 1: 上传代码 - -```bash -# 方式 1: Git 克隆(推荐) -ssh user@your-server -cd /var/www -git clone https://your-repo-url.git DesignerCEP -cd DesignerCEP/Server - -# 方式 2: SCP 上传 -# 本地执行 -scp -r Server/ user@your-server:/var/www/DesignerCEP/ -``` - -#### 步骤 2: 创建虚拟环境 - -```bash -cd /var/www/DesignerCEP/Server - -# 创建虚拟环境 -python3 -m venv venv - -# 激活虚拟环境 -source venv/bin/activate # Linux -# 或 -venv\Scripts\activate # Windows - -# 安装依赖 -pip install -r requirements.txt -``` - -#### 步骤 3: 配置环境变量 - -创建 `.env` 文件: - -```bash -# /var/www/DesignerCEP/Server/.env - -# 基础配置 -PROJECT_NAME=DesignerCEP -VERSION=1.0.0 -DEBUG=False - -# 安全配置 -SECRET_KEY=your-super-secret-key-change-this-in-production -ALGORITHM=HS256 -ACCESS_TOKEN_EXPIRE_MINUTES=43200 - -# 数据库配置(如果使用) -DATABASE_URL=sqlite:///./designer.db -# 或使用 PostgreSQL/MySQL -# DATABASE_URL=postgresql://user:password@localhost/dbname - -# CORS 配置 -ALLOWED_ORIGINS=https://your-domain.com,https://www.your-domain.com - -# 静态文件路径 -STATIC_DIR=/var/www/DesignerCEP/Server/static -SHELL_DIR=/var/www/DesignerCEP/Server/static/shell -CORE_DIR=/var/www/DesignerCEP/Server/static/core -``` - -#### 步骤 4: 准备静态文件目录 - -```bash -# 创建目录结构 -mkdir -p static/shell -mkdir -p static/core/1.0.0 - -# 1. 上传 Shell 在线登录页(用于网页访问) -scp -r Designer/dist/Shell/* user@your-server:/var/www/DesignerCEP/Server/static/shell/ - -# 2. 打包 Shell 供 CEP 扩展下载 -cd Designer/dist -zip -r shell-1.0.0.zip Shell/ -scp shell-1.0.0.zip user@your-server:/var/www/DesignerCEP/Server/static/downloads/ -cd ../.. - -# 3. 上传 Core 构建产物 -scp -r Designer/dist/Designer/* user@your-server:/var/www/DesignerCEP/Server/static/core/1.0.0/ -``` - -目录结构应该是: - -``` -Server/ - ├── app/ - ├── static/ - │ ├── shell/ # Shell 在线登录页 - │ │ ├── index.html - │ │ ├── assets/ - │ │ └── ... - │ ├── downloads/ # 下载文件(供 CEP 扩展) - │ │ └── shell-1.0.0.zip - │ └── core/ - │ └── 1.0.0/ # Core 核心应用 - │ ├── index.html - │ ├── assets/ - │ └── ... - ├── .env - ├── requirements.txt - └── main.py -``` - -**说明:** -- `static/shell/` - Shell 在线登录页,用户退出登录后访问这里 -- `static/downloads/shell-1.0.0.zip` - 供 CEP 扩展首次下载的 Shell 安装包 -- `static/core/1.0.0/` - Core 核心应用,用户登录后使用 - -#### 步骤 5: 使用 Gunicorn 运行(生产环境) - -安装 Gunicorn: - -```bash -pip install gunicorn uvicorn[standard] -``` - -创建启动脚本 `start.sh`: - -```bash -#!/bin/bash -cd /var/www/DesignerCEP/Server -source venv/bin/activate - -gunicorn app.main:app \ - --workers 4 \ - --worker-class uvicorn.workers.UvicornWorker \ - --bind 0.0.0.0:8000 \ - --access-logfile logs/access.log \ - --error-logfile logs/error.log \ - --daemon -``` - -```bash -chmod +x start.sh -./start.sh -``` - -#### 步骤 6: 使用 Systemd 管理服务(推荐) - -创建服务文件 `/etc/systemd/system/designer-cep.service`: - -```ini -[Unit] -Description=DesignerCEP Backend Service -After=network.target - -[Service] -Type=notify -User=www-data -Group=www-data -WorkingDirectory=/var/www/DesignerCEP/Server -Environment="PATH=/var/www/DesignerCEP/Server/venv/bin" -ExecStart=/var/www/DesignerCEP/Server/venv/bin/gunicorn \ - --workers 4 \ - --worker-class uvicorn.workers.UvicornWorker \ - --bind 0.0.0.0:8000 \ - app.main:app - -Restart=always -RestartSec=3 - -[Install] -WantedBy=multi-user.target -``` - -启动服务: - -```bash -# 重载 systemd -sudo systemctl daemon-reload - -# 启动服务 -sudo systemctl start designer-cep - -# 设置开机自启 -sudo systemctl enable designer-cep - -# 查看状态 -sudo systemctl status designer-cep - -# 查看日志 -sudo journalctl -u designer-cep -f -``` - ---- - -## 🔧 三、Nginx 反向代理配置 - -### 3.1 安装 Nginx - -```bash -sudo apt update -sudo apt install nginx -``` - -### 3.2 配置 Nginx - -创建配置文件 `/etc/nginx/sites-available/designer-cep`: - -```nginx -# HTTP 重定向到 HTTPS -server { - listen 80; - listen [::]:80; - server_name your-domain.com www.your-domain.com; - - # Let's Encrypt 验证 - location /.well-known/acme-challenge/ { - root /var/www/certbot; - } - - # 重定向到 HTTPS - location / { - return 301 https://$server_name$request_uri; - } -} - -# HTTPS 配置 -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name your-domain.com www.your-domain.com; - - # SSL 证书配置 - ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - - # 日志 - access_log /var/log/nginx/designer-cep-access.log; - error_log /var/log/nginx/designer-cep-error.log; - - # 客户端最大上传大小(用于大文件上传) - client_max_body_size 100M; - - # API 代理 - location /api/ { - proxy_pass http://127.0.0.1:8000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # WebSocket 支持(如果需要) - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } - - # Shell 在线登录页 - location /shell/ { - alias /var/www/DesignerCEP/Server/static/shell/; - try_files $uri $uri/ /shell/index.html; - - # HTML 不缓存,资源文件缓存 - location ~* \.html$ { - expires -1; - add_header Cache-Control "no-cache, no-store, must-revalidate"; - } - - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 7d; - add_header Cache-Control "public, immutable"; - } - } - - # 下载文件(供 CEP 扩展下载) - location /downloads/ { - alias /var/www/DesignerCEP/Server/static/downloads/; - autoindex off; - - # 强制下载 - add_header Content-Disposition "attachment"; - - # 缓存配置 - expires 7d; - add_header Cache-Control "public, immutable"; - } - - # Core 静态文件 - location /core/ { - alias /var/www/DesignerCEP/Server/static/core/; - try_files $uri $uri/ =404; - - # SPA 路由支持(如果需要) - # try_files $uri $uri/ /core/$1/index.html; - - # 缓存配置 - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } - - location ~* \.html$ { - expires -1; - add_header Cache-Control "no-cache, no-store, must-revalidate"; - } - } - - # 健康检查 - location /health { - proxy_pass http://127.0.0.1:8000/health; - access_log off; - } -} -``` - -启用配置: - -```bash -# 创建软链接 -sudo ln -s /etc/nginx/sites-available/designer-cep /etc/nginx/sites-enabled/ - -# 测试配置 -sudo nginx -t - -# 重载 Nginx -sudo systemctl reload nginx -``` - -### 3.3 配置 SSL 证书(Let's Encrypt) - -```bash -# 安装 Certbot -sudo apt install certbot python3-certbot-nginx - -# 获取证书 -sudo certbot --nginx -d your-domain.com -d www.your-domain.com - -# 自动续期(已自动配置 cron) -sudo certbot renew --dry-run -``` - ---- - -## 🔒 四、安全配置 - -### 4.1 防火墙配置 - -```bash -# 允许 SSH -sudo ufw allow 22/tcp - -# 允许 HTTP/HTTPS -sudo ufw allow 80/tcp -sudo ufw allow 443/tcp - -# 启用防火墙 -sudo ufw enable - -# 查看状态 -sudo ufw status -``` - -### 4.2 生产环境安全检查清单 - -- [ ] 修改 `SECRET_KEY` 为随机强密钥 -- [ ] 设置 `DEBUG=False` -- [ ] 配置正确的 `ALLOWED_ORIGINS` -- [ ] 使用 HTTPS(SSL 证书) -- [ ] 配置数据库(不使用 SQLite) -- [ ] 设置文件上传大小限制 -- [ ] 配置日志轮转 -- [ ] 关闭前端日志输出 -- [ ] 定期备份数据库和用户数据 -- [ ] 配置监控和告警 - ---- - -## 📦 五、版本更新流程 - -### 5.1 发布新版本 - -```bash -# 1. 本地构建新版本 -cd Designer -npm run build - -# 2. 上传到服务器 -scp -r dist/Designer/* user@your-server:/var/www/DesignerCEP/Server/static/core/1.0.1/ - -# 3. 更新后端版本配置 -# 在后端 API 中更新 current_version 为 1.0.1 -``` - -### 5.2 版本管理建议 - -``` -static/core/ - ├── 1.0.0/ # 旧版本保留 - ├── 1.0.1/ # 当前版本 - └── 1.0.2/ # 新版本 -``` - -后端 API 返回最新版本号,客户端自动下载更新。 - ---- - -## 🔍 六、监控与日志 - -### 6.1 日志管理 - -创建日志轮转配置 `/etc/logrotate.d/designer-cep`: - -``` -/var/www/DesignerCEP/Server/logs/*.log { - daily - rotate 30 - compress - delaycompress - notifempty - create 0640 www-data www-data - sharedscripts - postrotate - systemctl reload designer-cep > /dev/null 2>&1 || true - endscript -} -``` - -### 6.2 性能监控 - -推荐使用: -- **PM2**: 进程管理和监控 -- **Prometheus + Grafana**: 指标监控 -- **Sentry**: 错误追踪 -- **ELK Stack**: 日志分析 - ---- - -## 🚀 七、快速部署脚本 - -创建 `deploy.sh` 一键部署脚本: - -```bash -#!/bin/bash - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}========================================${NC}" -echo -e "${GREEN} DesignerCEP 自动部署脚本${NC}" -echo -e "${GREEN}========================================${NC}" - -# 1. 拉取最新代码 -echo -e "\n${YELLOW}[1/6] 拉取最新代码...${NC}" -git pull origin main - -# 2. 构建前端 -echo -e "\n${YELLOW}[2/6] 构建前端...${NC}" -cd Designer -npm install -npm run build -cd .. - -# 3. 上传 Core 到服务器 -echo -e "\n${YELLOW}[3/6] 上传 Core 到服务器...${NC}" -VERSION=$(node -p "require('./Designer/package.json').version") -ssh user@your-server "mkdir -p /var/www/DesignerCEP/Server/static/core/$VERSION" -scp -r Designer/dist/Designer/* user@your-server:/var/www/DesignerCEP/Server/static/core/$VERSION/ - -# 4. 更新后端代码 -echo -e "\n${YELLOW}[4/6] 更新后端代码...${NC}" -ssh user@your-server "cd /var/www/DesignerCEP/Server && git pull origin main" - -# 5. 重启后端服务 -echo -e "\n${YELLOW}[5/6] 重启后端服务...${NC}" -ssh user@your-server "sudo systemctl restart designer-cep" - -# 6. 检查服务状态 -echo -e "\n${YELLOW}[6/6] 检查服务状态...${NC}" -ssh user@your-server "sudo systemctl status designer-cep --no-pager" - -echo -e "\n${GREEN}========================================${NC}" -echo -e "${GREEN} 部署完成!${NC}" -echo -e "${GREEN} 版本: $VERSION${NC}" -echo -e "${GREEN}========================================${NC}" -``` - -使用方法: - -```bash -chmod +x deploy.sh -./deploy.sh -``` - ---- - -## ❓ 八、常见问题 - -### Q1: CORS 跨域问题 -**A**: 在后端 `.env` 中正确配置 `ALLOWED_ORIGINS`。 - -### Q2: 静态文件 404 -**A**: 检查 Nginx 配置中的 `alias` 路径是否正确。 - -### Q3: API 请求超时 -**A**: 调整 Nginx `proxy_read_timeout` 和 Gunicorn `timeout` 参数。 - -### Q4: 前端日志仍然输出 -**A**: 确保在生产环境中调用了 `logger.disable()`。 - -### Q5: 版本更新后客户端没反应 -**A**: 检查后端 API 返回的版本号是否正确,清除客户端缓存。 - ---- - -## 📞 技术支持 - -如遇到部署问题,请检查: -1. 后端日志:`sudo journalctl -u designer-cep -f` -2. Nginx 日志:`sudo tail -f /var/log/nginx/designer-cep-error.log` -3. 系统资源:`htop` 或 `top` - ---- - -**最后更新**: 2024-12-17 - diff --git a/temp_backup/Server_redundant/tempdocs/认证接口文档.md b/temp_backup/Server_redundant/tempdocs/认证接口文档.md deleted file mode 100644 index bd7734b..0000000 --- a/temp_backup/Server_redundant/tempdocs/认证接口文档.md +++ /dev/null @@ -1,97 +0,0 @@ -# 认证接口文档 - -## 概述 -- 基础地址:`http://localhost:8000` -- 版本前缀:`/api/v1` -- 认证方式:`Bearer JWT`(登录或注册成功后返回的 `access_token`) -- 单设备限制:同一账号仅允许一个设备同时在线(依据 `device_id`) - -## 注册 -- 方法与路径:`POST /api/v1/auth/register` -- 请求体: -```json -{ - "username": "alice", - "password": "secret123", - "confirm_password": "secret123" -} -``` -- 成功响应: -```json -{ - "access_token": "", - "token_type": "bearer", - "username": "alice" -} -``` -- 失败响应示例: - - 400:`Passwords do not match` - - 400:`Username already registered` -- 调用示例(curl): -```bash -curl -X POST http://localhost:8000/api/v1/auth/register \ - -H "Content-Type: application/json" \ - -d '{"username":"alice","password":"secret123","confirm_password":"secret123"}' -``` - -## 登录 -- 方法与路径:`POST /api/v1/auth/login` -- 请求体: -```json -{ - "username": "alice", - "password": "secret123", - "device_id": "devA" -} -``` -- 成功响应: -```json -{ - "access_token": "", - "token_type": "bearer", - "username": "alice" -} -``` -- 失败响应示例: - - 401:`用户名或密码错误` - - 403:`该账号已在其他设备在线` -- 调用示例(curl): -```bash -curl -X POST http://localhost:8000/api/v1/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"alice","password":"secret123","device_id":"devA"}' -``` - -## 登出 -- 方法与路径:`POST /api/v1/auth/logout` -- 请求体: -```json -{ - "username": "alice", - "device_id": "devA" -} -``` -- 成功响应: -```json -{ "detail": "已退出登录" } -``` -- 用途:释放当前设备的会话,便于其他设备登录同账号 - -## 在线时长统计 -- 方法与路径:`GET /api/v1/auth/online-time/{username}` -- 返回体: -```json -{ - "username": "alice", - "total_seconds": 1234, // 已登出会话累计时长(秒) - "active_seconds": 56 // 当前活跃会话的实时在线时长(秒) -} -``` -- 说明: - - 登录时会记录 `login_at`,登出时写入 `logout_at` 并计算 `duration_seconds` - - `total_seconds` 为历史累计;`active_seconds` 为当前会话实时值 - -## 前端对接建议 -- 前端拿到 `access_token` 后,将其置于请求头:`Authorization: Bearer ` -- 后续接口可以基于该令牌进行身份识别和鉴权 -- 登录时必须传入稳定的 `device_id`,建议由前端根据系统信息生成并持久化(例如用户目录内文件或硬件指纹) diff --git a/temp_backup/Server_redundant/tempdocs/许可证验证接口文档.md b/temp_backup/Server_redundant/tempdocs/许可证验证接口文档.md deleted file mode 100644 index 013af20..0000000 --- a/temp_backup/Server_redundant/tempdocs/许可证验证接口文档.md +++ /dev/null @@ -1,371 +0,0 @@ -# 许可证验证接口文档 - -## 📋 接口概述 - -**接口路径:** `POST /api/v1/auth/verify` - -**功能:** 验证用户的登录 token 是否有效(用于心跳检测) - -**调用频率:** 每 60 秒调用一次 - ---- - -## 📥 请求参数 - -### Headers -```json -{ - "Content-Type": "application/json", - "Authorization": "Bearer {token}" -} -``` - -### Body (JSON) -```json -{ - "username": "string", // 用户名 - "device_id": "string", // 设备 ID - "timestamp": 1234567890 // 客户端时间戳(毫秒) -} -``` - -### 示例请求 -```http -POST /api/v1/auth/verify HTTP/1.1 -Host: 127.0.0.1:8000 -Content-Type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - -{ - "username": "zuowei", - "device_id": "065dfbc8-9539-405e-8af0-7cfd56000e6", - "timestamp": 1702828800000 -} -``` - ---- - -## 📤 响应格式 - -### 成功响应(200 OK) - -```json -{ - "valid": true, - "username": "zuowei", - "expire_date": "2025-12-31T23:59:59Z" // 可选:账户过期时间 -} -``` - -### 失败响应 1:Token 无效(401 Unauthorized) - -```json -{ - "detail": "Token 无效或已过期" -} -``` - -### 失败响应 2:账户已过期(403 Forbidden) - -```json -{ - "valid": false, - "message": "账户已过期" -} -``` - -### 失败响应 3:会话不存在(404 Not Found) - -```json -{ - "detail": "会话不存在或已登出" -} -``` - ---- - -## 🔧 后端实现示例(FastAPI) - -### 1. 在 `Server/app/api/v1/auth.py` 添加路由 - -```python -from fastapi import Depends, HTTPException, status -from pydantic import BaseModel -from app.core.security import get_current_user -from app.db import get_db -from sqlalchemy.orm import Session -from app.models.user import User, UserSession -from datetime import datetime, timezone - -class VerifyRequest(BaseModel): - """验证请求""" - username: str - device_id: str - timestamp: int - -class VerifyResponse(BaseModel): - """验证响应""" - valid: bool - username: str = None - expire_date: str = None - -@router.post("/verify", response_model=VerifyResponse) -async def verify_license( - request: VerifyRequest, - current_user: dict = Depends(get_current_user), - db: Session = Depends(get_db) -): - """ - 验证许可证(心跳检测) - 检查: - 1. Token 是否有效(通过 Depends(get_current_user) 自动验证) - 2. 用户是否存在 - 3. 会话是否活跃 - 4. 账户是否过期 - """ - - # 1. 查询用户 - user = db.query(User).filter(User.username == request.username).first() - if not user: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="用户不存在" - ) - - # 2. 检查账户是否过期 - if user.expire_date: - expire_dt = user.expire_date - if expire_dt.tzinfo is None: - expire_dt = expire_dt.replace(tzinfo=timezone.utc) - - if datetime.now(timezone.utc) > expire_dt: - return VerifyResponse( - valid=False, - username=request.username, - expire_date=user.expire_date.isoformat() if user.expire_date else None - ) - - # 3. 检查会话是否活跃 - session = db.query(UserSession).filter( - UserSession.user_id == user.id, - UserSession.device_id == request.device_id, - UserSession.active == True - ).first() - - if not session: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="会话不存在或已登出" - ) - - # 4. 更新最后活跃时间 - session.last_seen_at = datetime.now(timezone.utc) - db.commit() - - # 5. 返回验证成功 - return VerifyResponse( - valid=True, - username=request.username, - expire_date=user.expire_date.isoformat() if user.expire_date else None - ) -``` - ---- - -### 2. 更新 `Server/app/schemas/auth.py` - -添加验证相关的 Schema: - -```python -class VerifyRequest(BaseModel): - """验证请求模型""" - username: str - device_id: str - timestamp: int - -class VerifyResponse(BaseModel): - """验证响应模型""" - valid: bool - username: Optional[str] = None - expire_date: Optional[str] = None -``` - ---- - -## 🧪 测试验证接口 - -### 使用 curl 测试 - -```bash -curl -X POST http://127.0.0.1:8000/api/v1/auth/verify \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_TOKEN_HERE" \ - -d '{ - "username": "zuowei", - "device_id": "test-device-123", - "timestamp": 1702828800000 - }' -``` - -### 预期响应 - -**成功:** -```json -{ - "valid": true, - "username": "zuowei", - "expire_date": null -} -``` - -**Token 无效:** -```json -{ - "detail": "Could not validate credentials" -} -``` - -**会话不存在:** -```json -{ - "detail": "会话不存在或已登出" -} -``` - ---- - -## 📊 数据库表设计(参考) - -确保数据库有以下表和字段: - -### users 表 -```sql -CREATE TABLE users ( - id INTEGER PRIMARY KEY, - username VARCHAR UNIQUE NOT NULL, - expire_date DATETIME, -- 账户过期时间(NULL = 永久) - ... -); -``` - -### user_sessions 表 -```sql -CREATE TABLE user_sessions ( - id INTEGER PRIMARY KEY, - user_id INTEGER NOT NULL, - device_id VARCHAR NOT NULL, - active BOOLEAN DEFAULT TRUE, - last_seen_at DATETIME, -- 最后活跃时间 - ... - FOREIGN KEY (user_id) REFERENCES users(id) -); -``` - ---- - -## 🔐 安全注意事项 - -1. **Token 验证** - - 使用 `Depends(get_current_user)` 确保 Token 有效 - - Token 过期自动返回 401 - -2. **会话管理** - - 验证成功时更新 `last_seen_at` - - 可用于统计在线时长 - -3. **过期检查** - - 支持账户过期时间 - - 过期返回 `valid: false` - -4. **频率控制** - - 前端已做 30 秒缓存,减少请求频率 - - 后端可添加 Rate Limiting - ---- - -## 🚀 部署检查 - -添加接口后,确认: - -1. ✅ 路由已注册 - ```python - # Server/app/main.py - app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth") - ``` - -2. ✅ 数据库表存在 - ```bash - # 检查 users 和 user_sessions 表 - ``` - -3. ✅ Token 验证正常 - ```bash - # 测试登录获取 Token - # 测试 verify 接口 - ``` - -4. ✅ 前端心跳正常 - ``` - # 前端每 60 秒调用一次 - # 30 秒内不重复验证(有缓存) - ``` - ---- - -## 📝 完整实现清单 - -- [ ] 添加 `VerifyRequest` 和 `VerifyResponse` Schema -- [ ] 在 `auth.py` 添加 `/verify` 路由 -- [ ] 实现 Token 验证逻辑 -- [ ] 实现账户过期检查 -- [ ] 实现会话活跃检查 -- [ ] 更新最后活跃时间 -- [ ] 测试接口(成功、失败、过期等场景) -- [ ] 部署到服务器 - ---- - -## 💡 可选增强 - -### 1. 添加限流(Rate Limiting) - -```python -from slowapi import Limiter -from slowapi.util import get_remote_address - -limiter = Limiter(key_func=get_remote_address) - -@router.post("/verify") -@limiter.limit("120/minute") # 每分钟最多 120 次 -async def verify_license(...): - ... -``` - -### 2. 添加详细日志 - -```python -import logging - -logger = logging.getLogger(__name__) - -@router.post("/verify") -async def verify_license(...): - logger.info(f"[Verify] {request.username} from {request.device_id}") - ... -``` - -### 3. 返回更多信息 - -```python -class VerifyResponse(BaseModel): - valid: bool - username: str = None - expire_date: str = None - permissions: list = [] # 用户权限列表 - online_time: int = 0 # 在线时长(秒) -``` - ---- - -**实现这个接口后,前端的心跳检测就能正常工作了!** ✅ - diff --git a/temp_backup/Server_redundant/tempdocs/设备与在线时长接口文档.md b/temp_backup/Server_redundant/tempdocs/设备与在线时长接口文档.md deleted file mode 100644 index 62acc27..0000000 --- a/temp_backup/Server_redundant/tempdocs/设备与在线时长接口文档.md +++ /dev/null @@ -1,106 +0,0 @@ -# 设备与在线时长接口 - -## 概述 -- 基础地址:`http://localhost:8000` -- 版本前缀:`/api/v1` -- 说明:同一账号仅允许一个设备同时在线(依据 `device_id`);后端会记录登录登出并可统计在线时长。 - -## 登录(含单设备限制) -- 方法与路径:`POST /api/v1/auth/login` -- 请求体: -```json -{ - "username": "alice", - "password": "secret123", - "device_id": "devA" -} -``` -- 成功响应: -```json -{ - "access_token": "", - "token_type": "bearer", - "username": "alice" -} -``` -- 失败响应: - - 401:`用户名或密码错误` - - 403:`该账号已在其他设备在线` -- 说明: - - 必须传入稳定的 `device_id`(前端生成并持久化),用于限制并发登录与统计时长 - - 登录成功会记录会话的 `login_at`,并将设备会话标记为活跃 - -## 登出(记录在线时长) -- 方法与路径:`POST /api/v1/auth/logout` -- 请求体: -```json -{ - "username": "alice", - "device_id": "devA" -} -``` -- 成功响应: -```json -{ "detail": "已退出登录" } -``` -- 行为: - - 将对应设备的会话置为非活跃,并记录 `logout_at` - - 若存在 `login_at`,会计算本次会话的在线时长 `duration_seconds`(单位:秒) - -## 在线时长统计 -- 方法与路径:`GET /api/v1/auth/online-time/{username}` -- 成功响应: -```json -{ - "username": "alice", - "total_seconds": 1234, - "active_seconds": 56 -} -``` -- 字段说明: - - `total_seconds`:历史所有已登出会话的累计在线时长(秒) - - `active_seconds`:当前活跃会话的实时在线时长(秒),若无活跃会话则为 0;实时时长基于最近心跳时间 `last_seen_at` 与 `login_at` 的差值 -- 统计逻辑: - - 登录时写入 `login_at`(UTC) - - 登出时写入 `logout_at` 并计算 `duration_seconds` - - 查询时将已登出会话的 `duration_seconds` 累加为 `total_seconds`,并以当前时间与活跃会话的 `login_at` 计算 `active_seconds` - -## 心跳接口(保持在线时长统计) -- 方法与路径:`POST /api/v1/auth/heartbeat` -- 请求体: -```json -{ - "username": "alice", - "device_id": "devA" -} -``` -- 成功响应: -```json -{ "detail": "心跳已更新" } -``` -- 说明: - - 前端应在用户在线期间定期调用心跳(例如每 30~60 秒),以更新会话的 `last_seen_at` - - 若未调用登出而直接关闭应用,在线时长将以最近一次心跳为准,不会无限累计 - -## 错误信息(统一中文) -- 401:`用户名或密码错误` -- 403:`该账号已在其他设备在线` -- 404:`用户不存在` - -## 前端调用示例(Axios) -```ts -import axios from 'axios'; -const API = 'http://localhost:8000/api/v1/auth'; - -export async function login(username: string, password: string, deviceId: string) { - return axios.post(`${API}/login`, { username, password, device_id: deviceId }); -} - -export async function logout(username: string, deviceId: string) { - return axios.post(`${API}/logout`, { username, device_id: deviceId }); -} - -export async function getOnlineTime(username: string) { - return axios.get(`${API}/online-time/${encodeURIComponent(username)}`); -} -``` diff --git a/temp_backup/Server_redundant/tempdocs/邮箱验证与密码重置接口文档.md b/temp_backup/Server_redundant/tempdocs/邮箱验证与密码重置接口文档.md deleted file mode 100644 index df17155..0000000 --- a/temp_backup/Server_redundant/tempdocs/邮箱验证与密码重置接口文档.md +++ /dev/null @@ -1,137 +0,0 @@ -# DesignerCEP 邮箱验证与密码重置接口文档 - -本文档描述了最新的注册验证流程和密码重置流程。 - -## 1. 注册流程 (单表单模式) - -新版注册流程改为在同一个表单中完成:输入邮箱 -> 发送验证码 -> 填写验证码及密码 -> 提交注册。 - -### 1.1 发送注册验证码 -用户输入邮箱后,点击“发送验证码”按钮调用此接口。 - -- **接口地址**: `/api/v1/auth/send-verification-code` -- **请求方式**: `POST` -- **Content-Type**: `application/json` - -**请求参数**: - -```json -{ - "email": "user@example.com" -} -``` - -**响应示例 (成功)**: - -```json -{ - "detail": "验证码已发送" -} -``` - -**响应示例 (失败)**: -- 400 Bad Request: "该邮箱已被注册" -- 500 Internal Server Error: "邮件发送失败: ..." - ---- - -### 1.2 提交注册 -用户填写收到的 6 位数字验证码、用户名、密码后,调用此接口完成注册。 - -- **接口地址**: `/api/v1/auth/register` -- **请求方式**: `POST` -- **Content-Type**: `application/json` - -**请求参数**: - -```json -{ - "username": "myusername", - "email": "user@example.com", - "password": "mypassword123", - "confirm_password": "mypassword123", - "code": "123456", - "device_id": "device_unique_id" -} -``` -*注:`device_id` 为可选,若不传默认为 "unknown_device"* - -**响应示例 (成功)**: - -```json -{ - "access_token": "eyJhbGciOiJIUzI1NiIs...", - "token_type": "bearer", - "username": "myusername" -} -``` - -**响应示例 (失败)**: -- 400 Bad Request: "请先发送验证码" (如果邮箱未先调用发送接口) -- 400 Bad Request: "验证码错误" -- 400 Bad Request: "验证码已过期" -- 400 Bad Request: "用户名已存在" - ---- - -## 2. 找回/重置密码流程 - -密码重置流程改为使用 6 位数字验证码,而非之前的长链接。 - -### 2.1 发送重置验证码 -用户在“忘记密码”页面输入邮箱,点击发送。 - -- **接口地址**: `/api/v1/auth/forgot-password` -- **请求方式**: `POST` -- **Content-Type**: `application/json` - -**请求参数**: - -```json -{ - "email": "user@example.com" -} -``` - -**响应示例**: - -```json -{ - "detail": "如果邮箱存在,重置邮件已发送" -} -``` - ---- - -### 2.2 重置密码 -用户输入收到的 6 位验证码和新密码进行重置。 - -- **接口地址**: `/api/v1/auth/reset-password` -- **请求方式**: `POST` -- **Content-Type**: `application/json` - -**请求参数**: - -```json -{ - "email": "user@example.com", - "token": "123456", - "new_password": "newpassword123", - "confirm_password": "newpassword123" -} -``` -*注:`token` 字段即为邮件中收到的 6 位数字验证码* - -**响应示例 (成功)**: - -```json -{ - "detail": "密码重置成功" -} -``` - -**响应示例 (失败)**: -- 400 Bad Request: "验证码错误" -- 400 Bad Request: "验证码已过期" -- 400 Bad Request: "两次输入的密码不一致" -- 404 Not Found: "用户不存在" diff --git a/temp_backup/Server_redundant/tempdocs/部署前检查清单.md b/temp_backup/Server_redundant/tempdocs/部署前检查清单.md deleted file mode 100644 index 78ee761..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署前检查清单.md +++ /dev/null @@ -1,460 +0,0 @@ -# DesignerCEP 部署前检查清单 - -## ✅ 部署前准备(本地) - -### 前端配置 - -- [ ] 创建 `Designer/.env.production` 文件 - ```env - VITE_API_BASE_URL=https://your-domain.com/api/v1 - VITE_API_SERVER=https://your-domain.com - ``` - -- [ ] 修改 `Designer/src/main.ts` 添加日志控制 - ```typescript - import { logger } from '@/utils/logger'; - - if (import.meta.env.PROD) { - logger.disable(); // 生产环境关闭日志 - } else { - logger.enable(); // 开发环境开启日志 - } - ``` - -- [ ] 检查 `Designer/src/config.ts` 是否使用环境变量 - ```typescript - apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://127.0.0.1:8000/api/v1' - ``` - -- [ ] 测试构建命令 - ```bash - cd Designer - npm run build - ``` - -- [ ] 检查构建产物(应该在 `Designer/dist/` 目录) - - `dist/Shell/` - Shell 登录壳 - - `dist/Designer/` - Core 核心应用 - -### 后端配置 - -- [ ] 创建生产环境配置文件(用于上传到服务器) - ```bash - cp Server/.env.example Server/.env.production - ``` - -- [ ] 修改 `Server/.env.production`: - - [ ] 修改 `SECRET_KEY` 为强随机密钥 - - [ ] 设置 `DEBUG=False` - - [ ] 配置 `ALLOWED_ORIGINS`(你的域名) - - [ ] 配置数据库连接(如使用 PostgreSQL/MySQL) - -- [ ] 检查 `Server/requirements.txt` 包含所有依赖 - -- [ ] 打包 Shell(供用户下载) - ```bash - cd Designer/dist - zip -r shell-1.0.0.zip Shell/ - # 将 shell-1.0.0.zip 准备上传到服务器 - ``` - ---- - -## 🖥️ 服务器准备 - -### 基础环境 - -- [ ] 服务器已购买(推荐:阿里云、腾讯云、AWS) -- [ ] 操作系统:Ubuntu 20.04+ 或 CentOS 7+ -- [ ] 配置:最低 1核2G,推荐 2核4G -- [ ] 已安装 Python 3.9+ - ```bash - python3 --version - ``` -- [ ] 已安装 Nginx - ```bash - nginx -v - ``` -- [ ] 已安装 Git - ```bash - git --version - ``` - -### 域名和 SSL - -- [ ] 域名已购买 -- [ ] DNS 已解析到服务器 IP - ```bash - # 验证 DNS 解析 - ping your-domain.com - ``` -- [ ] 准备申请 SSL 证书(Let's Encrypt 免费) - -### 网络配置 - -- [ ] 服务器防火墙已开放端口: - - [ ] 22 (SSH) - - [ ] 80 (HTTP) - - [ ] 443 (HTTPS) - -- [ ] 安全组规则已配置(云服务器) - ---- - -## 📤 文件上传 - -### 上传后端代码 - -- [ ] 方式 1: 使用 Git(推荐) - ```bash - ssh user@your-server - cd /var/www - git clone https://your-repo-url.git DesignerCEP - ``` - -- [ ] 方式 2: 使用 SCP - ```bash - scp -r Server/ user@your-server:/var/www/DesignerCEP/ - ``` - -### 上传前端构建产物 - -- [ ] 上传 Shell 在线登录页 - ```bash - scp -r Designer/dist/Shell/* \ - user@your-server:/var/www/DesignerCEP/Server/static/shell/ - ``` - -- [ ] 上传 Core(核心应用) - ```bash - scp -r Designer/dist/Designer/* \ - user@your-server:/var/www/DesignerCEP/Server/static/core/1.0.0/ - ``` - -- [ ] 打包并上传 Shell(供 CEP 扩展下载) - ```bash - # 本地打包 - cd Designer/dist - zip -r shell-1.0.0.zip Shell/ - - # 上传到服务器 - scp shell-1.0.0.zip \ - user@your-server:/var/www/DesignerCEP/Server/static/downloads/ - ``` - ---- - -## 🔧 服务器配置 - -### Python 环境 - -- [ ] 创建虚拟环境 - ```bash - cd /var/www/DesignerCEP/Server - python3 -m venv venv - source venv/bin/activate - ``` - -- [ ] 安装依赖 - ```bash - pip install -r requirements.txt - pip install gunicorn uvicorn[standard] - ``` - -### 环境变量 - -- [ ] 上传 `.env.production` 并重命名为 `.env` - ```bash - scp Server/.env.production user@your-server:/var/www/DesignerCEP/Server/.env - ``` - -- [ ] 验证配置 - ```bash - cat /var/www/DesignerCEP/Server/.env - ``` - -### 目录结构 - -- [ ] 验证目录结构正确 - ``` - /var/www/DesignerCEP/Server/ - ├── app/ - ├── static/ - │ ├── shell/ # Shell 在线登录页 - │ │ ├── index.html - │ │ └── assets/ - │ ├── downloads/ # 下载文件 - │ │ └── shell-1.0.0.zip - │ └── core/ - │ └── 1.0.0/ - │ ├── index.html - │ └── assets/ - ├── .env - ├── requirements.txt - └── venv/ - ``` - -- [ ] 创建日志目录 - ```bash - mkdir -p /var/www/DesignerCEP/Server/logs - ``` - -### Systemd 服务 - -- [ ] 创建服务文件 - ```bash - sudo nano /etc/systemd/system/designer-cep.service - ``` - -- [ ] 启动服务 - ```bash - sudo systemctl daemon-reload - sudo systemctl start designer-cep - sudo systemctl enable designer-cep - ``` - -- [ ] 验证服务状态 - ```bash - sudo systemctl status designer-cep - ``` - -### Nginx 配置 - -- [ ] 创建 Nginx 配置文件 - ```bash - sudo nano /etc/nginx/sites-available/designer-cep - ``` - -- [ ] 启用配置 - ```bash - sudo ln -s /etc/nginx/sites-available/designer-cep /etc/nginx/sites-enabled/ - ``` - -- [ ] 测试 Nginx 配置 - ```bash - sudo nginx -t - ``` - -- [ ] 重启 Nginx - ```bash - sudo systemctl restart nginx - ``` - -### SSL 证书 - -- [ ] 安装 Certbot - ```bash - sudo apt install certbot python3-certbot-nginx - ``` - -- [ ] 申请证书 - ```bash - sudo certbot --nginx -d your-domain.com -d www.your-domain.com - ``` - -- [ ] 验证自动续期 - ```bash - sudo certbot renew --dry-run - ``` - ---- - -## 🧪 测试验证 - -### 后端 API 测试 - -- [ ] 健康检查 - ```bash - curl https://your-domain.com/api/v1/health - ``` - -- [ ] 登录接口 - ```bash - curl -X POST https://your-domain.com/api/v1/client/login \ - -H "Content-Type: application/json" \ - -d '{"username":"test","password":"test123","device_id":"test-device"}' - ``` - -### 前端访问测试 - -- [ ] 访问 Shell 在线登录页 - ``` - https://your-domain.com/shell/ - 或 - https://your-domain.com/shell/index.html - ``` - -- [ ] 访问 Core 首页 - ``` - https://your-domain.com/core/1.0.0/index.html - ``` - -- [ ] 检查静态资源加载(F12 查看 Network) - -- [ ] Shell 下载链接(供 CEP 扩展下载) - ``` - https://your-domain.com/downloads/shell-1.0.0.zip - ``` - -### 功能测试 - -- [ ] 用户注册功能 -- [ ] 用户登录功能 -- [ ] 自动登录功能 -- [ ] 版本检查和更新 -- [ ] Photoshop 插件功能(创建图层等) -- [ ] 退出登录功能 - -### 性能测试 - -- [ ] 页面加载速度 - ```bash - curl -w "@curl-format.txt" -o /dev/null -s https://your-domain.com/core/1.0.0/ - ``` - -- [ ] API 响应时间 - -- [ ] 并发测试(可选) - ```bash - ab -n 1000 -c 10 https://your-domain.com/api/v1/health - ``` - ---- - -## 🔒 安全检查 - -- [ ] 防火墙已启用 - ```bash - sudo ufw status - ``` - -- [ ] 仅开放必要端口(22, 80, 443) - -- [ ] `SECRET_KEY` 已修改为强随机值 - -- [ ] `DEBUG=False` 已设置 - -- [ ] CORS 配置正确(`ALLOWED_ORIGINS`) - -- [ ] 数据库密码强度检查(如使用数据库) - -- [ ] 文件权限检查 - ```bash - # .env 文件应该仅所有者可读 - chmod 600 /var/www/DesignerCEP/Server/.env - ``` - -- [ ] 定期更新系统和依赖 - ```bash - sudo apt update && sudo apt upgrade - ``` - ---- - -## 📊 监控配置(可选) - -- [ ] 配置日志轮转 - ```bash - sudo nano /etc/logrotate.d/designer-cep - ``` - -- [ ] 设置系统监控(推荐工具) - - [ ] Prometheus + Grafana - - [ ] Zabbix - - [ ] Datadog - -- [ ] 配置错误追踪(推荐) - - [ ] Sentry - - [ ] Bugsnag - -- [ ] 配置服务告警(推荐) - - [ ] 邮件告警 - - [ ] 短信告警 - - [ ] 企业微信/钉钉告警 - ---- - -## 📝 文档和备份 - -- [ ] 记录服务器信息 - - 服务器 IP: __________________ - - SSH 用户名: __________________ - - SSH 密钥位置: __________________ - - 域名: __________________ - -- [ ] 记录部署信息 - - 部署日期: __________________ - - 当前版本: __________________ - - 数据库位置: __________________ - -- [ ] 设置定期备份 - - [ ] 数据库备份(每天) - - [ ] 配置文件备份 - - [ ] 用户数据备份 - -- [ ] 编写故障恢复文档 - ---- - -## 🎉 上线后操作 - -- [ ] 通知用户新版本上线 - -- [ ] 更新 CEP 插件配置(如需要) - - 修改 API 地址指向生产环境 - -- [ ] 监控服务器资源使用情况 - ```bash - htop - df -h - ``` - -- [ ] 检查错误日志 - ```bash - sudo journalctl -u designer-cep -f - sudo tail -f /var/log/nginx/designer-cep-error.log - ``` - -- [ ] 第一周密切关注系统运行状况 - ---- - -## 🆘 应急预案 - -### 服务无法访问 - -1. 检查服务状态 - ```bash - sudo systemctl status designer-cep - sudo systemctl status nginx - ``` - -2. 查看错误日志 - ```bash - sudo journalctl -u designer-cep -n 100 --no-pager - ``` - -3. 重启服务 - ```bash - sudo systemctl restart designer-cep - sudo systemctl restart nginx - ``` - -### 回滚到上一版本 - -1. 切换 Core 版本(修改后端 API 返回的版本号) - -2. 或直接替换静态文件 - ```bash - rm -rf /var/www/DesignerCEP/Server/static/core/1.0.1 - # 恢复旧版本 - ``` - -3. 重启服务 - ---- - -**检查完成日期**: _______________ -**检查人**: _______________ -**备注**: _______________ - diff --git a/temp_backup/Server_redundant/tempdocs/部署功能使用说明.md b/temp_backup/Server_redundant/tempdocs/部署功能使用说明.md deleted file mode 100644 index df036de..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署功能使用说明.md +++ /dev/null @@ -1,263 +0,0 @@ -# 前端 App 部署功能使用说明 - -## 📦 功能概述 - -新增的部署功能可以将已构建好的 `dist_core` 目录部署到服务器 `/var/www/app/`,并提供完整的版本历史管理和回滚功能。 - ---- - -## 🚀 使用流程 - -### 1. 准备工作 - -#### 1.1 安装依赖 -```bash -cd AdminTool -pip install -r requirements.txt -``` - -确保已安装: -- `PyQt5` - GUI 界面 -- `paramiko` - SSH 连接 -- `pymysql` - MySQL 数据库 -- `requests` - API 请求 - -#### 1.2 配置服务器信息 - -编辑 `AdminTool/deploy_config.json`: -```json -{ - "host": "103.97.201.136", - "port": "22", - "username": "root", - "password": "你的密码", - "remote_path": "/var/www/app", - "mysql": { - "host": "localhost", - "port": "3306", - "username": "designer_user", - "password": "DesignerPass123!", - "database": "designer_db" - } -} -``` - -#### 1.3 构建前端 - -**在部署前,请先手动构建前端:** -```bash -cd Designer -npm run build:core -``` - -构建完成后会生成 `Designer/dist_core/` 目录。 - ---- - -### 2. 启动管理工具 - -```bash -cd AdminTool -python admin_gui.py -``` - -打开后切换到 **"自动化部署"** 标签页。 - ---- - -### 3. 部署新版本 - -#### 步骤: - -1. **选择 dist_core 目录** - - 点击 "浏览..." 按钮 - - 选择 `Designer/dist_core` 目录 - -2. **添加备注(可选)** - - 例如:`修复主题同步bug`、`新增管理后台功能` - -3. **点击 "🚀 部署到服务器"** - - 系统会: - - 自动生成时间戳版本号(如 `20231220_153045`) - - 备份当前运行版本到 `/var/www/app_versions/backup_XXXXXX/` - - 清空 `/var/www/app/` - - 上传新版本 - - 保存版本到 `/var/www/app_versions/20231220_153045/` - - 记录到 MySQL 数据库 - -4. **查看部署日志** - - 底部日志区域会实时显示进度 - - 部署成功后会弹出提示 - ---- - -### 4. 查看版本历史 - -部署成功后,版本会自动显示在 **"版本历史管理"** 表格中: - -| 版本号 | 部署时间 | 大小(MB) | 备注 | 状态 | -|--------|----------|----------|------|------| -| 20231220_153045 | 2023-12-20 15:30:45 | 12.5 | 修复主题同步bug | ✅ 当前 | -| 20231220_102030 | 2023-12-20 10:20:30 | 12.3 | 初始版本 | | - -- **绿色 "✅ 当前"** 表示正在服务器上运行的版本 -- 点击 **"🔄 刷新列表"** 可手动刷新 - ---- - -### 5. 回滚到历史版本 - -如果新版本有问题,可以快速回滚: - -1. **选择要回滚的版本** - - 在表格中点击某个历史版本 - -2. **点击 "⏪ 回滚到选中版本"** - - 确认对话框会显示版本信息 - -3. **确认回滚** - - 系统会: - - 备份当前版本 - - 从 `/var/www/app_versions/` 复制选中版本到 `/var/www/app/` - - 更新数据库 - -4. **刷新页面** - - 访问 `https://app.aidg168.uk/` 查看回滚结果 - ---- - -### 6. 删除历史版本 - -如果某个版本不再需要: - -1. **选择要删除的版本** -2. **点击 "🗑️ 删除选中版本"** -3. **确认删除** - - 会同时删除: - - 数据库记录 - - 服务器文件 `/var/www/app_versions/XXXXXX/` - -**注意**: -- ❌ 无法删除当前正在使用的版本 -- ⚠️ 删除操作不可恢复 - ---- - -## 📁 服务器目录结构 - -``` -/var/www/ -├── app/ ← 当前运行版本(Caddy 直接访问) -│ ├── index.html -│ ├── assets/ -│ └── ... -│ -└── app_versions/ ← 版本历史存档 - ├── 20231220_153045/ ← 版本 1 - ├── 20231220_164522/ ← 版本 2 - ├── backup_20231221_092301/ ← 自动备份 - └── ... -``` - ---- - -## 🗄️ 数据库表结构 - -**表名**:`app_deployments` - -```sql -CREATE TABLE app_deployments ( - id INT PRIMARY KEY AUTO_INCREMENT, - version VARCHAR(50) UNIQUE NOT NULL, -- 版本号(时间戳) - deployed_at DATETIME NOT NULL, -- 部署时间 - is_current BOOLEAN DEFAULT FALSE, -- 是否当前版本 - file_size_mb DECIMAL(10, 2), -- 文件大小(MB) - comment VARCHAR(500), -- 备注 - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -``` - ---- - -## ❓ 常见问题 - -### Q1: 部署后需要重启 Caddy 吗? -**A**: 通常不需要。Caddy 会自动读取 `/var/www/app/` 中的新文件。但如果页面没更新,可以尝试: -```bash -ssh root@your-server -systemctl restart caddy -``` - -### Q2: 如果数据库连接失败怎么办? -**A**: 检查 `deploy_config.json` 中的 MySQL 配置: -- 主机地址(`host`) -- 端口(`port`) -- 用户名和密码 -- 数据库名(`database`) - -### Q3: 如何查看服务器上的实际文件? -**A**: 使用 SSH 登录: -```bash -ssh root@103.97.201.136 -cd /var/www/app -ls -lh -``` - -### Q4: 部署失败后如何恢复? -**A**: 如果部署中断: -1. 进入 GUI 的"版本历史管理" -2. 选择上一个稳定版本 -3. 点击"回滚" - -### Q5: 可以同时部署到多个服务器吗? -**A**: 当前版本不支持。如需要,可以: -- 修改服务器配置 -- 重新部署 - ---- - -## 🛠️ 技术细节 - -### 版本号生成规则 -- 格式:`YYYYMMDD_HHMMSS` -- 示例:`20231220_153045` = 2023年12月20日 15:30:45 -- 自动生成,无需手动输入 - -### 备份机制 -- **部署新版本时**:自动备份当前版本为 `backup_{timestamp}` -- **回滚时**:自动备份当前版本 -- 备份存储在 `/var/www/app_versions/` - -### 上传方式 -- 使用 SFTP(基于 SSH) -- 递归上传整个目录 -- 实时显示上传进度 - ---- - -## ⚠️ 注意事项 - -1. **部署前务必构建** - - 必须先运行 `npm run build:core` - - 确保 `dist_core/` 目录存在且完整 - -2. **生产环境谨慎操作** - - 部署会直接替换线上版本 - - 建议先在测试环境验证 - -3. **保留足够历史版本** - - 建议至少保留 3-5 个历史版本 - - 便于快速回滚 - -4. **定期清理旧版本** - - 旧版本会占用服务器空间 - - 定期删除不再需要的版本 - ---- - -## 📞 支持 - -如有问题,请联系开发者或查看: -- [AdminTool/README.md](./README.md) -- [项目文档](../README.md) - diff --git a/temp_backup/Server_redundant/tempdocs/部署工具使用.md b/temp_backup/Server_redundant/tempdocs/部署工具使用.md deleted file mode 100644 index 4a435d2..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署工具使用.md +++ /dev/null @@ -1,129 +0,0 @@ -# 🚀 部署工具 - 快速使用指南 - -## ⚡ 快速启动 - -### 方式 1:直接启动部署工具(推荐) -```bash -cd AdminTool -python deploy_tool.py -``` -**自动跳转到部署功能,忽略后端 API 错误** - -### 方式 2:完整管理工具 -```bash -cd AdminTool -python admin_gui.py -``` -手动切换到「自动化部署」标签页 - ---- - -## 📦 完整部署流程 - -### 1️⃣ 构建前端 -```bash -cd D:\main\DesignerCEP\Designer -npm run build:core -``` -等待构建完成,生成 `dist_core/` 目录 - -### 2️⃣ 启动部署工具 -```bash -cd D:\main\DesignerCEP\AdminTool -python deploy_tool.py -``` - -### 3️⃣ 配置服务器(首次使用) -在「服务器配置」区域: -- 服务器地址:`103.97.201.136` -- SSH 端口:`22` -- 用户名:`root` -- 密码:`***`(填入实际密码) - -点击「保存配置」 - -### 4️⃣ 部署 -在「部署新版本」区域: -1. 点击「浏览...」选择 `Designer/dist_core` 目录 -2. 输入备注(可选):例如 `修复主题同步bug` -3. 点击 **「🚀 部署到服务器」** - -### 5️⃣ 等待完成 -部署日志会实时显示进度: -- ✅ 连接服务器 -- ✅ 备份当前版本 -- ✅ 上传新版本 -- ✅ 保存版本历史 -- ✅ 更新记录 - -完成后访问:https://app.aidg168.uk/ - ---- - -## 🔄 版本回滚 - -如果新版本有问题: - -1. 在「版本历史管理」表格中查看所有版本 -2. 点击要回滚的版本(表格行) -3. 点击 **「⏪ 回滚到选中版本」** -4. 确认操作 -5. 刷新网站验证 - ---- - -## ⚠️ 常见问题 - -### Q: 启动时出现 "500 Server Error" 或 "获取组列表失败"? -**A**: 这是正常的,可以忽略! -- 这个错误来自后端 API(组管理功能) -- **不影响部署功能** -- 部署功能完全独立,使用 SSH 直接操作服务器 -- 建议使用 `deploy_tool.py` 启动,自动跳过这个错误 - -### Q: 如何确认部署成功? -**A**: -1. 查看部署日志,最后应显示「🎉 部署完成!」 -2. 访问 https://app.aidg168.uk/ 验证 -3. 版本历史列表会显示新版本(带 ✅ 当前标记) - -### Q: 部署需要多久? -**A**: 通常 1-2 分钟,取决于: -- 文件大小(dist_core 约 10-15MB) -- 网络速度 - -### Q: 可以删除旧版本吗? -**A**: 可以,但注意: -- ❌ 无法删除当前正在使用的版本 -- 建议保留 3-5 个最近的版本用于回滚 - ---- - -## 🎯 部署前检查清单 - -- [ ] 已运行 `npm run build:core` -- [ ] `Designer/dist_core/` 目录存在 -- [ ] 服务器 SSH 配置正确 -- [ ] 已点击「测试连接」验证 - ---- - -## 📞 技术支持 - -- 详细文档:[部署功能使用说明.md](./部署功能使用说明.md) -- 修复说明:[修复说明.md](./修复说明.md) -- 测试系统:`python test_version_system.py` - ---- - -## 💡 提示 - -1. **后端 API 错误不影响部署** - 部署功能完全独立 -2. **首次使用建议测试** - 先部署一个测试版本熟悉流程 -3. **保留历史版本** - 方便快速回滚 -4. **非高峰期部署** - 避免影响线上用户 - ---- - -**开始使用:`python deploy_tool.py`** 🚀 - diff --git a/temp_backup/Server_redundant/tempdocs/部署指南.md b/temp_backup/Server_redundant/tempdocs/部署指南.md deleted file mode 100644 index e2bce85..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署指南.md +++ /dev/null @@ -1,251 +0,0 @@ -# 🚀 DesignerCEP 完整部署指南 - -## 📊 最终架构 - -``` -app.aidg168.uk → 前端应用(Caddy 静态文件) -backend.aidg168.uk → 后端 API(FastAPI + MySQL) -``` - ---- - -## 📁 项目目录结构 - -``` -DesignerCEP/ -│ -├── Designer/ ← 前端源代码 -│ ├── src/ ← Vue 源码 -│ ├── dist_core/ ← ⭐ 构建输出(需要复制到 Server) -│ ├── package.json -│ └── vite.config.ts -│ -├── Server/ ← 后端 + 部署配置 -│ ├── app/ ← 后端代码(FastAPI) -│ │ ├── api/ ← API 路由 -│ │ ├── models/ ← 数据模型 -│ │ └── main.py ← 入口文件 -│ │ -│ ├── static/ ← ⭐ 前端文件放这里 -│ │ └── app/ ← ⭐ Designer/dist_core/ 复制到这里 -│ │ ├── index.html -│ │ ├── assets/ -│ │ └── ... -│ │ -│ ├── archives/ ← Core 版本压缩包 -│ ├── docker-compose.yml ← Docker 配置 -│ ├── Dockerfile ← 后端镜像 -│ ├── requirements.txt ← Python 依赖 -│ └── mysql.cnf ← MySQL 配置 -│ -├── Caddyfile ← Caddy 配置 -└── AdminTool/ ← 自动化部署工具 -``` - ---- - -## 🔧 本地准备(您现在要做的) - -### 步骤 1:构建前端 - -```bash -cd Designer -npm install -npm run build:core -``` - -**输出**:`Designer/dist_core/` 目录 - -### 步骤 2:复制前端到 Server - -```powershell -# 在项目根目录执行 -xcopy /E /Y Designer\dist_core\* Server\static\app\ -``` - -**验证**: -```bash -dir Server\static\app\ -# 应该看到: -# - index-core.html -# - assets/ -# - CSInterface.js -# - vite.svg -``` - -### 步骤 3:配置环境变量 - -复制 `Server/.env.example` 为 `Server/.env`,并修改: - -```env -ENV=production -SECRET_KEY=修改为随机密钥 -ALLOWED_ORIGINS=https://app.aidg168.uk,https://backend.aidg168.uk -SMTP_USER=您的邮箱 -SMTP_PASSWORD=您的邮箱密码 -``` - ---- - -## 📤 上传到服务器 - -### 方法 A:打包上传(推荐) - -```powershell -# 1. 压缩 Server 文件夹 -Compress-Archive -Path Server\* -DestinationPath DesignerCEP-Server.zip - -# 2. 上传到服务器 -scp DesignerCEP-Server.zip root@103.97.201.136:/root/ - -# 3. 上传 Caddyfile -scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile -``` - -### 方法 B:使用自动化脚本 - -```bash -cd AdminTool -python auto_deploy_core.py --version 1.0.0 --deploy -``` - ---- - -## 🐳 服务器部署 - -### SSH 登录服务器 - -```bash -ssh root@103.97.201.136 -``` - -### 步骤 1:解压文件 - -```bash -cd /root -unzip DesignerCEP-Server.zip -d /var/www/DesignerCEP/Server -cd /var/www/DesignerCEP/Server -``` - -### 步骤 2:配置 Caddy - -```bash -# Caddyfile 已上传到 /etc/caddy/Caddyfile - -# 验证配置 -caddy validate --config /etc/caddy/Caddyfile - -# 重启 Caddy -systemctl restart caddy -systemctl status caddy -``` - -### 步骤 3:启动 Docker 服务 - -```bash -cd /var/www/DesignerCEP/Server - -# 启动所有服务(Caddy + FastAPI + MySQL) -docker-compose up -d - -# 查看日志 -docker-compose logs -f - -# 查看运行状态 -docker-compose ps -``` - ---- - -## ✅ 验证部署 - -### 1. 检查服务状态 - -```bash -# Caddy -systemctl status caddy - -# Docker 服务 -docker-compose ps -``` - -### 2. 测试 API - -```bash -curl https://backend.aidg168.uk/health -# 期望:{"status":"healthy"} -``` - -### 3. 测试前端 - -浏览器访问: -``` -https://app.aidg168.uk/ -``` - -**期望**:能看到登录页面 - ---- - -## 📋 完整部署清单 - -- [ ] 前端已构建:`Designer/dist_core/` -- [ ] 前端已复制到:`Server/static/app/` -- [ ] Server 文件夹已打包 -- [ ] Caddyfile 已上传到服务器 -- [ ] Server 已上传并解压 -- [ ] `.env` 已配置 -- [ ] Caddy 已重启 -- [ ] Docker 服务已启动 -- [ ] `https://app.aidg168.uk/` 可访问 -- [ ] `https://backend.aidg168.uk/health` 可访问 - ---- - -## 🎯 快速命令汇总 - -### 本地准备 - -```powershell -# 1. 构建前端 -cd Designer -npm run build:core - -# 2. 复制前端到 Server -cd .. -xcopy /E /Y Designer\dist_core\* Server\static\app\ - -# 3. 检查文件 -dir Server\static\app\ - -# 4. 打包 Server -Compress-Archive -Path Server\* -DestinationPath Server.zip -``` - -### 服务器部署 - -```bash -# 1. 上传文件 -scp Server.zip root@103.97.201.136:/root/ -scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile - -# 2. SSH 登录 -ssh root@103.97.201.136 - -# 3. 解压并部署 -cd /root -unzip Server.zip -d /var/www/DesignerCEP/Server -cd /var/www/DesignerCEP/Server - -# 4. 启动服务 -systemctl restart caddy -docker-compose up -d - -# 5. 查看日志 -docker-compose logs -f -``` - ---- - -**完成后访问 https://app.aidg168.uk/ 测试!** 🎉 - diff --git a/temp_backup/Server_redundant/tempdocs/部署文档_积分VIP签到系统.md b/temp_backup/Server_redundant/tempdocs/部署文档_积分VIP签到系统.md deleted file mode 100644 index f1c29b8..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署文档_积分VIP签到系统.md +++ /dev/null @@ -1,383 +0,0 @@ -# DesignerCEP 完整功能部署文档 - -## 📋 更新内容 - -### 1. 后端新增功能 ✅ - -#### 1.1 数据库迁移 -- **文件位置**: `Server/migrations/001_add_points_vip_checkin.sql` -- **执行方式**: - ```bash - mysql -u root -p designercep < Server/migrations/001_add_points_vip_checkin.sql - ``` -- **内容**: - - 扩展users表(添加积分、VIP、签到字段) - - 创建功能配置表(features_config) - - 创建VIP配置表(vip_config) - - 创建签到配置表(check_in_config) - - 创建签到记录表(check_in_records) - - 创建积分历史表(points_history) - - 创建功能使用日志表(feature_usage_logs) - -#### 1.2 新增API接口 - -**管理员配置接口** (`Server/app/api/v1/admin_config.py`): -- `GET /api/v1/admin/config/features` - 获取所有功能配置 -- `POST /api/v1/admin/config/features` - 新增功能配置 -- `PUT /api/v1/admin/config/features/{feature_key}` - 更新功能配置 -- `DELETE /api/v1/admin/config/features/{feature_key}` - 删除功能配置 -- `GET /api/v1/admin/config/vip` - 获取VIP配置 -- `PUT /api/v1/admin/config/vip/{vip_type}` - 更新VIP配置 -- `GET /api/v1/admin/config/checkin` - 获取签到配置 -- `POST /api/v1/admin/config/checkin` - 新增签到档位 -- `PUT /api/v1/admin/config/checkin/{consecutive_days}` - 更新签到档位 -- `DELETE /api/v1/admin/config/checkin/{consecutive_days}` - 删除签到档位 - -**通用功能使用接口** (`Server/app/api/v1/feature.py`): -- `POST /api/v1/feature/use` - 使用功能(核心业务逻辑) - -**签到接口** (`Server/app/api/v1/checkin.py`): -- `POST /api/v1/checkin/daily` - 每日签到 -- `GET /api/v1/checkin/status` - 获取签到状态 -- `GET /api/v1/checkin/calendar/{year}/{month}` - 获取签到日历 -- `GET /api/v1/checkin/history` - 签到记录 - -**用户资料接口** (`Server/app/api/v1/user_profile.py`): -- `GET /api/v1/user/profile` - 获取用户资料 -- `PUT /api/v1/user/profile` - 更新用户资料 -- `GET /api/v1/points/history` - 积分历史 - -**统计接口** (`Server/app/api/v1/stats.py`): -- `GET /api/v1/admin/stats/today` - 今日统计 -- `GET /api/v1/admin/stats/feature-usage` - 功能使用排行 -- `GET /api/v1/admin/stats/points-trend` - 积分趋势统计 - -### 2. 前端新增页面 ✅ - -#### 2.1 HomePage(首页) -- **文件**: `Designer/src/view/HomePage.vue` -- **功能**: - - 欢迎区(显示昵称、问候语) - - 快捷信息卡片(积分、连续签到、VIP状态) - - 功能网格(展示所有可用功能) - - 快捷入口(签到、个人中心、工作台) - - 点击功能卡片直接使用功能 - -#### 2.2 Profile(个人中心) -- **文件**: `Designer/src/view/Profile.vue` -- **功能**: - - 用户头像和基本信息展示 - - 统计数据卡片(积分、累计签到、连续签到、VIP到期) - - 编辑资料功能(昵称、头像、邮箱) - - 积分历史记录(带类型筛选) - - 分页展示 - -#### 2.3 CheckIn(签到) -- **文件**: `Designer/src/view/CheckIn.vue` -- **功能**: - - 签到主卡片(显示状态、连续天数、累计天数) - - 立即签到按钮 - - 签到奖励规则展示 - - 签到日历(显示本月签到情况) - - 签到历史记录 - -#### 2.4 路由更新 -- **文件**: `Designer/src/router/index.ts` -- 默认重定向到 `/home/index`(首页) -- 新增 `/home/profile` 路由 -- 新增 `/home/checkin` 路由 - ---- - -## 🚀 部署步骤 - -### 步骤 1: 数据库迁移 - -```bash -# 连接到MySQL -mysql -u root -p - -# 选择数据库 -use designercep; - -# 执行迁移脚本 -source d:\main\DesignerCEP\Server\migrations\001_add_points_vip_checkin.sql; - -# 验证表是否创建成功 -show tables; - -# 检查users表新增字段 -desc users; -``` - -### 步骤 2: 后端部署 - -```bash -# 进入后端目录 -cd d:\main\DesignerCEP\Server - -# 确保依赖已安装 -pip install pymysql - -# 重启后端服务 -# 如果使用Docker: -cd .. -docker-compose restart backend - -# 如果直接运行: -python -m app.main -``` - -### 步骤 3: 前端部署 - -```bash -# 进入前端目录 -cd d:\main\DesignerCEP\Designer - -# 安装依赖(如有新增) -npm install - -# 构建 -npm run build - -# 如果需要实时调试 -npm run dev -``` - -### 步骤 4: 验证部署 - -1. **访问后端健康检查**: - ```bash - curl https://backend.aidg168.uk/health - ``` - -2. **测试新增API**: - ```bash - # 测试签到状态 - curl "https://backend.aidg168.uk/api/v1/checkin/status?username=testuser" - - # 测试功能配置 - curl -H "x-admin-token: admin-secret-token" https://backend.aidg168.uk/api/v1/admin/config/features - ``` - -3. **前端验证**: - - 打开 https://app.aidg168.uk - - 登录后应该看到新的首页 - - 检查「个人中心」和「每日签到」页面 - ---- - -## 📊 核心业务逻辑说明 - -### 功能使用流程 - -``` -用户点击功能 → POST /api/v1/feature/use - ↓ -检查功能配置(是否启用) - ↓ -检查用户VIP类型 - ├─ SVIP: 免费使用(如果svip_points_cost=0) - ├─ VIP: 优先扣配额,配额不足扣积分 - └─ 普通: 扣除积分 - ↓ -记录使用日志 - ↓ -返回结果(剩余积分/配额) -``` - -### 签到逻辑 - -``` -用户签到 → POST /api/v1/checkin/daily - ↓ -检查今日是否已签到 - ↓ -计算连续天数(昨天签到则+1,否则归零) - ↓ -从配置表获取对应档位奖励 - ↓ -应用VIP倍数(VIP×1.5, SVIP×2.0) - ↓ -更新用户积分和签到数据 - ↓ -记录签到日志和积分历史 -``` - ---- - -## 🔧 配置管理 - -### 功能配置示例 - -```sql --- 查看现有功能 -SELECT * FROM features_config; - --- 新增功能 -INSERT INTO features_config -(feature_key, feature_name, category, points_cost, vip_points_cost, svip_points_cost, description) -VALUES -('new_feature', '新功能', 'ai', 60, 0, 0, '这是一个新功能'); - --- 更新功能价格 -UPDATE features_config -SET points_cost = 80 -WHERE feature_key = 'ai_color_match'; - --- 禁用功能 -UPDATE features_config -SET enabled = 0 -WHERE feature_key = 'batch_export'; -``` - -### VIP配置示例 - -```sql --- 查看VIP配置 -SELECT * FROM vip_config; - --- 修改VIP价格 -UPDATE vip_config -SET price = 35.00, daily_quota = 25 -WHERE vip_type = 'vip'; -``` - -### 签到配置示例 - -```sql --- 查看签到配置 -SELECT * FROM check_in_config ORDER BY consecutive_days; - --- 新增签到档位 -INSERT INTO check_in_config -(consecutive_days, base_points, bonus_points, total_points) -VALUES (60, 10, 150, 160); -``` - ---- - -## 🧪 测试清单 - -### 后端API测试 - -- [ ] 功能配置CRUD全流程 -- [ ] VIP配置更新 -- [ ] 签到配置更新 -- [ ] 用户签到(首次、连续、中断) -- [ ] 功能使用(普通用户、VIP、SVIP) -- [ ] 用户资料获取和更新 -- [ ] 积分历史查询 -- [ ] 统计接口 - -### 前端UI测试 - -- [ ] 首页展示正常 -- [ ] 功能卡片点击使用 -- [ ] 个人中心数据展示 -- [ ] 编辑资料功能 -- [ ] 积分历史分页 -- [ ] 签到主流程 -- [ ] 签到日历显示 -- [ ] 路由跳转正常 - ---- - -## ⚠️ 注意事项 - -### 1. 配置化原则 -- ❌ **严禁硬编码业务规则** -- ✅ **所有价格、奖励、配额从数据库读取** -- ✅ **通过管理后台修改配置即时生效** - -### 2. 数据库连接 -- 确保 `Server/app/core/database.py` 的连接配置正确 -- 建议使用环境变量配置数据库信息 - -### 3. 权限验证 -- 管理员接口需要 `x-admin-token` header -- 用户接口需要 `Authorization: Bearer {token}` header - -### 4. 日志规范 -- 所有代码必须使用 `logger` 而非 `console.log` -- 生产环境关闭日志: `logger.disable()` - ---- - -## 📝 后续优化建议 - -### AdminTool Fluent Design 改造 -由于用户要求"算了,你全部搞完吧",AdminTool的Fluent Design改造暂时跳过,因为: -1. 需要安装新的Python依赖(qfluentwidgets) -2. 需要大规模重构现有代码 -3. 后端功能和前端功能已全部完成,可以正常使用 - -**如需改造,请参考文档第2部分的代码框架进行开发。** - ---- - -## ✅ 完成清单 - -- [x] 数据库迁移SQL -- [x] 后端API(5个文件) -- [x] 路由注册 -- [x] 前端HomePage -- [x] 前端Profile -- [x] 前端CheckIn -- [x] 路由配置 -- [x] 删除测试代码 -- [x] 生成部署文档 - ---- - -## 🎯 使用流程 - -### 用户视角 - -1. **登录** → 进入新首页 -2. **首页**: - - 查看积分和VIP状态 - - 点击功能卡片使用功能 - - 快捷跳转签到/个人中心 -3. **签到**: - - 每日签到获得积分 - - 查看签到日历和历史 -4. **个人中心**: - - 查看详细统计数据 - - 编辑个人资料 - - 查看积分历史 - -### 管理员视角 - -1. **使用AdminTool管理工具**: - - 管理用户组 - - 发布版本 - - 自动化部署 -2. **通过API管理配置**: - - 调整功能价格 - - 修改VIP权益 - - 设置签到奖励 -3. **查看统计数据**: - - 今日活跃情况 - - 功能使用排行 - - 积分趋势分析 - ---- - -## 📞 技术支持 - -如遇问题,请检查: -1. 数据库是否正确迁移 -2. 后端服务是否正常运行 -3. 前端是否正确构建 -4. API地址配置是否正确 -5. 浏览器控制台是否有错误 - -查看日志: -- 后端: `docker-compose logs backend` -- 前端: 浏览器开发者工具 Console - ---- - -**部署完成!🎉** - diff --git a/temp_backup/Server_redundant/tempdocs/部署架构说明.md b/temp_backup/Server_redundant/tempdocs/部署架构说明.md deleted file mode 100644 index 5f7c5ed..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署架构说明.md +++ /dev/null @@ -1,333 +0,0 @@ -# DesignerCEP 部署架构说明 - -## 📐 整体架构 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ 用户设备 │ -│ ┌────────────────────────────────────────────────────────┐ │ -│ │ Adobe Photoshop + CEP 扩展 │ │ -│ │ ┌──────────────────────────────────────────────────┐ │ │ -│ │ │ 1. Shell (本地 CEP) │ │ │ -│ │ │ - 首次从服务器下载 shell.zip │ │ │ -│ │ │ - 离线登录页 (file://) │ │ │ -│ │ │ - 版本管理和更新 │ │ │ -│ │ └──────────────────────────────────────────────────┘ │ │ -│ │ ▼ │ │ -│ │ ┌──────────────────────────────────────────────────┐ │ │ -│ │ │ 2. Core (在线应用) │ │ │ -│ │ │ - 从服务器加载 (https://) │ │ │ -│ │ │ - 核心功能和业务逻辑 │ │ │ -│ │ │ - 与 Photoshop 交互 │ │ │ -│ │ └──────────────────────────────────────────────────┘ │ │ -│ └────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ HTTP/HTTPS -┌─────────────────────────────────────────────────────────────┐ -│ 服务器 (Linux) │ -│ ┌────────────────────────────────────────────────────────┐ │ -│ │ Nginx (反向代理) │ │ -│ │ ┌──────────────┬──────────────┬──────────────────┐ │ │ -│ │ │ /shell/ │ /core/ │ /api/ │ │ │ -│ │ │ Shell 在线页 │ Core 应用 │ API 接口 │ │ │ -│ │ └──────┬───────┴──────┬───────┴────────┬─────────┘ │ │ -│ └─────────┼──────────────┼────────────────┼─────────────┘ │ -│ │ │ │ │ -│ ┌─────────▼──────────────▼────────────────▼─────────────┐ │ -│ │ 静态文件服务 + FastAPI │ │ -│ │ ┌────────────┐ ┌────────────┐ ┌─────────────┐ │ │ -│ │ │ Shell │ │ Core │ │ API Routes │ │ │ -│ │ │ (在线登录) │ │ (核心应用) │ │ (业务逻辑) │ │ │ -│ │ └────────────┘ └────────────┘ └─────────────┘ │ │ -│ └────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 🔄 用户流程 - -### 场景 1: 首次使用(CEP 扩展) - -``` -1. 用户安装 CEP 扩展 - └─> 扩展启动,检查本地是否有 Shell - -2. 如果没有 Shell,从服务器下载 - └─> 下载 /downloads/shell-1.0.0.zip - └─> 解压到本地缓存目录 - -3. 加载本地 Shell 登录页 (file://) - └─> 用户输入用户名密码 - -4. 登录成功后 - └─> 检查版本更新 - └─> 下载 Core 应用到本地缓存 - └─> 加载 Core 应用 (http://localhost:8000/core/1.0.0/) - 或直接从服务器加载 (https://your-domain.com/core/1.0.0/) -``` - -### 场景 2: 在线使用(浏览器访问) - -``` -1. 用户访问在线登录页 - └─> https://your-domain.com/shell/ - -2. 输入用户名密码登录 - -3. 登录成功后跳转到 Core - └─> https://your-domain.com/core/1.0.0/ - -4. 使用核心功能 - └─> API 调用 → /api/v1/* - -5. 退出登录 - └─> 清除本地 token - └─> 跳转回 Shell 登录页 - https://your-domain.com/shell/#/login -``` - -## 📁 服务器目录结构详解 - -``` -/var/www/DesignerCEP/Server/ -│ -├── app/ # 后端应用代码 -│ ├── api/ # API 路由 -│ │ └── v1/ -│ │ ├── auth.py # 认证相关 -│ │ ├── client.py # 客户端相关 -│ │ └── ... -│ ├── core/ # 核心配置 -│ ├── services/ # 业务逻辑 -│ └── main.py # 应用入口 -│ -├── static/ # 静态文件(重要!) -│ │ -│ ├── shell/ # Shell 在线登录页 -│ │ ├── index.html # 登录页入口 -│ │ ├── assets/ # JS/CSS/图片等 -│ │ │ ├── index-abc123.js -│ │ │ ├── index-xyz456.css -│ │ │ └── logo.png -│ │ └── ... -│ │ -│ ├── downloads/ # 下载文件(供 CEP 扩展) -│ │ ├── shell-1.0.0.zip # Shell 安装包 -│ │ ├── shell-1.0.1.zip -│ │ └── ... -│ │ -│ └── core/ # Core 核心应用 -│ ├── 1.0.0/ # 版本 1.0.0 -│ │ ├── index.html -│ │ ├── assets/ -│ │ └── ... -│ ├── 1.0.1/ # 版本 1.0.1 -│ │ ├── index.html -│ │ ├── assets/ -│ │ └── ... -│ └── ... -│ -├── logs/ # 日志文件 -│ ├── access.log -│ └── error.log -│ -├── .env # 环境变量配置 -├── requirements.txt # Python 依赖 -└── venv/ # Python 虚拟环境 -``` - -## 🌐 URL 路由映射 - -| URL 路径 | 本地文件路径 | 说明 | 访问方式 | -|---------|------------|------|---------| -| `/shell/` | `static/shell/index.html` | Shell 在线登录页 | 浏览器/CEP | -| `/shell/assets/xxx.js` | `static/shell/assets/xxx.js` | Shell 静态资源 | 自动加载 | -| `/downloads/shell-1.0.0.zip` | `static/downloads/shell-1.0.0.zip` | Shell 安装包 | CEP 下载 | -| `/core/1.0.0/` | `static/core/1.0.0/index.html` | Core 应用(版本 1.0.0) | 浏览器/CEP | -| `/core/1.0.0/assets/xxx.js` | `static/core/1.0.0/assets/xxx.js` | Core 静态资源 | 自动加载 | -| `/api/v1/client/login` | FastAPI 路由 | 登录接口 | API 调用 | -| `/api/v1/client/check_update` | FastAPI 路由 | 检查更新 | API 调用 | - -## 🔐 认证流程详解 - -### 1. 用户登录 - -``` -用户 → Shell 登录页 - ↓ - 输入用户名/密码 - ↓ - POST /api/v1/client/login - ↓ - ┌─────────────────────┐ - │ 后端验证 │ - │ - 检查用户名密码 │ - │ - 检查设备限制 │ - │ - 生成 JWT Token │ - └─────────────────────┘ - ↓ - 返回 token + 用户信息 - ↓ - 保存到 localStorage: - - token - - username - - device_id - - auto_login - ↓ - 跳转到 Core 应用 - (/core/1.0.0/#/home?token=xxx&username=xxx&device_id=xxx) -``` - -### 2. Core 应用初始化 - -``` -Core 启动 - ↓ -检查 URL 参数或 localStorage 中的 token - ↓ -如果有 token: - ├─> 保存到 localStorage - ├─> 启动心跳检测 (每 60 秒验证一次) - └─> 加载用户数据 - -如果没有 token: - └─> 跳转到 Shell 登录页 -``` - -### 3. 退出登录 - -``` -用户点击退出 - ↓ -POST /api/v1/auth/logout - ↓ -清除 localStorage: - - token - - username - - device_id - - auto_login - ↓ -判断环境: - - CEP 环境 → 跳转到本地 Shell (file://) - - 浏览器环境 → 跳转到在线 Shell (https://) -``` - -## 🔄 版本更新流程 - -### 方案 1: 服务器端更新(推荐) - -``` -1. 构建新版本 - cd Designer - npm run build - -2. 上传到服务器 - scp -r dist/Designer/* \ - user@server:/var/www/DesignerCEP/Server/static/core/1.0.1/ - -3. 更新后端配置 - 修改 current_version = "1.0.1" - -4. 用户下次登录时自动获取新版本 -``` - -### 方案 2: CEP 扩展自动更新 - -``` -1. 用户启动 CEP 扩展 - -2. Shell 调用 /api/v1/client/check_update - 返回: { version: "1.0.1", download_url: "/core/1.0.1.zip" } - -3. 如果版本号不同,自动下载新版本 - -4. 下载并解压到本地缓存 - -5. 启动新版本 Core -``` - -## 🔒 安全考虑 - -### 1. 数据传输 - -- ✅ 必须使用 HTTPS(SSL 证书) -- ✅ API 请求必须携带 JWT Token -- ✅ Token 过期时间设置合理(默认 30 天) - -### 2. 跨域处理 - -```python -# 后端配置 CORS -ALLOWED_ORIGINS = [ - "https://your-domain.com", - "https://www.your-domain.com", - "file://", # 允许 CEP 扩展访问 -] -``` - -### 3. 文件访问权限 - -```bash -# 静态文件目录权限 -chmod 755 static/ -chmod 644 static/shell/* -chmod 644 static/core/* - -# 配置文件权限 -chmod 600 .env -``` - -## 📊 性能优化 - -### 1. 静态资源缓存 - -```nginx -# Nginx 配置 -location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { - expires 1y; - add_header Cache-Control "public, immutable"; -} - -location ~* \.html$ { - expires -1; - add_header Cache-Control "no-cache"; -} -``` - -### 2. 资源压缩 - -```nginx -# 启用 Gzip 压缩 -gzip on; -gzip_types text/plain text/css application/json application/javascript; -``` - -### 3. CDN 加速(可选) - -将静态资源部署到 CDN,加快全球访问速度。 - -## 🔍 监控和日志 - -### 1. 应用日志 - -- 后端日志: `/var/www/DesignerCEP/Server/logs/` -- Nginx 日志: `/var/log/nginx/` -- Systemd 日志: `journalctl -u designer-cep` - -### 2. 监控指标 - -- 服务器 CPU/内存使用率 -- API 响应时间 -- 在线用户数 -- 错误率和异常追踪 - ---- - -**总结**: - -这个架构支持两种使用方式: -1. **CEP 扩展模式**:Shell 在本地,Core 可在本地或服务器 -2. **纯在线模式**:Shell 和 Core 都在服务器,通过浏览器访问 - -无论哪种方式,用户退出登录后都能回到 Shell 登录页重新登录。 - diff --git a/temp_backup/Server_redundant/tempdocs/部署配置手册.md b/temp_backup/Server_redundant/tempdocs/部署配置手册.md deleted file mode 100644 index f1fb48c..0000000 --- a/temp_backup/Server_redundant/tempdocs/部署配置手册.md +++ /dev/null @@ -1,436 +0,0 @@ -# 🚀 DesignerCEP 部署配置手册(子域名方案) - -## 📐 架构概览 - -``` -app.aidg168.uk → 前端应用(Caddy 静态文件) -backend.aidg168.uk → 后端 API(FastAPI) -``` - ---- - -## 🌐 第 1 步:配置 DNS(Cloudflare) - -登录 Cloudflare,添加以下 DNS 记录: - -| 类型 | 名称 | 内容 | 代理状态 | TTL | -|------|------|------|----------|-----| -| A | app | 103.97.201.136 | ☁️ 已代理 | 自动 | -| A | backend | 103.97.201.136 | ☁️ 已代理 | 自动 | -| A | @ | 103.97.201.136 | ☁️ 已代理 | 自动 | - -> 注:103.97.201.136 是您的服务器 IP - ---- - -## 📁 第 2 步:服务器目录准备 - -SSH 登录服务器: -```bash -ssh root@103.97.201.136 -``` - -创建目录结构: -```bash -# 创建静态文件目录 -sudo mkdir -p /var/www/DesignerCEP/Server/static/app - -# 设置权限 -sudo chown -R www-data:www-data /var/www/DesignerCEP -sudo chmod -R 755 /var/www/DesignerCEP -``` - ---- - -## ⚙️ 第 3 步:配置 Caddy - -### 方法 A:直接使用提供的配置文件 - -```bash -# 1. 上传 Caddyfile 到服务器 -# 在本地执行: -scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile - -# 2. SSH 登录服务器 -ssh root@103.97.201.136 - -# 3. 验证配置 -sudo caddy validate --config /etc/caddy/Caddyfile - -# 4. 重启 Caddy -sudo systemctl restart caddy - -# 5. 查看状态 -sudo systemctl status caddy -``` - -### 方法 B:手动编辑 - -```bash -# 编辑 Caddy 配置 -sudo nano /etc/caddy/Caddyfile - -# 粘贴 Caddyfile 的内容(已在项目根目录) - -# 保存后验证 -sudo caddy validate --config /etc/caddy/Caddyfile - -# 重启 -sudo systemctl restart caddy -``` - ---- - -## 📤 第 4 步:上传前端文件 - -### 构建前端 - -在本地执行: -```bash -cd Designer - -# 构建主应用 -npm run build:core - -# 输出在 dist_core/ 目录 -``` - -### 上传到服务器 - -#### 方法 A:手动上传(临时测试) - -```bash -# 在本地 Designer 目录执行 -cd dist_core - -# 上传所有文件到服务器 -scp -r * root@103.97.201.136:/var/www/DesignerCEP/Server/static/app/ -``` - -#### 方法 B:使用自动化脚本(推荐) - -修改 `AdminTool/deploy_config.json`: -```json -{ - "host": "103.97.201.136", - "port": "22", - "username": "root", - "password": "tuEj-jkaw-8mFe", - "remote_path": "/var/www/DesignerCEP/Server/static" -} -``` - -然后执行: -```bash -cd AdminTool -python auto_deploy_core.py --version 1.0.0 --deploy --update-db -``` - ---- - -## 🔍 第 5 步:验证部署 - -### 5.1 检查文件是否上传成功 - -SSH 登录服务器: -```bash -ssh root@103.97.201.136 - -# 检查文件 -ls -la /var/www/DesignerCEP/Server/static/app/ - -# 应该看到: -# index-core.html -# assets/ -# CSInterface.js -# vite.svg -``` - -### 5.2 测试静态文件访问 - -在浏览器访问: -``` -https://app.aidg168.uk/index-core.html -``` - -**期望结果**:能看到页面(即使可能显示错误,至少文件能加载) - -### 5.3 测试 API - -```bash -# 测试健康检查 -curl https://backend.aidg168.uk/health - -# 期望输出: -# {"status":"healthy","timestamp":"...","env":"production"} -``` - -### 5.4 测试完整流程 - -1. 在浏览器打开:`https://app.aidg168.uk/` -2. 应该能看到登录页面(如果已合并) -3. 或者 404(如果还没合并 Shell 和 Core) - ---- - -## ⚠️ 当前问题 - -### 问题 1:文件名不匹配 - -您的 Core 构建输出是 `index-core.html`,但 Caddy 和浏览器默认访问 `index.html`。 - -**解决方法 A**:修改 Caddy 配置 -```caddy -app.aidg168.uk { - root * /var/www/DesignerCEP/Server/static/app - - # 指定默认文件 - try_files {path} /index-core.html - - file_server -} -``` - -**解决方法 B**(推荐):修改构建配置 -```typescript -// Designer/vite.config.ts -build: { - outDir: 'dist_core', - rollupOptions: { - input: 'index-core.html' // ← 改成 'index.html' - } -} -``` - -### 问题 2:Shell 和 Core 还没合并 - -目前 Shell(登录)和 Core(主功能)还是分开的。 - -需要: -- 把登录页面路由加到 Core 应用 -- 或者先测试用 Core 的主页 - ---- - -## 🎯 快速测试方案 - -### 临时方案:先让 Core 能访问 - -1. **修改 Caddy 配置**(访问 index-core.html): -```caddy -app.aidg168.uk { - root * /var/www/DesignerCEP/Server/static/app - - # 默认访问 index-core.html - @root { - path / - } - rewrite @root /index-core.html - - try_files {path} /index-core.html - file_server - - encode gzip -} -``` - -2. **上传文件**: -```bash -cd Designer/dist_core -scp -r * root@103.97.201.136:/var/www/DesignerCEP/Server/static/app/ -``` - -3. **访问测试**: -``` -https://app.aidg168.uk/ -``` - ---- - -## 📋 完整 Caddyfile 配置 - -复制这个内容到服务器的 `/etc/caddy/Caddyfile`: - -```caddy -# ==================== DesignerCEP Caddy 配置 ==================== - -{ - # 邮箱用于 HTTPS 证书申请 - email admin@aidg168.uk - - # 如果使用 Cloudflare 橙云代理,取消下面这行注释 - # auto_https off -} - -# ==================== 前端应用 ==================== -app.aidg168.uk { - # 静态文件根目录 - root * /var/www/DesignerCEP/Server/static/app - - # SPA 路由支持(所有请求都返回 index-core.html) - try_files {path} /index-core.html - - # 提供静态文件 - file_server - - # ========== 缓存策略 ========== - - # HTML 不缓存 - @html path *.html - header @html Cache-Control "no-cache, no-store, must-revalidate" - - # JS/CSS 长期缓存 - @assets path *.js *.css *.woff *.woff2 - header @assets Cache-Control "public, max-age=31536000, immutable" - - # 图片缓存 - @images path *.png *.jpg *.jpeg *.gif *.svg *.ico - header @images Cache-Control "public, max-age=2592000" - - # ========== 安全头 ========== - header { - X-Frame-Options "SAMEORIGIN" - X-Content-Type-Options "nosniff" - X-XSS-Protection "1; mode=block" - -Server - } - - # ========== 压缩 ========== - encode gzip - - # ========== 日志 ========== - log { - output file /var/log/caddy/app.log { - roll_size 50mb - roll_keep 5 - } - } -} - -# ==================== 后端 API ==================== -backend.aidg168.uk { - # 反向代理到 FastAPI (端口 8000) - reverse_proxy localhost:8000 { - # 传递真实 IP - header_up X-Real-IP {remote_host} - header_up X-Forwarded-For {remote_host} - header_up X-Forwarded-Proto {scheme} - header_up X-Forwarded-Host {host} - } - - # ========== 压缩 ========== - encode gzip - - # ========== 日志 ========== - log { - output file /var/log/caddy/backend.log { - roll_size 50mb - roll_keep 5 - } - } -} - -# ==================== 主域名重定向(可选)==================== -aidg168.uk, www.aidg168.uk { - # 重定向到应用 - redir https://app.aidg168.uk{uri} permanent -} -``` - ---- - -## ✅ 部署清单 - -执行以下命令: - -```bash -# ========== 在本地 ========== - -# 1. 构建前端 -cd Designer -npm run build:core - -# 2. 上传 Caddyfile -scp Caddyfile root@103.97.201.136:/etc/caddy/Caddyfile - -# 3. 上传前端文件 -cd dist_core -scp -r * root@103.97.201.136:/var/www/DesignerCEP/Server/static/app/ - -# ========== 在服务器 ========== - -# 4. SSH 登录 -ssh root@103.97.201.136 - -# 5. 验证 Caddy 配置 -sudo caddy validate --config /etc/caddy/Caddyfile - -# 6. 重启 Caddy -sudo systemctl restart caddy - -# 7. 查看状态 -sudo systemctl status caddy - -# 8. 查看日志(如果有错误) -sudo journalctl -u caddy -n 50 -``` - ---- - -## 🧪 测试 - -### 测试 1:静态文件 -```bash -curl -I https://app.aidg168.uk/ -# 期望:HTTP/2 200 -``` - -### 测试 2:API -```bash -curl https://backend.aidg168.uk/health -# 期望:{"status":"healthy"} -``` - -### 测试 3:浏览器访问 -``` -https://app.aidg168.uk/ -``` - ---- - -## 🔧 常见问题 - -### Q1: 访问 app.aidg168.uk 显示 404 - -**检查**: -```bash -ls -la /var/www/DesignerCEP/Server/static/app/index-core.html -``` - -### Q2: API 请求 CORS 错误 - -**检查**:FastAPI 的 `ALLOWED_ORIGINS` 是否包含 `https://app.aidg168.uk` - -```bash -# 编辑 .env -sudo nano /var/www/DesignerCEP/Server/.env - -# 确保有: -# ALLOWED_ORIGINS=https://app.aidg168.uk,https://backend.aidg168.uk -``` - -### Q3: Caddy 证书申请失败 - -如果使用 Cloudflare 橙云代理,修改 Caddyfile: -```caddy -{ - auto_https off # ← 添加这行 -} -``` - -然后重启 Caddy。 - ---- - -**部署完成后,访问 `https://app.aidg168.uk/` 测试!** 🎉 - diff --git a/temp_backup/Server_redundant/tempdocs/项目结构文档.md b/temp_backup/Server_redundant/tempdocs/项目结构文档.md deleted file mode 100644 index 589bffc..0000000 --- a/temp_backup/Server_redundant/tempdocs/项目结构文档.md +++ /dev/null @@ -1,77 +0,0 @@ -# DesignerCEP 项目结构文档 - -本文档详细说明了 `DesignerCEP/Designer` 项目的目录结构及各核心文件的作用,帮助开发者快速理解项目架构。 - -## 1. 核心目录结构 (src) - -`src` 是项目的源代码目录,主要分为 **前端 UI (Vue)** 和 **后端逻辑 (JSX/ExtendScript)** 两部分。 - -### 📂 src/ - -| 文件/目录 | 说明 | -| :---------------- | :-------------------------------------------------------------------- | -| **`App.vue`** | Vue 应用的根组件,定义了全局的布局结构。 | -| **`main.ts`** | Vue 应用的入口文件,负责初始化 Vue 实例、挂载路由和插件。 | -| **`api/`** | 存放前端与后端接口交互的代码 (虽然是 CEP,但也可能涉及部分网络请求)。 | -| **`assets/`** | 静态资源目录,存放图片、字体等。 | -| **`components/`** | Vue 通用组件库,存放可在多个页面复用的 UI 组件。 | -| **`view/`** | Vue 页面目录,存放具体的业务页面 (如 Login.vue, Home.vue)。 | -| **`router/`** | 路由配置目录,定义了页面跳转规则。 | -| **`utils/`** | 前端通用工具函数库。 | -| **`jsx/`** | **核心 Photoshop 交互逻辑代码** (见下文详细说明)。 | - ---- - -## 2. Photoshop 交互核心 (src/jsx) - -`src/jsx` 目录包含了所有在 Photoshop 内部执行的 ExtendScript 代码。这部分代码会被编译为 `index.js` 供 CEP 调用。 - -### 📂 src/jsx/ - -| 文件/目录 | 说明 | -| :------------------ | :------------------------------------------------------------------------------------------ | -| **`index.ts`** | **JSX 入口文件**。导出了供前端调用的所有高级函数。可以理解为 CEP 插件的 "后端 API 控制器"。 | -| **`tsconfig.json`** | JSX 部分的 TypeScript 配置文件,确保 ExtendScript 代码被正确编译(编译为 ES3 兼容代码)。 | -| **`types/`** | 存放 `.d.ts` 类型定义文件,用于支持 TypeScript 开发 Photoshop 脚本。 | - -### 📂 src/jsx/utils/ (通用工具库) - -这是我们本次重构新建的目录,用于存放可复用的底层工具函数。 - -| 文件 | 作用详解 | -| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **`ActionManager.ts`** | **ActionManager (AM) 低级操作库**。
封装了 `loadSelection` (载入选区), `fill` (填充), `newDocument` (新建文档) 等通过 ActionDescriptor 调用 Photoshop 底层功能的函数。 | -| **`LayerUtils.ts`** | **图层操作工具库**。
包含了 `getAllLayers` (获取所有图层), `findLayerByName` (按名查找), `selectLayerByName` (选中图层) 等 DOM 层面的图层辅助函数。 | - -### 📂 src/jsx/function/ (业务逻辑封装) - -这里存放封装好的高级业务类。 - -| 文件/目录 | 说明 | -| :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`abstract.ts`** | 定义了一些抽象基类或接口 (目前看来可能是作为一个基类模板)。 | -| **`index.ts`** | 导出 `g_func` 等全局对象,汇集了所有功能模块。 | -| **`ps/api.ts`** | **核心 API 实现类**。包含了 `PSApi`, `MyLayer`, `MyDocument` 等类。
- 这是一个庞大的文件,封装了大量对 Photoshop 的操作。
- 很多功能与我们的 `ActionManager.ts` 类似,但以类的形式组织。
- **注意**: 该文件定义了全局的 `executeAction` 类型,我们在写新代码时要注意兼容。 | - ---- - -## 3. 前端工具库 (src/utils) - -| 文件 | 说明 | -| :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | -| **`cep.ts`** | **CEP 桥接工具**。封装了 `CSInterface`,提供了前端调用 JSX(`evalScript`)、监听事件、获取路径等功能。这是 Vue 与 Photoshop 对话的桥梁。 | -| **`request.ts`** | 封装了 axios 请求,用于网络通信 (如登录、数据同步)。 | -| **`common.ts`** | 通用的 JS 辅助函数 (如日期格式化等)。 | - -## 4. 总结:我们要关注的重点 - -在接下来的重构工作中,我们主要关注以下流程: - -1. **Vue (前端)**: 在 `src/view` 中编写 UI 界面。 -2. **调用**: 使用 `src/utils/cep.ts` 中的 `evalFile` 或 `evalScript` 调用 JSX。 -3. **JSX (后端)**: - - 在 `src/jsx/index.ts` 中注册导出的函数。 - - 复杂的业务逻辑写在 `src/jsx/function` 中。 - - 通用的底层操作 (AM/图层) 优先调用 `src/jsx/utils/ActionManager.ts` 和 `LayerUtils.ts`。 - -这样分层清晰,便于我们逐步迁移 `psmark` 的旧脚本。 diff --git a/temp_backup/Server_redundant/tests/README.md b/temp_backup/Server_redundant/tests/README.md deleted file mode 100644 index 23021fa..0000000 --- a/temp_backup/Server_redundant/tests/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# DesignerCEP 测试套件 - -本目录包含前后端的完整测试代码。 - -## 目录结构 - -``` -tests/ -├── backend/ # 后端测试 -│ ├── test_admin_config.py -│ ├── test_feature.py -│ ├── test_checkin.py -│ ├── test_user_profile.py -│ ├── test_stats.py -│ └── conftest.py -├── frontend/ # 前端测试 -│ ├── HomePage.test.ts -│ ├── Profile.test.ts -│ ├── CheckIn.test.ts -│ └── utils.test.ts -├── integration/ # 集成测试 -│ └── e2e.test.py -└── README.md # 本文件 -``` - -## 运行测试 - -### 后端测试 -```bash -cd tests/backend -pytest -v -``` - -### 前端测试 -```bash -cd Designer -npm run test -``` - -### 集成测试 -```bash -cd tests/integration -pytest -v -``` - -## 测试覆盖率 - -- 后端API: 目标 > 80% -- 前端组件: 目标 > 70% -- 集成测试: 核心流程全覆盖 - diff --git a/temp_backup/Server_redundant/tests/backend/conftest.py b/temp_backup/Server_redundant/tests/backend/conftest.py deleted file mode 100644 index 64c1719..0000000 --- a/temp_backup/Server_redundant/tests/backend/conftest.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Pytest 配置文件 -提供测试fixtures和公共设置 -""" - -import pytest -import pymysql -import os -from typing import Generator - -# 测试数据库配置 -TEST_DB_CONFIG = { - 'host': os.getenv('TEST_DB_HOST', 'localhost'), - 'user': os.getenv('TEST_DB_USER', 'root'), - 'password': os.getenv('TEST_DB_PASSWORD', ''), - 'database': os.getenv('TEST_DB_NAME', 'designercep_test'), - 'charset': 'utf8mb4' -} - -# API配置 -API_BASE_URL = os.getenv('TEST_API_URL', 'https://backend.aidg168.uk/api/v1') -ADMIN_TOKEN = 'admin-secret-token' - - -@pytest.fixture(scope='session') -def db_connection(): - """数据库连接fixture(会话级别)""" - conn = pymysql.connect(**TEST_DB_CONFIG) - yield conn - conn.close() - - -@pytest.fixture(scope='function') -def db_cursor(db_connection): - """数据库游标fixture(函数级别,自动回滚)""" - cursor = db_connection.cursor(pymysql.cursors.DictCursor) - yield cursor - db_connection.rollback() # 测试后回滚 - cursor.close() - - -@pytest.fixture(scope='function') -def test_user(db_cursor): - """创建测试用户""" - username = 'test_user_pytest' - password = 'test123456' - email = 'test@example.com' - - # 清理可能存在的旧数据 - db_cursor.execute("DELETE FROM users WHERE username = %s", (username,)) - db_cursor.connection.commit() - - # 创建测试用户 - db_cursor.execute(""" - INSERT INTO users (username, password, email, points, vip_type, - consecutive_check_in, total_check_in_days) - VALUES (%s, %s, %s, 100, 'none', 0, 0) - """, (username, password, email)) - db_cursor.connection.commit() - - # 获取用户信息 - db_cursor.execute("SELECT * FROM users WHERE username = %s", (username,)) - user = db_cursor.fetchone() - - yield user - - # 清理 - db_cursor.execute("DELETE FROM users WHERE username = %s", (username,)) - db_cursor.connection.commit() - - -@pytest.fixture(scope='function') -def vip_user(db_cursor): - """创建VIP测试用户""" - username = 'test_vip_user' - - # 清理 - db_cursor.execute("DELETE FROM users WHERE username = %s", (username,)) - db_cursor.connection.commit() - - # 创建VIP用户 - db_cursor.execute(""" - INSERT INTO users (username, password, email, points, vip_type, - vip_daily_quota, vip_quota_reset_date) - VALUES (%s, 'test123', 'vip@test.com', 200, 'vip', 20, CURDATE()) - """, (username,)) - db_cursor.connection.commit() - - db_cursor.execute("SELECT * FROM users WHERE username = %s", (username,)) - user = db_cursor.fetchone() - - yield user - - # 清理 - db_cursor.execute("DELETE FROM users WHERE username = %s", (username,)) - db_cursor.connection.commit() - - -@pytest.fixture(scope='function') -def test_feature(db_cursor): - """创建测试功能配置""" - feature_key = 'test_feature_pytest' - - # 清理 - db_cursor.execute("DELETE FROM features_config WHERE feature_key = %s", (feature_key,)) - db_cursor.connection.commit() - - # 创建测试功能 - db_cursor.execute(""" - INSERT INTO features_config - (feature_key, feature_name, category, points_cost, vip_points_cost, - svip_points_cost, enabled) - VALUES (%s, '测试功能', 'test', 50, 0, 0, 1) - """, (feature_key,)) - db_cursor.connection.commit() - - db_cursor.execute("SELECT * FROM features_config WHERE feature_key = %s", (feature_key,)) - feature = db_cursor.fetchone() - - yield feature - - # 清理 - db_cursor.execute("DELETE FROM features_config WHERE feature_key = %s", (feature_key,)) - db_cursor.connection.commit() - - -@pytest.fixture -def admin_headers(): - """管理员请求头""" - return {'x-admin-token': ADMIN_TOKEN} - - -@pytest.fixture -def user_headers(test_user): - """用户请求头(需要实际token生成逻辑)""" - # 这里简化处理,实际应该调用登录接口获取token - return {'Authorization': 'Bearer test_token'} - - -# 测试数据清理 -def pytest_sessionfinish(session, exitstatus): - """测试会话结束后清理""" - try: - conn = pymysql.connect(**TEST_DB_CONFIG) - cursor = conn.cursor() - - # 清理测试数据 - cursor.execute("DELETE FROM users WHERE username LIKE 'test_%'") - cursor.execute("DELETE FROM features_config WHERE feature_key LIKE 'test_%'") - cursor.execute("DELETE FROM check_in_records WHERE username LIKE 'test_%'") - cursor.execute("DELETE FROM points_history WHERE username LIKE 'test_%'") - cursor.execute("DELETE FROM feature_usage_logs WHERE username LIKE 'test_%'") - - conn.commit() - cursor.close() - conn.close() - except Exception as e: - print(f"清理测试数据失败: {e}") - diff --git a/temp_backup/Server_redundant/tests/backend/requirements.txt b/temp_backup/Server_redundant/tests/backend/requirements.txt deleted file mode 100644 index 40b9934..0000000 --- a/temp_backup/Server_redundant/tests/backend/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -pytest==7.4.3 -requests==2.31.0 -pymysql==1.1.0 -pytest-cov==4.1.0 -pytest-html==4.1.1 - diff --git a/temp_backup/Server_redundant/tests/backend/run_tests.bat b/temp_backup/Server_redundant/tests/backend/run_tests.bat deleted file mode 100644 index a9b6291..0000000 --- a/temp_backup/Server_redundant/tests/backend/run_tests.bat +++ /dev/null @@ -1,38 +0,0 @@ -@echo off -chcp 65001 >nul -echo ======================================== -echo DesignerCEP 后端API测试套件 -echo ======================================== -echo. - -echo [1/3] 检查Python环境... -python --version -if %errorlevel% neq 0 ( - echo ❌ Python未安装! - pause - exit /b 1 -) - -echo. -echo [2/3] 安装测试依赖... -pip install -r requirements.txt -if %errorlevel% neq 0 ( - echo ❌ 依赖安装失败! - pause - exit /b 1 -) - -echo. -echo [3/3] 运行测试... -echo ======================================== -pytest -v --cov=../../Server/app/api/v1 --cov-report=html --html=report.html --self-contained-html - -echo. -echo ======================================== -echo 测试完成! -echo 查看报告: -echo - HTML报告: report.html -echo - 覆盖率报告: htmlcov/index.html -echo ======================================== -pause - diff --git a/temp_backup/Server_redundant/tests/backend/test_admin_config.py b/temp_backup/Server_redundant/tests/backend/test_admin_config.py deleted file mode 100644 index 444d208..0000000 --- a/temp_backup/Server_redundant/tests/backend/test_admin_config.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- coding: utf-8 -*- -""" -管理员配置API测试 -测试功能配置、VIP配置、签到配置的CRUD操作 -""" - -import pytest -import requests -from conftest import API_BASE_URL, ADMIN_TOKEN - - -class TestFeaturesConfig: - """功能配置测试""" - - def test_get_features_config(self, admin_headers): - """测试获取功能配置列表""" - response = requests.get( - f"{API_BASE_URL}/admin/config/features", - headers=admin_headers - ) - - assert response.status_code == 200 - data = response.json() - assert isinstance(data, list) - assert len(data) > 0 - - # 验证数据结构 - feature = data[0] - assert 'feature_key' in feature - assert 'feature_name' in feature - assert 'points_cost' in feature - assert 'enabled' in feature - - def test_create_feature_config(self, admin_headers): - """测试创建功能配置""" - feature_data = { - 'feature_key': 'test_feature_api', - 'feature_name': 'API测试功能', - 'category': 'test', - 'points_cost': 60, - 'vip_points_cost': 0, - 'svip_points_cost': 0, - 'description': '这是一个API测试功能' - } - - response = requests.post( - f"{API_BASE_URL}/admin/config/features", - json=feature_data, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - assert result['message'] == '创建成功' - - # 清理 - requests.delete( - f"{API_BASE_URL}/admin/config/features/test_feature_api", - headers=admin_headers - ) - - def test_update_feature_config(self, admin_headers, test_feature): - """测试更新功能配置""" - feature_key = test_feature['feature_key'] - - update_data = { - 'points_cost': 80, - 'enabled': True - } - - response = requests.put( - f"{API_BASE_URL}/admin/config/features/{feature_key}", - json=update_data, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - def test_update_nonexistent_feature(self, admin_headers): - """测试更新不存在的功能""" - response = requests.put( - f"{API_BASE_URL}/admin/config/features/nonexistent_feature", - json={'points_cost': 100}, - headers=admin_headers - ) - - assert response.status_code == 404 - - def test_delete_feature_config(self, admin_headers): - """测试删除功能配置""" - # 先创建 - feature_key = 'test_delete_feature' - requests.post( - f"{API_BASE_URL}/admin/config/features", - json={ - 'feature_key': feature_key, - 'feature_name': '待删除功能', - 'category': 'test', - 'points_cost': 50, - 'vip_points_cost': 0, - 'svip_points_cost': 0 - }, - headers=admin_headers - ) - - # 删除 - response = requests.delete( - f"{API_BASE_URL}/admin/config/features/{feature_key}", - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - -class TestVIPConfig: - """VIP配置测试""" - - def test_get_vip_config(self, admin_headers): - """测试获取VIP配置""" - response = requests.get( - f"{API_BASE_URL}/admin/config/vip", - headers=admin_headers - ) - - assert response.status_code == 200 - data = response.json() - assert isinstance(data, list) - assert len(data) == 2 # VIP和SVIP - - # 验证数据结构 - vip = next((v for v in data if v['vip_type'] == 'vip'), None) - assert vip is not None - assert 'price' in vip - assert 'daily_quota' in vip - assert 'points_multiplier' in vip - - def test_update_vip_config(self, admin_headers): - """测试更新VIP配置""" - update_data = { - 'price': 35.00, - 'daily_quota': 25 - } - - response = requests.put( - f"{API_BASE_URL}/admin/config/vip/vip", - json=update_data, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - # 恢复原值 - requests.put( - f"{API_BASE_URL}/admin/config/vip/vip", - json={'price': 30.00, 'daily_quota': 20}, - headers=admin_headers - ) - - def test_update_invalid_vip_type(self, admin_headers): - """测试更新无效的VIP类型""" - response = requests.put( - f"{API_BASE_URL}/admin/config/vip/invalid", - json={'price': 100}, - headers=admin_headers - ) - - assert response.status_code == 400 - - -class TestCheckInConfig: - """签到配置测试""" - - def test_get_checkin_config(self, admin_headers): - """测试获取签到配置""" - response = requests.get( - f"{API_BASE_URL}/admin/config/checkin", - headers=admin_headers - ) - - assert response.status_code == 200 - data = response.json() - assert isinstance(data, list) - assert len(data) > 0 - - # 验证数据结构 - config = data[0] - assert 'consecutive_days' in config - assert 'base_points' in config - assert 'bonus_points' in config - assert 'total_points' in config - - def test_create_checkin_config(self, admin_headers): - """测试创建签到档位""" - config_data = { - 'consecutive_days': 99, - 'base_points': 10, - 'bonus_points': 200, - 'total_points': 210 - } - - response = requests.post( - f"{API_BASE_URL}/admin/config/checkin", - json=config_data, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - # 清理 - requests.delete( - f"{API_BASE_URL}/admin/config/checkin/99", - headers=admin_headers - ) - - def test_update_checkin_config(self, admin_headers): - """测试更新签到档位""" - # 假设第7天的配置存在 - update_data = { - 'bonus_points': 25, - 'total_points': 35 - } - - response = requests.put( - f"{API_BASE_URL}/admin/config/checkin/7", - json=update_data, - headers=admin_headers - ) - - # 可能成功也可能404(取决于是否存在) - assert response.status_code in [200, 404] - - if response.status_code == 200: - # 恢复原值 - requests.put( - f"{API_BASE_URL}/admin/config/checkin/7", - json={'bonus_points': 20, 'total_points': 30}, - headers=admin_headers - ) - - def test_delete_checkin_config(self, admin_headers): - """测试删除签到档位""" - # 先创建 - requests.post( - f"{API_BASE_URL}/admin/config/checkin", - json={ - 'consecutive_days': 88, - 'base_points': 10, - 'bonus_points': 150, - 'total_points': 160 - }, - headers=admin_headers - ) - - # 删除 - response = requests.delete( - f"{API_BASE_URL}/admin/config/checkin/88", - headers=admin_headers - ) - - assert response.status_code in [200, 404] - - -class TestAdminAuth: - """管理员权限测试""" - - def test_unauthorized_access(self): - """测试未授权访问""" - response = requests.get( - f"{API_BASE_URL}/admin/config/features", - headers={'x-admin-token': 'invalid_token'} - ) - - assert response.status_code == 401 - - def test_missing_token(self): - """测试缺少token""" - response = requests.get( - f"{API_BASE_URL}/admin/config/features" - ) - - assert response.status_code in [401, 422] # FastAPI可能返回422 - - -if __name__ == '__main__': - pytest.main([__file__, '-v']) - diff --git a/temp_backup/Server_redundant/tests/backend/test_checkin.py b/temp_backup/Server_redundant/tests/backend/test_checkin.py deleted file mode 100644 index a81f4e6..0000000 --- a/temp_backup/Server_redundant/tests/backend/test_checkin.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- coding: utf-8 -*- -""" -签到API测试 -测试签到功能、连续天数计算、VIP倍数 -""" - -import pytest -import requests -from datetime import date -from conftest import API_BASE_URL - - -class TestDailyCheckIn: - """每日签到测试""" - - def test_first_checkin(self, test_user): - """测试首次签到""" - request_data = {'username': test_user['username']} - - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json=request_data - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert data['success'] is True - assert data['consecutive_days'] == 1 - assert data['points_earned'] > 0 - assert '签到成功' in data['message'] - - def test_duplicate_checkin(self, test_user, db_cursor): - """测试重复签到""" - # 先签到一次 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 再次签到 - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - assert response.status_code == 400 - assert '已签到' in response.json()['detail'] - - def test_consecutive_checkin_calculation(self, test_user, db_cursor): - """测试连续天数计算""" - from datetime import timedelta - - # 设置昨天签到 - yesterday = date.today() - timedelta(days=1) - db_cursor.execute(""" - UPDATE users - SET last_check_in_date = %s, consecutive_check_in = 5 - WHERE username = %s - """, (yesterday, test_user['username'])) - db_cursor.connection.commit() - - # 今天签到 - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - assert response.status_code == 200 - data = response.json()['data'] - - # 连续天数应该+1 - assert data['consecutive_days'] == 6 - - def test_broken_consecutive_checkin(self, test_user, db_cursor): - """测试中断连续签到""" - from datetime import timedelta - - # 设置3天前签到 - three_days_ago = date.today() - timedelta(days=3) - db_cursor.execute(""" - UPDATE users - SET last_check_in_date = %s, consecutive_check_in = 10 - WHERE username = %s - """, (three_days_ago, test_user['username'])) - db_cursor.connection.commit() - - # 今天签到 - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - assert response.status_code == 200 - data = response.json()['data'] - - # 连续天数应该归零重新开始 - assert data['consecutive_days'] == 1 - - def test_vip_multiplier(self, vip_user): - """测试VIP倍数""" - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': vip_user['username']} - ) - - assert response.status_code == 200 - data = response.json()['data'] - - # VIP应该有倍数 - assert data['vip_multiplier'] >= 1.0 - if vip_user['vip_type'] == 'vip': - assert data['vip_multiplier'] == 1.5 - - def test_checkin_nonexistent_user(self): - """测试不存在的用户签到""" - response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': 'nonexistent_user'} - ) - - assert response.status_code == 404 - - -class TestCheckInStatus: - """签到状态测试""" - - def test_get_checkin_status(self, test_user): - """测试获取签到状态""" - response = requests.get( - f"{API_BASE_URL}/checkin/status", - params={'username': test_user['username']} - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert 'today_checked' in data - assert 'consecutive_days' in data - assert 'total_days' in data - - def test_status_after_checkin(self, test_user): - """测试签到后状态更新""" - # 签到 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 查询状态 - response = requests.get( - f"{API_BASE_URL}/checkin/status", - params={'username': test_user['username']} - ) - - data = response.json()['data'] - assert data['today_checked'] is True - - -class TestCheckInCalendar: - """签到日历测试""" - - def test_get_checkin_calendar(self, test_user): - """测试获取签到日历""" - today = date.today() - - response = requests.get( - f"{API_BASE_URL}/checkin/calendar/{today.year}/{today.month}", - params={'username': test_user['username']} - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert data['year'] == today.year - assert data['month'] == today.month - assert isinstance(data['checked_dates'], list) - - def test_calendar_after_checkin(self, test_user, db_cursor): - """测试签到后日历更新""" - today = date.today() - - # 签到 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 查询日历 - response = requests.get( - f"{API_BASE_URL}/checkin/calendar/{today.year}/{today.month}", - params={'username': test_user['username']} - ) - - data = response.json()['data'] - assert today.day in data['checked_dates'] - - -class TestCheckInHistory: - """签到历史测试""" - - def test_get_checkin_history(self, test_user): - """测试获取签到历史""" - response = requests.get( - f"{API_BASE_URL}/checkin/history", - params={'username': test_user['username'], 'page': 1, 'limit': 10} - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert 'total' in data - assert 'records' in data - assert isinstance(data['records'], list) - - def test_history_after_checkin(self, test_user): - """测试签到后历史记录增加""" - # 获取签到前记录数 - response_before = requests.get( - f"{API_BASE_URL}/checkin/history", - params={'username': test_user['username']} - ) - total_before = response_before.json()['data']['total'] - - # 签到 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 获取签到后记录数 - response_after = requests.get( - f"{API_BASE_URL}/checkin/history", - params={'username': test_user['username']} - ) - total_after = response_after.json()['data']['total'] - - assert total_after == total_before + 1 - - def test_history_pagination(self, test_user): - """测试分页""" - response = requests.get( - f"{API_BASE_URL}/checkin/history", - params={'username': test_user['username'], 'page': 1, 'limit': 5} - ) - - assert response.status_code == 200 - data = response.json()['data'] - assert len(data['records']) <= 5 - - -if __name__ == '__main__': - pytest.main([__file__, '-v']) - diff --git a/temp_backup/Server_redundant/tests/backend/test_feature.py b/temp_backup/Server_redundant/tests/backend/test_feature.py deleted file mode 100644 index 510c7cb..0000000 --- a/temp_backup/Server_redundant/tests/backend/test_feature.py +++ /dev/null @@ -1,207 +0,0 @@ -# -*- coding: utf-8 -*- -""" -功能使用API测试 -测试核心扣费逻辑、VIP配额管理 -""" - -import pytest -import requests -from conftest import API_BASE_URL - - -class TestFeatureUsage: - """功能使用测试""" - - def test_use_feature_normal_user(self, test_user, test_feature): - """测试普通用户使用功能(扣积分)""" - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert data['success'] is True - assert data['cost_type'] == 'points' - assert data['points_cost'] == test_feature['points_cost'] - assert data['points_remaining'] == test_user['points'] - test_feature['points_cost'] - - def test_use_feature_insufficient_points(self, test_user, test_feature, db_cursor): - """测试积分不足""" - # 设置用户积分为0 - db_cursor.execute( - "UPDATE users SET points = 0 WHERE username = %s", - (test_user['username'],) - ) - db_cursor.connection.commit() - - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 402 - assert '积分不足' in response.json()['detail'] - - def test_use_feature_vip_user_with_quota(self, vip_user, test_feature): - """测试VIP用户使用配额""" - request_data = { - 'username': vip_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 200 - result = response.json() - - data = result['data'] - # VIP用户应该使用配额(如果vip_points_cost=0) - assert data['cost_type'] in ['vip_quota', 'points'] - - if data['cost_type'] == 'vip_quota': - assert data['vip_remaining_quota'] == vip_user['vip_daily_quota'] - 1 - - def test_use_disabled_feature(self, test_user, test_feature, db_cursor): - """测试使用已禁用的功能""" - # 禁用功能 - db_cursor.execute( - "UPDATE features_config SET enabled = 0 WHERE feature_key = %s", - (test_feature['feature_key'],) - ) - db_cursor.connection.commit() - - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 400 - assert '禁用' in response.json()['detail'] - - # 恢复 - db_cursor.execute( - "UPDATE features_config SET enabled = 1 WHERE feature_key = %s", - (test_feature['feature_key'],) - ) - db_cursor.connection.commit() - - def test_use_nonexistent_feature(self, test_user): - """测试使用不存在的功能""" - request_data = { - 'username': test_user['username'], - 'feature_key': 'nonexistent_feature', - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 400 - - def test_use_feature_nonexistent_user(self, test_feature): - """测试不存在的用户使用功能""" - request_data = { - 'username': 'nonexistent_user', - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 404 - - -class TestFeatureUsageLogging: - """功能使用日志测试""" - - def test_usage_log_created(self, test_user, test_feature, db_cursor): - """测试使用后创建日志""" - # 使用前记录数 - db_cursor.execute( - "SELECT COUNT(*) as count FROM feature_usage_logs WHERE username = %s", - (test_user['username'],) - ) - count_before = db_cursor.fetchone()['count'] - - # 使用功能 - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - requests.post(f"{API_BASE_URL}/feature/use", json=request_data) - - # 使用后记录数 - db_cursor.execute( - "SELECT COUNT(*) as count FROM feature_usage_logs WHERE username = %s", - (test_user['username'],) - ) - count_after = db_cursor.fetchone()['count'] - - assert count_after == count_before + 1 - - def test_points_history_created(self, test_user, test_feature, db_cursor): - """测试积分历史记录""" - # 使用前记录数 - db_cursor.execute( - "SELECT COUNT(*) as count FROM points_history WHERE username = %s", - (test_user['username'],) - ) - count_before = db_cursor.fetchone()['count'] - - # 使用功能 - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post(f"{API_BASE_URL}/feature/use", json=request_data) - - # 只有扣积分时才记录积分历史 - if response.status_code == 200: - data = response.json()['data'] - if data['cost_type'] == 'points': - db_cursor.execute( - "SELECT COUNT(*) as count FROM points_history WHERE username = %s", - (test_user['username'],) - ) - count_after = db_cursor.fetchone()['count'] - assert count_after == count_before + 1 - - -if __name__ == '__main__': - pytest.main([__file__, '-v']) - diff --git a/temp_backup/Server_redundant/tests/backend/test_stats.py b/temp_backup/Server_redundant/tests/backend/test_stats.py deleted file mode 100644 index 85439af..0000000 --- a/temp_backup/Server_redundant/tests/backend/test_stats.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- coding: utf-8 -*- -""" -统计API测试 -测试数据统计功能 -""" - -import pytest -import requests -from conftest import API_BASE_URL, ADMIN_TOKEN - - -class TestTodayStats: - """今日统计测试""" - - def test_get_today_stats(self, admin_headers): - """测试获取今日统计""" - response = requests.get( - f"{API_BASE_URL}/admin/stats/today", - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert 'total_users' in data - assert 'checkin_count' in data - assert 'feature_usage_count' in data - assert 'vip_count' in data - - # 验证数据类型 - assert isinstance(data['total_users'], int) - assert isinstance(data['checkin_count'], int) - assert isinstance(data['feature_usage_count'], int) - assert isinstance(data['vip_count'], int) - - # 验证数据合理性 - assert data['total_users'] >= 0 - assert data['checkin_count'] >= 0 - assert data['checkin_count'] <= data['total_users'] - - def test_stats_unauthorized(self): - """测试未授权访问统计""" - response = requests.get(f"{API_BASE_URL}/admin/stats/today") - - assert response.status_code in [401, 422] - - -class TestFeatureUsageStats: - """功能使用排行测试""" - - def test_get_feature_usage_stats(self, admin_headers): - """测试获取功能使用排行""" - response = requests.get( - f"{API_BASE_URL}/admin/stats/feature-usage", - params={'days': 7}, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert isinstance(data, list) - - # 如果有数据,验证结构 - if len(data) > 0: - item = data[0] - assert 'feature_key' in item - assert 'feature_name' in item - assert 'usage_count' in item - assert isinstance(item['usage_count'], int) - - def test_feature_usage_stats_different_days(self, admin_headers): - """测试不同天数的统计""" - days_list = [7, 30, 90] - - for days in days_list: - response = requests.get( - f"{API_BASE_URL}/admin/stats/feature-usage", - params={'days': days}, - headers=admin_headers - ) - - assert response.status_code == 200 - assert response.json()['code'] == 200 - - -class TestPointsTrend: - """积分趋势测试""" - - def test_get_points_trend(self, admin_headers): - """测试获取积分趋势""" - response = requests.get( - f"{API_BASE_URL}/admin/stats/points-trend", - params={'days': 7}, - headers=admin_headers - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert isinstance(data, list) - - # 如果有数据,验证结构 - if len(data) > 0: - item = data[0] - assert 'date' in item - assert 'earned' in item - assert 'consumed' in item - - # 验证数据类型 - assert isinstance(item['earned'], (int, float, type(None))) - assert isinstance(item['consumed'], (int, float, type(None))) - - def test_points_trend_date_format(self, admin_headers): - """测试日期格式""" - response = requests.get( - f"{API_BASE_URL}/admin/stats/points-trend", - params={'days': 7}, - headers=admin_headers - ) - - data = response.json()['data'] - - if len(data) > 0: - # 验证日期格式 (YYYY-MM-DD) - import re - date_pattern = r'^\d{4}-\d{2}-\d{2}$' - assert re.match(date_pattern, data[0]['date']) - - -class TestStatsIntegration: - """统计集成测试""" - - def test_stats_after_operations(self, test_user, test_feature, admin_headers, db_cursor): - """测试操作后统计数据变化""" - # 获取操作前统计 - response_before = requests.get( - f"{API_BASE_URL}/admin/stats/today", - headers=admin_headers - ) - stats_before = response_before.json()['data'] - - # 执行签到 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 使用功能 - requests.post( - f"{API_BASE_URL}/feature/use", - json={ - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test' - } - ) - - # 获取操作后统计 - response_after = requests.get( - f"{API_BASE_URL}/admin/stats/today", - headers=admin_headers - ) - stats_after = response_after.json()['data'] - - # 验证签到数增加 - assert stats_after['checkin_count'] >= stats_before['checkin_count'] - - # 验证功能使用数增加 - assert stats_after['feature_usage_count'] >= stats_before['feature_usage_count'] - - -if __name__ == '__main__': - pytest.main([__file__, '-v']) - diff --git a/temp_backup/Server_redundant/tests/backend/test_user_profile.py b/temp_backup/Server_redundant/tests/backend/test_user_profile.py deleted file mode 100644 index da22eab..0000000 --- a/temp_backup/Server_redundant/tests/backend/test_user_profile.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- -""" -用户资料和积分历史API测试 -""" - -import pytest -import requests -from conftest import API_BASE_URL - - -class TestUserProfile: - """用户资料测试""" - - def test_get_user_profile(self, test_user): - """测试获取用户资料""" - response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': test_user['username']} - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert data['username'] == test_user['username'] - assert 'points' in data - assert 'vip_type' in data - assert 'total_check_in_days' in data - assert 'consecutive_check_in' in data - - def test_get_nonexistent_user_profile(self): - """测试获取不存在的用户资料""" - response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': 'nonexistent_user'} - ) - - assert response.status_code == 404 - - def test_update_user_profile(self, test_user): - """测试更新用户资料""" - update_data = { - 'username': test_user['username'], - 'nickname': '测试昵称', - 'email': 'newemail@test.com' - } - - response = requests.put( - f"{API_BASE_URL}/user/profile", - json=update_data - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - assert result['message'] == '更新成功' - - # 验证更新 - profile_response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': test_user['username']} - ) - profile_data = profile_response.json()['data'] - assert profile_data['nickname'] == '测试昵称' - assert profile_data['email'] == 'newemail@test.com' - - def test_update_partial_profile(self, test_user): - """测试部分更新""" - update_data = { - 'username': test_user['username'], - 'nickname': '仅更新昵称' - } - - response = requests.put( - f"{API_BASE_URL}/user/profile", - json=update_data - ) - - assert response.status_code == 200 - - def test_update_nonexistent_user_profile(self): - """测试更新不存在的用户资料""" - update_data = { - 'username': 'nonexistent_user', - 'nickname': '测试' - } - - response = requests.put( - f"{API_BASE_URL}/user/profile", - json=update_data - ) - - assert response.status_code == 404 - - -class TestPointsHistory: - """积分历史测试""" - - def test_get_points_history(self, test_user): - """测试获取积分历史""" - response = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': test_user['username'], 'page': 1, 'limit': 10} - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert 'total' in data - assert 'current_balance' in data - assert 'records' in data - assert isinstance(data['records'], list) - - def test_points_history_with_type_filter(self, test_user): - """测试按类型筛选积分历史""" - response = requests.get( - f"{API_BASE_URL}/points/history", - params={ - 'username': test_user['username'], - 'type': 'checkin', - 'page': 1, - 'limit': 10 - } - ) - - assert response.status_code == 200 - data = response.json()['data'] - - # 验证所有记录都是签到类型 - for record in data['records']: - assert record['type'] == 'checkin' - - def test_points_history_pagination(self, test_user): - """测试分页""" - response = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': test_user['username'], 'page': 1, 'limit': 5} - ) - - assert response.status_code == 200 - data = response.json()['data'] - assert len(data['records']) <= 5 - - def test_points_history_structure(self, test_user, db_cursor): - """测试记录结构""" - # 创建一条测试记录 - db_cursor.execute(""" - INSERT INTO points_history - (user_id, username, type, amount, balance, description) - VALUES (%s, %s, 'reward', 50, 150, '测试奖励') - """, (test_user['id'], test_user['username'])) - db_cursor.connection.commit() - - response = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': test_user['username']} - ) - - data = response.json()['data'] - if len(data['records']) > 0: - record = data['records'][0] - assert 'type' in record - assert 'amount' in record - assert 'balance' in record - assert 'description' in record - assert 'created_at' in record - - def test_points_history_after_checkin(self, test_user): - """测试签到后积分历史增加""" - # 获取签到前记录数 - response_before = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': test_user['username']} - ) - total_before = response_before.json()['data']['total'] - - # 签到 - requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': test_user['username']} - ) - - # 获取签到后记录数 - response_after = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': test_user['username']} - ) - total_after = response_after.json()['data']['total'] - - # 签到会增加一条积分历史 - assert total_after == total_before + 1 - - def test_points_history_nonexistent_user(self): - """测试不存在的用户的积分历史""" - response = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': 'nonexistent_user'} - ) - - assert response.status_code == 404 - - -if __name__ == '__main__': - pytest.main([__file__, '-v']) - diff --git a/temp_backup/Server_redundant/tests/frontend/CheckIn.test.ts b/temp_backup/Server_redundant/tests/frontend/CheckIn.test.ts deleted file mode 100644 index 6853ed9..0000000 --- a/temp_backup/Server_redundant/tests/frontend/CheckIn.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -/** - * CheckIn组件测试 - */ - -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { mount } from '@vue/test-utils' -import CheckIn from '../../../src/view/CheckIn.vue' -import axios from 'axios' -import { Message } from '@arco-design/web-vue' - -vi.mock('axios') -vi.mock('@arco-design/web-vue', () => ({ - Message: { - success: vi.fn(), - error: vi.fn() - } -})) - -const mockRouter = { - push: vi.fn() -} - -vi.mock('vue-router', () => ({ - useRouter: () => mockRouter -})) - -describe('CheckIn', () => { - beforeEach(() => { - vi.clearAllMocks() - localStorage.setItem('username', 'testuser') - }) - - it('应该正确渲染组件', () => { - const wrapper = mount(CheckIn) - expect(wrapper.find('.checkin-page').exists()).toBe(true) - }) - - it('应该显示签到状态', async () => { - const mockStatus = { - today_checked: false, - consecutive_days: 7, - total_days: 30 - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockStatus } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('7') - expect(wrapper.text()).toContain('30') - }) - - it('未签到时应该显示签到按钮', async () => { - const mockStatus = { - today_checked: false, - consecutive_days: 5, - total_days: 20 - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockStatus } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('立即签到') - }) - - it('已签到时应该显示已签到状态', async () => { - const mockStatus = { - today_checked: true, - consecutive_days: 8, - total_days: 25 - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockStatus } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('今日已签到') - }) - - it('点击签到按钮应该调用签到API', async () => { - const mockStatus = { - today_checked: false, - consecutive_days: 5, - total_days: 20 - } - - const mockCheckInResponse = { - data: { - code: 200, - data: { - success: true, - points_earned: 30, - consecutive_days: 6, - message: '签到成功' - } - } - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockStatus } - }) - ;(axios.post as any).mockResolvedValue(mockCheckInResponse) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - const checkinButton = wrapper.find('.checkin-button') - if (checkinButton.exists()) { - await checkinButton.trigger('click') - - expect(axios.post).toHaveBeenCalledWith( - expect.stringContaining('/checkin/daily'), - expect.objectContaining({ - username: 'testuser' - }) - ) - } - }) - - it('签到成功后应该显示成功提示', async () => { - const mockCheckInResponse = { - data: { - code: 200, - data: { - success: true, - points_earned: 30, - consecutive_days: 6, - message: '签到成功!连续签到6天,获得30积分' - } - } - } - - ;(axios.post as any).mockResolvedValue(mockCheckInResponse) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - const checkinButton = wrapper.find('.checkin-button') - if (checkinButton.exists()) { - await checkinButton.trigger('click') - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(Message.success).toHaveBeenCalled() - } - }) - - it('应该显示奖励规则', async () => { - const mockRewards = [ - { consecutive_days: 1, base_points: 10, bonus_points: 0, total_points: 10 }, - { consecutive_days: 7, base_points: 10, bonus_points: 20, total_points: 30 } - ] - - ;(axios.get as any).mockResolvedValue({ - data: mockRewards - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 200)) - - expect(wrapper.text()).toContain('奖励规则') - }) - - it('应该显示签到日历', async () => { - const mockCalendar = { - year: 2024, - month: 1, - checked_dates: [1, 5, 10, 15, 20] - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockCalendar } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 200)) - - expect(wrapper.find('.calendar-grid').exists()).toBe(true) - }) - - it('应该能够切换月份', async () => { - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - const prevButton = wrapper.find('.calendar-title').parentElement?.querySelector('button') - if (prevButton) { - await prevButton.dispatchEvent(new Event('click')) - // 应该调用API加载新月份的数据 - await new Promise(resolve => setTimeout(resolve, 100)) - } - }) - - it('应该显示签到历史记录', async () => { - const mockHistory = { - total: 10, - records: [ - { - check_in_date: '2024-01-01', - points_earned: 30, - consecutive_days: 7 - } - ] - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockHistory } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 200)) - - expect(wrapper.text()).toContain('签到历史') - }) - - it('重复签到应该显示错误提示', async () => { - ;(axios.post as any).mockRejectedValue({ - response: { - data: { - detail: '今日已签到,明天再来吧' - } - } - }) - - const wrapper = mount(CheckIn) - await new Promise(resolve => setTimeout(resolve, 100)) - - const checkinButton = wrapper.find('.checkin-button') - if (checkinButton.exists()) { - await checkinButton.trigger('click') - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(Message.error).toHaveBeenCalled() - } - }) -}) - diff --git a/temp_backup/Server_redundant/tests/frontend/HomePage.test.ts b/temp_backup/Server_redundant/tests/frontend/HomePage.test.ts deleted file mode 100644 index af5fc43..0000000 --- a/temp_backup/Server_redundant/tests/frontend/HomePage.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -/** - * HomePage组件测试 - */ - -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { mount } from '@vue/test-utils' -import HomePage from '../../../src/view/HomePage.vue' -import { Message } from '@arco-design/web-vue' -import axios from 'axios' - -// Mock axios -vi.mock('axios') - -// Mock Arco Design Message -vi.mock('@arco-design/web-vue', () => ({ - Message: { - success: vi.fn(), - error: vi.fn(), - warning: vi.fn() - } -})) - -// Mock router -const mockRouter = { - push: vi.fn() -} - -vi.mock('vue-router', () => ({ - useRouter: () => mockRouter -})) - -describe('HomePage', () => { - beforeEach(() => { - vi.clearAllMocks() - localStorage.setItem('username', 'testuser') - localStorage.setItem('token', 'test_token') - }) - - it('应该正确渲染组件', () => { - const wrapper = mount(HomePage) - expect(wrapper.find('.home-page').exists()).toBe(true) - }) - - it('应该显示欢迎信息', async () => { - // Mock API响应 - const mockUserInfo = { - username: 'testuser', - nickname: '测试用户', - points: 1000, - vip_type: 'vip', - consecutive_check_in: 7 - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { - code: 200, - data: mockUserInfo - } - }) - - const wrapper = mount(HomePage) - await wrapper.vm.$nextTick() - - // 等待数据加载 - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('测试用户') - }) - - it('应该显示正确的积分数量', async () => { - const mockUserInfo = { - username: 'testuser', - points: 1500, - vip_type: 'none', - consecutive_check_in: 3 - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { - code: 200, - data: mockUserInfo - } - }) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - // 应该显示1500积分 - expect(wrapper.html()).toContain('1500') - }) - - it('应该显示VIP状态', async () => { - const mockUserInfo = { - username: 'testuser', - points: 1000, - vip_type: 'svip', - consecutive_check_in: 10 - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { - code: 200, - data: mockUserInfo - } - }) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('SVIP') - }) - - it('点击功能卡片应该调用使用功能API', async () => { - const mockUserInfo = { - username: 'testuser', - points: 1000, - vip_type: 'none', - consecutive_check_in: 5 - } - - const mockFeatureResponse = { - data: { - code: 200, - data: { - success: true, - cost_type: 'points', - points_cost: 50, - points_remaining: 950, - message: '使用成功' - } - } - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { code: 200, data: mockUserInfo } - }) - ;(axios.post as any).mockResolvedValueOnce(mockFeatureResponse) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - // 模拟点击功能卡片 - const featureItem = wrapper.find('.feature-item') - if (featureItem.exists()) { - await featureItem.trigger('click') - - expect(axios.post).toHaveBeenCalledWith( - expect.stringContaining('/feature/use'), - expect.objectContaining({ - username: 'testuser', - feature_key: expect.any(String), - device_id: expect.any(String) - }) - ) - } - }) - - it('积分不足时应该显示错误提示', async () => { - const mockUserInfo = { - username: 'testuser', - points: 10, - vip_type: 'none', - consecutive_check_in: 1 - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { code: 200, data: mockUserInfo } - }) - ;(axios.post as any).mockRejectedValueOnce({ - response: { - data: { - detail: '积分不足' - } - } - }) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - const featureItem = wrapper.find('.feature-item') - if (featureItem.exists()) { - await featureItem.trigger('click') - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(Message.error).toHaveBeenCalled() - } - }) - - it('应该有快捷入口按钮', async () => { - const wrapper = mount(HomePage) - - expect(wrapper.text()).toContain('每日签到') - expect(wrapper.text()).toContain('个人中心') - expect(wrapper.text()).toContain('工作台') - }) - - it('未登录时应该跳转到登录页', async () => { - localStorage.removeItem('username') - localStorage.removeItem('token') - - ;(axios.get as any).mockRejectedValueOnce(new Error('Unauthorized')) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - // 应该尝试跳转到登录页 - expect(mockRouter.push).toHaveBeenCalledWith('/login') - }) -}) - diff --git a/temp_backup/Server_redundant/tests/frontend/Profile.test.ts b/temp_backup/Server_redundant/tests/frontend/Profile.test.ts deleted file mode 100644 index cc2374b..0000000 --- a/temp_backup/Server_redundant/tests/frontend/Profile.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Profile组件测试 - */ - -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { mount } from '@vue/test-utils' -import Profile from '../../../src/view/Profile.vue' -import axios from 'axios' - -vi.mock('axios') - -const mockRouter = { - push: vi.fn() -} - -vi.mock('vue-router', () => ({ - useRouter: () => mockRouter -})) - -describe('Profile', () => { - beforeEach(() => { - vi.clearAllMocks() - localStorage.setItem('username', 'testuser') - localStorage.setItem('token', 'test_token') - }) - - it('应该正确渲染组件', () => { - const wrapper = mount(Profile) - expect(wrapper.find('.profile-page').exists()).toBe(true) - }) - - it('应该显示用户基本信息', async () => { - const mockProfile = { - username: 'testuser', - nickname: '测试昵称', - email: 'test@example.com', - points: 1200, - level: 3, - vip_type: 'vip', - total_check_in_days: 30, - consecutive_check_in: 7 - } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { code: 200, data: mockProfile } - }).mockResolvedValueOnce({ - data: { code: 200, data: { total: 0, current_balance: 1200, records: [] } } - }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('测试昵称') - expect(wrapper.text()).toContain('testuser') - }) - - it('应该显示统计数据卡片', async () => { - const mockProfile = { - username: 'testuser', - points: 1200, - total_check_in_days: 30, - consecutive_check_in: 7, - vip_type: 'vip' - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockProfile } - }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.findAll('.stat-card').length).toBeGreaterThan(0) - }) - - it('应该能够编辑资料', async () => { - const mockProfile = { - username: 'testuser', - nickname: '旧昵称', - points: 1000 - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockProfile } - }) - ;(axios.put as any).mockResolvedValue({ - data: { code: 200, message: '更新成功' } - }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 100)) - - // 模拟点击编辑按钮 - const editButton = wrapper.find('button') - if (editButton.exists() && editButton.text().includes('编辑')) { - await editButton.trigger('click') - // 编辑对话框应该打开 - await wrapper.vm.$nextTick() - } - }) - - it('应该显示VIP徽章', async () => { - const mockProfile = { - username: 'testuser', - vip_type: 'svip', - points: 2000 - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockProfile } - }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.html()).toContain('SVIP') - }) - - it('应该显示积分历史列表', async () => { - const mockProfile = { - username: 'testuser', - points: 1000 - } - - const mockHistory = { - total: 10, - current_balance: 1000, - records: [ - { - type: 'checkin', - amount: 30, - balance: 1000, - description: '每日签到', - created_at: '2024-01-01T10:00:00' - }, - { - type: 'consume', - amount: -50, - balance: 970, - description: '使用AI配色', - created_at: '2024-01-01T09:00:00' - } - ] - } - - ;(axios.get as any) - .mockResolvedValueOnce({ data: { code: 200, data: mockProfile } }) - .mockResolvedValueOnce({ data: { code: 200, data: mockHistory } }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 100)) - - expect(wrapper.text()).toContain('每日签到') - expect(wrapper.text()).toContain('使用AI配色') - }) - - it('积分变动应该有不同颜色', async () => { - const mockHistory = { - total: 2, - current_balance: 1000, - records: [ - { type: 'checkin', amount: 30, balance: 1000, description: '签到', created_at: '2024-01-01' }, - { type: 'consume', amount: -50, balance: 970, description: '消费', created_at: '2024-01-01' } - ] - } - - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockHistory } - }) - - const wrapper = mount(Profile) - await new Promise(resolve => setTimeout(resolve, 200)) - - // 正数应该是绿色,负数应该是红色 - const html = wrapper.html() - expect(html).toContain('positive') - expect(html).toContain('negative') - }) -}) - diff --git a/temp_backup/Server_redundant/tests/integration/e2e_test.py b/temp_backup/Server_redundant/tests/integration/e2e_test.py deleted file mode 100644 index 46f5932..0000000 --- a/temp_backup/Server_redundant/tests/integration/e2e_test.py +++ /dev/null @@ -1,239 +0,0 @@ -# -*- coding: utf-8 -*- -""" -端到端集成测试 -测试完整的业务流程 -""" - -import pytest -import requests -import time -from datetime import date - -API_BASE_URL = 'https://backend.aidg168.uk/api/v1' -ADMIN_TOKEN = 'admin-secret-token' - - -class TestUserJourney: - """用户完整流程测试""" - - def test_complete_user_journey(self): - """ - 测试用户完整使用流程: - 1. 查看用户资料 - 2. 每日签到 - 3. 使用功能 - 4. 查看积分历史 - """ - username = 'e2e_test_user' - - # 1. 查看用户资料 - profile_response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': username} - ) - - if profile_response.status_code == 200: - profile = profile_response.json()['data'] - initial_points = profile['points'] - print(f"初始积分: {initial_points}") - else: - print(f"用户 {username} 不存在,请先创建") - return - - # 2. 每日签到 - checkin_response = requests.post( - f"{API_BASE_URL}/checkin/daily", - json={'username': username} - ) - - if checkin_response.status_code == 200: - checkin_data = checkin_response.json()['data'] - print(f"签到成功:获得 {checkin_data['points_earned']} 积分") - print(f"连续签到:{checkin_data['consecutive_days']} 天") - elif checkin_response.status_code == 400: - print("今日已签到") - - # 等待数据更新 - time.sleep(1) - - # 3. 使用功能 - feature_response = requests.post( - f"{API_BASE_URL}/feature/use", - json={ - 'username': username, - 'feature_key': 'ai_color_match', - 'device_id': 'e2e_test_device' - } - ) - - if feature_response.status_code == 200: - feature_data = feature_response.json()['data'] - print(f"使用功能成功:{feature_data['message']}") - print(f"消耗类型:{feature_data['cost_type']}") - print(f"剩余积分:{feature_data['points_remaining']}") - else: - print(f"使用功能失败:{feature_response.json()['detail']}") - - # 4. 查看积分历史 - history_response = requests.get( - f"{API_BASE_URL}/points/history", - params={'username': username, 'page': 1, 'limit': 10} - ) - - if history_response.status_code == 200: - history_data = history_response.json()['data'] - print(f"\n积分历史(共 {history_data['total']} 条):") - for record in history_data['records'][:5]: - print(f" {record['created_at']}: {record['description']} {record['amount']:+d}") - - # 5. 验证最终状态 - final_profile_response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': username} - ) - - final_profile = final_profile_response.json()['data'] - final_points = final_profile['points'] - print(f"\n最终积分: {final_points}") - - assert True # 流程完成即通过 - - -class TestAdminWorkflow: - """管理员工作流程测试""" - - def test_admin_config_workflow(self): - """ - 测试管理员配置流程: - 1. 查看当前配置 - 2. 创建新功能 - 3. 修改VIP配置 - 4. 查看统计数据 - """ - headers = {'x-admin-token': ADMIN_TOKEN} - - # 1. 查看功能配置 - features_response = requests.get( - f"{API_BASE_URL}/admin/config/features", - headers=headers - ) - - assert features_response.status_code == 200 - features = features_response.json() - print(f"当前功能数量: {len(features)}") - - # 2. 创建测试功能 - new_feature = { - 'feature_key': 'e2e_test_feature', - 'feature_name': 'E2E测试功能', - 'category': 'test', - 'points_cost': 99, - 'vip_points_cost': 0, - 'svip_points_cost': 0, - 'description': '这是E2E测试创建的功能' - } - - create_response = requests.post( - f"{API_BASE_URL}/admin/config/features", - json=new_feature, - headers=headers - ) - - if create_response.status_code == 200: - print("✓ 创建功能成功") - - # 3. 修改功能 - update_response = requests.put( - f"{API_BASE_URL}/admin/config/features/e2e_test_feature", - json={'points_cost': 120}, - headers=headers - ) - - if update_response.status_code == 200: - print("✓ 修改功能成功") - - # 4. 查看统计数据 - stats_response = requests.get( - f"{API_BASE_URL}/admin/stats/today", - headers=headers - ) - - if stats_response.status_code == 200: - stats = stats_response.json()['data'] - print(f"\n今日统计:") - print(f" 总用户数: {stats['total_users']}") - print(f" 签到数: {stats['checkin_count']}") - print(f" 功能使用数: {stats['feature_usage_count']}") - print(f" VIP用户数: {stats['vip_count']}") - - # 5. 清理测试数据 - delete_response = requests.delete( - f"{API_BASE_URL}/admin/config/features/e2e_test_feature", - headers=headers - ) - - if delete_response.status_code == 200: - print("✓ 清理测试数据成功") - - assert True - - -class TestVIPFeatures: - """VIP功能测试""" - - def test_vip_quota_usage(self): - """测试VIP配额使用""" - vip_username = 'e2e_vip_user' # 需要是VIP用户 - - # 查看VIP配额 - profile_response = requests.get( - f"{API_BASE_URL}/user/profile", - params={'username': vip_username} - ) - - if profile_response.status_code == 200: - profile = profile_response.json()['data'] - - if profile['vip_type'] != 'none': - print(f"VIP类型: {profile['vip_type']}") - print(f"VIP配额: {profile.get('vip_daily_quota', 'N/A')}") - - # 使用功能(应该使用配额) - feature_response = requests.post( - f"{API_BASE_URL}/feature/use", - json={ - 'username': vip_username, - 'feature_key': 'ai_color_match', - 'device_id': 'e2e_vip_device' - } - ) - - if feature_response.status_code == 200: - data = feature_response.json()['data'] - print(f"使用功能: {data['cost_type']}") - if data['cost_type'] == 'vip_quota': - print(f"剩余配额: {data['vip_remaining_quota']}") - else: - print(f"{vip_username} 不是VIP用户") - - assert True - - -if __name__ == '__main__': - # 单独运行集成测试 - print("="*60) - print("开始运行E2E集成测试") - print("="*60) - - tester = TestUserJourney() - tester.test_complete_user_journey() - - print("\n" + "="*60) - - admin_tester = TestAdminWorkflow() - admin_tester.test_admin_config_workflow() - - print("\n" + "="*60) - print("E2E测试完成!") - print("="*60) - diff --git a/temp_backup/Server_redundant/tests/测试交付报告.md b/temp_backup/Server_redundant/tests/测试交付报告.md deleted file mode 100644 index e88c7dc..0000000 --- a/temp_backup/Server_redundant/tests/测试交付报告.md +++ /dev/null @@ -1,459 +0,0 @@ -# ✅ DesignerCEP 完整测试套件 - 交付报告 - -## 🎉 测试开发完成 - -已为整个项目创建完整的测试套件,包含前后端测试和集成测试。 - ---- - -## 📦 测试文件清单 - -### 后端测试 (5个测试文件) -``` -tests/backend/ -├── conftest.py (169行) - Pytest配置和fixtures -├── test_admin_config.py (267行) - 管理员配置API测试 -├── test_feature.py (163行) - 功能使用API测试 -├── test_checkin.py (239行) - 签到API测试 -├── test_user_profile.py (169行) - 用户资料API测试 -├── test_stats.py (147行) - 统计API测试 -├── requirements.txt - Python依赖 -└── run_tests.bat - Windows测试脚本 -``` - -**测试用例总数**: 约 50+ 个 - -### 前端测试 (3个测试文件) -``` -tests/frontend/ -├── HomePage.test.ts (142行) - 首页组件测试 -├── Profile.test.ts (131行) - 个人中心测试 -└── CheckIn.test.ts (169行) - 签到页面测试 -``` - -**测试用例总数**: 约 30+ 个 - -### 集成测试 (1个测试文件) -``` -tests/integration/ -└── e2e_test.py (219行) - 端到端集成测试 -``` - -**测试场景**: 3个完整业务流程 - -### 文档 -``` -tests/ -├── README.md - 测试套件说明 -└── 测试文档.md (完整测试文档) -``` - ---- - -## 📊 测试统计 - -| 类型 | 文件数 | 测试用例数 | 代码行数 | -|------|--------|-----------|---------| -| 后端API测试 | 6个 | ~50个 | ~1200行 | -| 前端组件测试 | 3个 | ~30个 | ~450行 | -| 集成测试 | 1个 | 3个场景 | ~220行 | -| **总计** | **10个** | **~80个** | **~1870行** | - ---- - -## 🧪 测试覆盖范围 - -### 后端API测试 ✅ - -#### 1. 管理员配置API (test_admin_config.py) -- ✅ 功能配置CRUD (创建/读取/更新/删除) -- ✅ VIP配置管理 -- ✅ 签到配置管理 -- ✅ 权限验证 -- ✅ 错误处理 - -#### 2. 功能使用API (test_feature.py) -- ✅ 普通用户扣积分 -- ✅ VIP用户使用配额 -- ✅ 积分不足处理 -- ✅ 禁用功能检查 -- ✅ 使用日志记录 -- ✅ 积分历史记录 - -#### 3. 签到API (test_checkin.py) -- ✅ 首次签到 -- ✅ 重复签到检查 -- ✅ 连续天数计算 -- ✅ 中断连续签到 -- ✅ VIP倍数加成 -- ✅ 签到状态查询 -- ✅ 签到日历 -- ✅ 签到历史 - -#### 4. 用户资料API (test_user_profile.py) -- ✅ 获取用户资料 -- ✅ 更新用户资料 -- ✅ 部分更新 -- ✅ 积分历史查询 -- ✅ 类型筛选 -- ✅ 分页 - -#### 5. 统计API (test_stats.py) -- ✅ 今日统计 -- ✅ 功能使用排行 -- ✅ 积分趋势 -- ✅ 权限验证 -- ✅ 集成测试 - -### 前端组件测试 ✅ - -#### 1. HomePage组件 (HomePage.test.ts) -- ✅ 组件渲染 -- ✅ 欢迎信息显示 -- ✅ 积分显示 -- ✅ VIP状态显示 -- ✅ 功能卡片点击 -- ✅ 错误处理 -- ✅ 快捷入口 -- ✅ 登录状态检查 - -#### 2. Profile组件 (Profile.test.ts) -- ✅ 用户信息显示 -- ✅ 统计卡片 -- ✅ 编辑资料 -- ✅ VIP徽章 -- ✅ 积分历史列表 -- ✅ 颜色区分 - -#### 3. CheckIn组件 (CheckIn.test.ts) -- ✅ 签到状态显示 -- ✅ 签到按钮 -- ✅ API调用 -- ✅ 成功提示 -- ✅ 奖励规则 -- ✅ 签到日历 -- ✅ 月份切换 -- ✅ 历史记录 -- ✅ 重复签到处理 - -### 集成测试 ✅ - -#### 1. 用户完整流程 (TestUserJourney) -- ✅ 查看用户资料 -- ✅ 每日签到 -- ✅ 使用功能 -- ✅ 查看积分历史 -- ✅ 验证最终状态 - -#### 2. 管理员工作流程 (TestAdminWorkflow) -- ✅ 查看配置 -- ✅ 创建功能 -- ✅ 修改配置 -- ✅ 查看统计 -- ✅ 清理数据 - -#### 3. VIP功能测试 (TestVIPFeatures) -- ✅ VIP配额查询 -- ✅ 配额使用 -- ✅ 配额扣减 - ---- - -## 🚀 运行测试 - -### 后端测试 - -```bash -# 1. 安装依赖 -cd tests/backend -pip install -r requirements.txt - -# 2. 配置环境变量 -# 复制 .env.example 为 .env 并配置测试数据库 - -# 3. 运行测试 -pytest -v - -# 4. 生成覆盖率报告 -pytest -v --cov --cov-report=html - -# 5. 查看报告 -# 打开 htmlcov/index.html -``` - -### 前端测试 - -```bash -# 1. 进入前端目录 -cd Designer - -# 2. 安装依赖(如未安装) -npm install - -# 3. 运行测试 -npm run test - -# 4. 监听模式 -npm run test:watch - -# 5. 生成覆盖率 -npm run test:coverage -``` - -### 集成测试 - -```bash -# 运行E2E测试 -cd tests/integration -python e2e_test.py - -# 或使用pytest -pytest e2e_test.py -v -``` - ---- - -## 📝 测试配置 - -### 后端测试环境变量 (.env) -```env -TEST_DB_HOST=localhost -TEST_DB_USER=root -TEST_DB_PASSWORD=your_password -TEST_DB_NAME=designercep_test -TEST_API_URL=https://backend.aidg168.uk/api/v1 -``` - -### 前端测试配置 -前端测试已集成到 `vite.config.ts`,无需额外配置。 - ---- - -## ✅ 测试质量保证 - -### 1. 测试隔离 -- ✅ 每个测试用例独立运行 -- ✅ 测试数据自动清理 -- ✅ 数据库事务回滚 - -### 2. Mock机制 -- ✅ HTTP请求Mock -- ✅ 路由Mock -- ✅ UI组件Mock - -### 3. 错误覆盖 -- ✅ 正常流程 -- ✅ 边界条件 -- ✅ 异常情况 -- ✅ 权限验证 - -### 4. 断言完整 -- ✅ 状态码验证 -- ✅ 数据结构验证 -- ✅ 业务逻辑验证 -- ✅ UI渲染验证 - ---- - -## 📊 测试覆盖率目标 - -| 模块 | 目标 | 实际 | 状态 | -|------|------|------|------| -| 后端API | > 80% | ~85% | ✅ 已达标 | -| 前端组件 | > 70% | ~75% | ✅ 已达标 | -| 核心业务流程 | 100% | 100% | ✅ 已达标 | - ---- - -## 🐛 测试场景示例 - -### 后端测试示例 -```python -def test_use_feature_normal_user(self, test_user, test_feature): - """测试普通用户使用功能(扣积分)""" - request_data = { - 'username': test_user['username'], - 'feature_key': test_feature['feature_key'], - 'device_id': 'test_device' - } - - response = requests.post( - f"{API_BASE_URL}/feature/use", - json=request_data - ) - - assert response.status_code == 200 - result = response.json() - assert result['code'] == 200 - - data = result['data'] - assert data['success'] is True - assert data['cost_type'] == 'points' - assert data['points_cost'] == test_feature['points_cost'] -``` - -### 前端测试示例 -```typescript -it('点击功能卡片应该调用使用功能API', async () => { - const mockUserInfo = { username: 'testuser', points: 1000 } - - ;(axios.get as any).mockResolvedValueOnce({ - data: { code: 200, data: mockUserInfo } - }) - - const wrapper = mount(HomePage) - await new Promise(resolve => setTimeout(resolve, 100)) - - const featureItem = wrapper.find('.feature-item') - await featureItem.trigger('click') - - expect(axios.post).toHaveBeenCalledWith( - expect.stringContaining('/feature/use'), - expect.objectContaining({ - username: 'testuser', - feature_key: expect.any(String) - }) - ) -}) -``` - ---- - -## 📚 文档清单 - -1. **tests/README.md** - 测试套件快速入门 -2. **tests/测试文档.md** - 完整测试文档 (本文件) -3. **tests/backend/conftest.py** - 后端测试配置说明 -4. **完成报告.md** - 项目整体完成报告 - ---- - -## 🎓 测试最佳实践 - -### 1. 命名规范 -```python -# 测试文件: test_*.py -# 测试类: Test* -# 测试函数: test_* -``` - -### 2. 测试结构 -```python -def test_something(): - # 1. Arrange (准备) - # 2. Act (执行) - # 3. Assert (断言) -``` - -### 3. 断言清晰 -```python -# ❌ 不好 -assert result - -# ✅ 好 -assert result['code'] == 200 -assert 'message' in result -``` - -### 4. 测试独立 -```python -# 每个测试应该能独立运行 -# 不依赖其他测试的执行顺序 -``` - ---- - -## 🔧 持续集成建议 - -### GitHub Actions配置 -```yaml -name: Tests -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run Backend Tests - run: | - cd tests/backend - pip install -r requirements.txt - pytest -v - - name: Run Frontend Tests - run: | - cd Designer - npm install - npm run test -``` - ---- - -## ⚠️ 注意事项 - -### 1. 测试数据库 -- **必须使用独立的测试数据库** -- 不要在生产数据库上运行测试 -- 测试前确保数据库已迁移 - -### 2. API地址 -- 开发环境测试使用本地API -- 集成测试使用生产API -- 配置环境变量区分 - -### 3. 异步操作 -- 前端测试需要等待异步操作完成 -- 使用 `await new Promise(resolve => setTimeout(resolve, ms))` - -### 4. Mock清理 -- 每个测试前清理Mock状态 -- 使用 `beforeEach(() => vi.clearAllMocks())` - ---- - -## 📈 后续优化建议 - -### 1. 增加测试 -- [ ] 性能测试 -- [ ] 压力测试 -- [ ] 安全测试 - -### 2. 自动化 -- [ ] CI/CD集成 -- [ ] 自动生成测试报告 -- [ ] 测试失败通知 - -### 3. 监控 -- [ ] 测试覆盖率监控 -- [ ] 测试执行时间监控 -- [ ] 失败率趋势分析 - ---- - -## 🎯 测试总结 - -### 已完成 -- ✅ 后端API测试 (6个文件, 50+用例) -- ✅ 前端组件测试 (3个文件, 30+用例) -- ✅ 集成测试 (1个文件, 3个场景) -- ✅ 测试文档 (完整说明) -- ✅ 测试脚本 (一键运行) - -### 测试质量 -- ✅ 覆盖率达标 -- ✅ 边界条件测试 -- ✅ 错误处理测试 -- ✅ 业务逻辑验证 - -### 可维护性 -- ✅ 代码结构清晰 -- ✅ 注释完整 -- ✅ fixtures复用 -- ✅ 易于扩展 - ---- - -**测试是代码质量的保证!** 🎊 - -所有测试文件已创建完成,可以立即投入使用! - diff --git a/temp_backup/Server_redundant/tests/测试文档.md b/temp_backup/Server_redundant/tests/测试文档.md deleted file mode 100644 index 8b507f4..0000000 --- a/temp_backup/Server_redundant/tests/测试文档.md +++ /dev/null @@ -1,426 +0,0 @@ -# DesignerCEP 测试文档 - -## 📋 测试概述 - -本测试套件包含完整的前后端测试,覆盖: -- **后端API测试** (Pytest) -- **前端组件测试** (Vitest) -- **端到端集成测试** (E2E) - ---- - -## 🎯 测试目标 - -### 后端测试覆盖 -- ✅ 管理员配置API (功能/VIP/签到配置) -- ✅ 功能使用API (核心扣费逻辑) -- ✅ 签到API (签到/日历/历史) -- ✅ 用户资料API -- ✅ 统计API - -### 前端测试覆盖 -- ✅ HomePage组件 -- ✅ Profile组件 -- ✅ CheckIn组件 -- ✅ 用户交互流程 - -### 集成测试覆盖 -- ✅ 用户完整使用流程 -- ✅ 管理员配置流程 -- ✅ VIP功能测试 - ---- - -## 🚀 快速开始 - -### 1. 后端测试 - -#### 环境准备 -```bash -cd tests/backend -pip install -r requirements.txt -``` - -#### 配置测试数据库 -复制 `.env.example` 为 `.env` 并配置: -```env -TEST_DB_HOST=localhost -TEST_DB_USER=root -TEST_DB_PASSWORD=your_password -TEST_DB_NAME=designercep_test -TEST_API_URL=https://backend.aidg168.uk/api/v1 -``` - -#### 运行测试 -```bash -# Windows -run_tests.bat - -# Linux/Mac -chmod +x run_tests.sh -./run_tests.sh - -# 或直接运行pytest -pytest -v -``` - -#### 查看覆盖率报告 -测试完成后,打开 `htmlcov/index.html` 查看代码覆盖率。 - ---- - -### 2. 前端测试 - -#### 环境准备 -```bash -cd Designer -npm install -``` - -#### 配置Vitest -前端项目已配置 Vitest,无需额外配置。 - -#### 运行测试 -```bash -# 运行所有测试 -npm run test - -# 监听模式 -npm run test:watch - -# 生成覆盖率报告 -npm run test:coverage -``` - -#### 单独运行某个测试文件 -```bash -npx vitest tests/frontend/HomePage.test.ts -``` - ---- - -### 3. 集成测试 - -#### 运行E2E测试 -```bash -cd tests/integration -python e2e_test.py -``` - -**注意**: 集成测试需要: -1. 后端服务正常运行 -2. 数据库已完成迁移 -3. 测试用户已创建 - ---- - -## 📊 测试文件结构 - -``` -tests/ -├── backend/ # 后端测试 -│ ├── conftest.py # Pytest配置和fixtures -│ ├── test_admin_config.py # 管理员配置测试 -│ ├── test_feature.py # 功能使用测试 -│ ├── test_checkin.py # 签到功能测试 -│ ├── test_user_profile.py # 用户资料测试 -│ ├── test_stats.py # 统计功能测试 -│ ├── requirements.txt # Python依赖 -│ └── run_tests.bat # Windows测试脚本 -│ -├── frontend/ # 前端测试 -│ ├── HomePage.test.ts # 首页组件测试 -│ ├── Profile.test.ts # 个人中心测试 -│ └── CheckIn.test.ts # 签到页面测试 -│ -├── integration/ # 集成测试 -│ └── e2e_test.py # 端到端测试 -│ -└── README.md # 测试说明文档 -``` - ---- - -## 🧪 测试用例详解 - -### 后端测试 - -#### 1. 管理员配置测试 (`test_admin_config.py`) -```python -class TestFeaturesConfig: - - test_get_features_config() # 获取功能配置列表 - - test_create_feature_config() # 创建新功能 - - test_update_feature_config() # 更新功能配置 - - test_delete_feature_config() # 删除功能配置 - - test_update_nonexistent_feature() # 更新不存在的功能 - -class TestVIPConfig: - - test_get_vip_config() # 获取VIP配置 - - test_update_vip_config() # 更新VIP配置 - -class TestCheckInConfig: - - test_get_checkin_config() # 获取签到配置 - - test_create_checkin_config() # 创建签到档位 - - test_update_checkin_config() # 更新签到档位 -``` - -#### 2. 功能使用测试 (`test_feature.py`) -```python -class TestFeatureUsage: - - test_use_feature_normal_user() # 普通用户使用功能 - - test_use_feature_insufficient_points() # 积分不足 - - test_use_feature_vip_user_with_quota() # VIP用户使用配额 - - test_use_disabled_feature() # 使用已禁用功能 - - test_use_nonexistent_feature() # 不存在的功能 -``` - -#### 3. 签到测试 (`test_checkin.py`) -```python -class TestDailyCheckIn: - - test_first_checkin() # 首次签到 - - test_duplicate_checkin() # 重复签到 - - test_consecutive_checkin_calculation() # 连续天数计算 - - test_broken_consecutive_checkin() # 中断连续签到 - - test_vip_multiplier() # VIP倍数 -``` - -### 前端测试 - -#### 1. HomePage测试 (`HomePage.test.ts`) -```typescript -describe('HomePage', () => { - - it('应该正确渲染组件') - - it('应该显示欢迎信息') - - it('应该显示正确的积分数量') - - it('应该显示VIP状态') - - it('点击功能卡片应该调用使用功能API') - - it('积分不足时应该显示错误提示') -}) -``` - -#### 2. Profile测试 (`Profile.test.ts`) -```typescript -describe('Profile', () => { - - it('应该显示用户基本信息') - - it('应该显示统计数据卡片') - - it('应该能够编辑资料') - - it('应该显示积分历史列表') -}) -``` - -#### 3. CheckIn测试 (`CheckIn.test.ts`) -```typescript -describe('CheckIn', () => { - - it('应该显示签到状态') - - it('未签到时应该显示签到按钮') - - it('点击签到按钮应该调用签到API') - - it('应该显示签到日历') - - it('应该显示签到历史记录') -}) -``` - ---- - -## 🔧 测试工具和技术 - -### 后端测试技术栈 -- **Pytest**: Python测试框架 -- **Requests**: HTTP客户端 -- **PyMySQL**: 数据库连接 -- **pytest-cov**: 代码覆盖率 -- **pytest-html**: HTML测试报告 - -### 前端测试技术栈 -- **Vitest**: Vue3测试框架 -- **@vue/test-utils**: Vue组件测试工具 -- **jsdom**: DOM环境模拟 - ---- - -## 📝 编写新测试 - -### 后端测试示例 - -```python -def test_your_api(test_user): - """测试你的API""" - # 1. 准备数据 - request_data = { - 'username': test_user['username'], - 'param': 'value' - } - - # 2. 调用API - response = requests.post( - f"{API_BASE_URL}/your/endpoint", - json=request_data - ) - - # 3. 断言结果 - assert response.status_code == 200 - data = response.json() - assert data['code'] == 200 - assert data['data']['field'] == expected_value -``` - -### 前端测试示例 - -```typescript -it('应该测试你的功能', async () => { - // 1. Mock API - ;(axios.get as any).mockResolvedValue({ - data: { code: 200, data: mockData } - }) - - // 2. 挂载组件 - const wrapper = mount(YourComponent) - await new Promise(resolve => setTimeout(resolve, 100)) - - // 3. 断言 - expect(wrapper.text()).toContain('期望文本') -}) -``` - ---- - -## ⚠️ 注意事项 - -### 1. 测试数据隔离 -- 后端测试使用独立的测试数据库 -- 每个测试用例结束后自动回滚数据 -- 测试用户名以 `test_` 开头 - -### 2. 异步操作 -```python -# 后端:等待数据库更新 -time.sleep(1) - -# 前端:等待组件更新 -await new Promise(resolve => setTimeout(resolve, 100)) -``` - -### 3. 测试环境变量 -确保测试环境不会影响生产数据: -```env -ENV=test -DB_NAME=designercep_test -API_URL=https://test.backend.aidg168.uk -``` - -### 4. Mock外部依赖 -```typescript -// Mock axios -vi.mock('axios') - -// Mock router -vi.mock('vue-router', () => ({ - useRouter: () => mockRouter -})) -``` - ---- - -## 📈 测试覆盖率目标 - -| 模块 | 目标覆盖率 | 当前状态 | -|------|-----------|---------| -| 后端API | > 80% | ✅ 已达标 | -| 前端组件 | > 70% | ✅ 已达标 | -| 集成测试 | 核心流程全覆盖 | ✅ 已达标 | - ---- - -## 🐛 问题排查 - -### 后端测试失败 - -**问题1**: 数据库连接失败 -``` -解决: 检查 .env 配置,确保测试数据库存在 -``` - -**问题2**: API返回500错误 -``` -解决: 检查后端服务是否正常运行 -``` - -### 前端测试失败 - -**问题1**: 组件挂载失败 -``` -解决: 检查是否正确Mock了所有依赖 -``` - -**问题2**: 异步断言失败 -``` -解决: 增加等待时间或使用 waitFor() -``` - ---- - -## 📊 CI/CD集成 - -### GitHub Actions示例 - -```yaml -name: Tests - -on: [push, pull_request] - -jobs: - backend-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install dependencies - run: | - cd tests/backend - pip install -r requirements.txt - - name: Run tests - run: pytest -v --cov - - frontend-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Node.js - uses: actions/setup-node@v2 - - name: Install dependencies - run: | - cd Designer - npm install - - name: Run tests - run: npm run test -``` - ---- - -## ✅ 测试检查清单 - -### 提交代码前 -- [ ] 所有测试通过 -- [ ] 新功能已添加测试 -- [ ] 测试覆盖率达标 -- [ ] 无eslint/pylint警告 - -### 发布前 -- [ ] 运行完整测试套件 -- [ ] 运行E2E集成测试 -- [ ] 检查测试报告 -- [ ] 验证关键流程 - ---- - -## 📚 参考资料 - -- [Pytest文档](https://docs.pytest.org/) -- [Vitest文档](https://vitest.dev/) -- [Vue Test Utils](https://test-utils.vuejs.org/) -- [Testing Best Practices](https://testingjavascript.com/) - ---- - -**测试是质量的保证!** 🎯 - diff --git a/temp_backup/Server_redundant/tests/测试运行报告_20251221.md b/temp_backup/Server_redundant/tests/测试运行报告_20251221.md deleted file mode 100644 index 9cde3d7..0000000 --- a/temp_backup/Server_redundant/tests/测试运行报告_20251221.md +++ /dev/null @@ -1,307 +0,0 @@ -# 🧪 测试运行报告 - -## 测试执行时间 -**2025-12-21 20:10** - ---- - -## 📊 测试结果总结 - -### 后端测试 ⚠️ - -**状态**: 环境就绪,但需要配置 - -#### 问题 -1. ✅ 测试依赖已安装成功 -2. ❌ 后端API路由未在生产环境注册 -3. ❌ 测试数据库未配置 - -#### 测试环境状态 -- ✅ pytest 7.4.3 已安装 -- ✅ requests 2.31.0 已安装 -- ✅ pymysql 1.1.0 已安装 -- ✅ pytest-cov 4.1.0 已安装 -- ✅ pytest-html 4.1.1 已安装 - -#### 执行结果 -``` -测试文件: test_admin_config.py -状态: FAILED -原因: API返回404 (路由未注册) - -测试文件: e2e_test.py -状态: FAILED -原因: API返回404 (路由未注册) -``` - ---- - -### 前端测试 ⚠️ - -**状态**: 环境就绪,但需要额外依赖 - -#### 问题 -1. ✅ vitest 1.6.0 已安装 -2. ✅ 测试脚本已添加到package.json -3. ❌ 缺少 @vue/test-utils 和 jsdom -4. ❌ npm安装命令执行失败 - -#### 测试脚本已添加 -```json -"test": "vitest run", -"test:watch": "vitest", -"test:ui": "vitest --ui", -"test:coverage": "vitest run --coverage" -``` - ---- - -## 🔧 需要解决的问题 - -### 1. 后端API路由注册 ⭐⭐⭐ (最重要) - -**问题**: 新增的API路由未在 `Server/app/main.py` 中正确注册 - -**检查**: -```python -# Server/app/main.py 应该包含: -from app.api.v1 import admin_config, feature, checkin, user_profile, stats - -app.include_router(admin_config.router, prefix=settings.API_V1_STR, tags=["admin-config"]) -app.include_router(feature.router, prefix=settings.API_V1_STR, tags=["feature"]) -app.include_router(checkin.router, prefix=settings.API_V1_STR, tags=["checkin"]) -app.include_router(user_profile.router, prefix=settings.API_V1_STR, tags=["user-profile"]) -app.include_router(stats.router, prefix=settings.API_V1_STR, tags=["stats"]) -``` - -**解决方案**: -1. 确认 main.py 中已正确导入和注册路由 -2. 重启后端服务: `docker-compose restart backend` -3. 验证路由: `curl https://backend.aidg168.uk/api/v1/admin/config/features` - ---- - -### 2. 测试数据库配置 - -**问题**: 后端测试需要测试数据库 - -**解决方案**: -创建 `tests/backend/.env` 文件: -```env -TEST_DB_HOST=localhost -TEST_DB_USER=root -TEST_DB_PASSWORD=your_password -TEST_DB_NAME=designercep_test -TEST_API_URL=https://backend.aidg168.uk/api/v1 -``` - -然后创建测试数据库: -```bash -mysql -u root -p -CREATE DATABASE designercep_test; -USE designercep_test; -SOURCE D:/main/DesignerCEP/Server/migrations/001_add_points_vip_checkin.sql; -``` - ---- - -### 3. 前端测试依赖安装 - -**问题**: npm安装失败 - -**解决方案**: - -**方法1**: 清理npm缓存 -```bash -cd Designer -npm cache clean --force -npm install --save-dev @vue/test-utils @vitest/ui jsdom -``` - -**方法2**: 删除node_modules重新安装 -```bash -cd Designer -rm -rf node_modules package-lock.json -npm install -npm install --save-dev @vue/test-utils @vitest/ui jsdom -``` - -**方法3**: 手动创建vitest.config.ts -```typescript -import { defineConfig } from 'vitest/config' -import vue from '@vitejs/plugin-vue' -import path from 'path' - -export default defineConfig({ - plugins: [vue()], - test: { - globals: true, - environment: 'jsdom', - }, - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, -}) -``` - ---- - -## ✅ 测试执行步骤(修复后) - -### 后端测试 -```bash -# 1. 配置测试数据库 -cd tests/backend -# 创建 .env 文件 - -# 2. 运行所有测试 -pytest -v - -# 3. 运行特定测试 -pytest test_admin_config.py -v - -# 4. 生成覆盖率报告 -pytest --cov=../../Server/app/api/v1 --cov-report=html - -# 5. 查看报告 -# 打开 htmlcov/index.html -``` - -### 前端测试 -```bash -# 1. 安装依赖 -cd Designer -npm install --save-dev @vue/test-utils @vitest/ui jsdom - -# 2. 运行测试 -npm run test - -# 3. 监听模式 -npm run test:watch - -# 4. 生成覆盖率 -npm run test:coverage -``` - -### 集成测试 -```bash -# 需要后端服务正常运行 -cd tests/integration -python e2e_test.py -``` - ---- - -## 📋 测试文件清单 - -### 后端测试 (已创建) ✅ -- `tests/backend/conftest.py` (169行) -- `tests/backend/test_admin_config.py` (267行) -- `tests/backend/test_feature.py` (163行) -- `tests/backend/test_checkin.py` (239行) -- `tests/backend/test_user_profile.py` (169行) -- `tests/backend/test_stats.py` (147行) -- `tests/backend/run_tests.bat` -- `tests/backend/requirements.txt` - -### 前端测试 (已创建) ✅ -- `tests/frontend/HomePage.test.ts` (211行) -- `tests/frontend/Profile.test.ts` (181行) -- `tests/frontend/CheckIn.test.ts` (246行) - -### 集成测试 (已创建) ✅ -- `tests/integration/e2e_test.py` (219行) - -### 文档 (已创建) ✅ -- `tests/README.md` -- `tests/测试文档.md` -- `tests/测试交付报告.md` - ---- - -## 🎯 下一步行动 - -### 立即执行(按优先级) - -1. **修复后端API路由** ⭐⭐⭐ - ```bash - # 检查 Server/app/main.py - # 确认路由已注册 - # 重启服务 - docker-compose restart backend - ``` - -2. **配置测试数据库** - ```bash - # 创建测试数据库 - # 执行迁移脚本 - ``` - -3. **修复npm安装问题** - ```bash - cd Designer - npm cache clean --force - npm install - ``` - -4. **运行测试** - ```bash - # 后端测试 - cd tests/backend - pytest -v - - # 前端测试 - cd Designer - npm run test - ``` - ---- - -## 📊 预期测试结果 - -修复上述问题后,预期测试结果: - -### 后端测试 -- ✅ test_admin_config.py: 约15个测试用例 PASS -- ✅ test_feature.py: 约10个测试用例 PASS -- ✅ test_checkin.py: 约12个测试用例 PASS -- ✅ test_user_profile.py: 约10个测试用例 PASS -- ✅ test_stats.py: 约8个测试用例 PASS -- **总计**: ~55个测试用例 - -### 前端测试 -- ✅ HomePage.test.ts: 约10个测试用例 PASS -- ✅ Profile.test.ts: 约8个测试用例 PASS -- ✅ CheckIn.test.ts: 约12个测试用例 PASS -- **总计**: ~30个测试用例 - -### 集成测试 -- ✅ e2e_test.py: 3个场景测试 PASS - ---- - -## 总结 - -### 当前状态 -- ✅ 测试代码已完整编写 -- ✅ 测试环境基本就绪 -- ⚠️ 需要修复3个配置问题 -- ⏳ 待执行完整测试套件 - -### 预计修复时间 -- 后端路由注册: 5分钟 -- 测试数据库配置: 10分钟 -- npm依赖安装: 5分钟 -- **总计**: 约20分钟 - -### 修复后即可 -- ✅ 运行80+个自动化测试 -- ✅ 生成测试覆盖率报告 -- ✅ 验证所有功能正常 - ---- - -**测试代码质量优秀,修复配置问题后即可投入使用!** 🚀 - diff --git a/temp_backup/Server_redundant/verify_routes.py b/temp_backup/Server_redundant/verify_routes.py deleted file mode 100644 index a2722fa..0000000 --- a/temp_backup/Server_redundant/verify_routes.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys -import os -from fastapi.routing import APIRoute - -# 添加 Server 目录到 Python 路径 -sys.path.append(os.path.join(os.getcwd(), 'Server')) - -try: - from app.main import app - - print("="*60) - print("🔍 DesignerCEP 后端路由表检查") - print("="*60) - - routes = [] - for route in app.routes: - if isinstance(route, APIRoute): - methods = ",".join(route.methods) - routes.append(f"{methods:<20} {route.path}") - - # 排序以便查看 - routes.sort(key=lambda x: x.split()[1]) - - for r in routes: - print(r) - - print("="*60) - print(f"✅ 总计: {len(routes)} 个路由") - -except Exception as e: - print(f"❌ 加载应用失败: {e}") - import traceback - traceback.print_exc() diff --git a/开发准则.md b/开发准则.md index 440664d..659a028 100644 --- a/开发准则.md +++ b/开发准则.md @@ -6,13 +6,88 @@ ## 2. 技术栈 +### 2.1 核心框架与语言 + - **核心框架**: Vue 3 (Composition API + `