Initial commit - DesignerCEP Project with Caddy deployment
This commit is contained in:
355
tempdocs/混合架构快速开发模板.md
Normal file
355
tempdocs/混合架构快速开发模板.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# 混合架构快速开发模板
|
||||
|
||||
## 🚀 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<JSXResponse> {
|
||||
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
|
||||
<template>
|
||||
<a-button type="primary" @click="handleYourFeature">
|
||||
你的功能
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { yourFeatureFunction } from '@/api/jsxApi/inline/your-feature';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const handleYourFeature = async () => {
|
||||
try {
|
||||
Message.loading('处理中...');
|
||||
|
||||
// 调用混合 API
|
||||
const res = await yourFeatureFunction('测试参数', 100);
|
||||
|
||||
if (res && res.success) {
|
||||
Message.success(res.message || '操作成功');
|
||||
} else {
|
||||
Message.error(res?.error || '执行失败');
|
||||
}
|
||||
} catch (e: any) {
|
||||
Message.error('调用失败: ' + e.message);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 开发流程
|
||||
|
||||
### 本地测试
|
||||
```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 分钟/功能** ⚡
|
||||
|
||||
Reference in New Issue
Block a user