feat: AI套图分层方案 + Gemini集成 - 4种图案类型处理 + 正片叠底 + 宽高比 + 模型选择
Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -13,7 +13,7 @@ const config: ICepConfig = {
|
||||
"panels": [
|
||||
{
|
||||
"name": "AdminPanel-dev",
|
||||
"displayName": "管理面板",
|
||||
"displayName": "ps套版",
|
||||
"main": "./index.html",
|
||||
"width": 280,
|
||||
"height": 600,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="/CSInterface.js"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
3
AdminPanel/plugins/jsx/template/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 目录说明
|
||||
- cep 插件壳模板文件
|
||||
- cep.config.json 配置文件
|
||||
65
AdminPanel/plugins/jsx/template/cep.config.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { ICepConfig } from "@plugins";
|
||||
|
||||
const config: ICepConfig = {
|
||||
name: "cepName",
|
||||
id: "com.cepName",
|
||||
version: "1.0.0",
|
||||
extensionVersion: "6.1.0",
|
||||
requiredRuntimeVersion: "9.0",
|
||||
type: "Panel",
|
||||
parameters: [
|
||||
"--enable-nodejs",
|
||||
],
|
||||
panels: [
|
||||
{
|
||||
name: "cepName",
|
||||
displayName: "panelName",
|
||||
main: "./index.html",
|
||||
width: 400,
|
||||
height: 300,
|
||||
minWidth: 400,
|
||||
minHeight: 300,
|
||||
maxWidth: 4000,
|
||||
maxHeight: 3000,
|
||||
}
|
||||
],
|
||||
hosts:[
|
||||
{
|
||||
name: "AEFT",
|
||||
version: "[0.0,99.9]",
|
||||
},
|
||||
{
|
||||
name: "PPRO",
|
||||
version: "[0.0,99.9]",
|
||||
},
|
||||
{
|
||||
name: "ILST",
|
||||
version: "[0.0,99.9]",
|
||||
},
|
||||
{
|
||||
name: "PHXS",
|
||||
version: "[0.0,99.9]",
|
||||
},
|
||||
{
|
||||
name: "FLPR",
|
||||
version: "[0.0,99.9]",
|
||||
},
|
||||
],
|
||||
build: {
|
||||
jsxBin: false,
|
||||
/**国家 */
|
||||
country: "CN",
|
||||
/**省份 */
|
||||
province: "GD",
|
||||
/**公司名称 */
|
||||
org: "你的公司名称",
|
||||
/**签名密码 */
|
||||
password: "",
|
||||
tsa: "",
|
||||
},
|
||||
zxp: {
|
||||
jsxBin: false
|
||||
}
|
||||
}
|
||||
|
||||
export default config;
|
||||
21
AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId="com.temp.id" ExtensionBundleVersion="1.0" Version="6.0"> <!-- MAJOR-VERSION-UPDATE-MARKER -->
|
||||
<ExtensionList>
|
||||
<Extension Id="com.temp.id" Version="6.1.0"/>
|
||||
</ExtensionList>
|
||||
<ExecutionEnvironment>
|
||||
<HostList>
|
||||
<Host Name="PHXS" Version="[11.0,99.9]"/>
|
||||
<Host Name="ILST" Version="[11.0,99.9]"/>
|
||||
</HostList>
|
||||
<LocaleList>
|
||||
<Locale Code="All"/>
|
||||
</LocaleList>
|
||||
<RequiredRuntimeList>
|
||||
<RequiredRuntime Name="CSXS" Version="7.0"/> <!-- MAJOR-VERSION-UPDATE-MARKER -->
|
||||
</RequiredRuntimeList>
|
||||
</ExecutionEnvironment>
|
||||
<DispatchInfoList>
|
||||
|
||||
</DispatchInfoList>
|
||||
</ExtensionManifest>
|
||||
BIN
AdminPanel/plugins/jsx/template/cep/img/dark.png
Normal file
|
After Width: | Height: | Size: 475 B |
BIN
AdminPanel/plugins/jsx/template/cep/img/dark@2x.png
Normal file
|
After Width: | Height: | Size: 846 B |
BIN
AdminPanel/plugins/jsx/template/cep/img/dark@3x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
AdminPanel/plugins/jsx/template/cep/img/dark@4x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
AdminPanel/plugins/jsx/template/cep/img/highlight.png
Normal file
|
After Width: | Height: | Size: 475 B |
BIN
AdminPanel/plugins/jsx/template/cep/img/highlight@2x.png
Normal file
|
After Width: | Height: | Size: 846 B |
BIN
AdminPanel/plugins/jsx/template/cep/img/highlight@3x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
AdminPanel/plugins/jsx/template/cep/img/highlight@4x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
16
AdminPanel/plugins/jsx/template/cep/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{name}}</title>
|
||||
<script>
|
||||
window.location.href = "{{serverURL}}"
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
15
AdminPanel/plugins/jsx/template/debug.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export function joinDebug(id: string, hosts: { name: string }[]) {
|
||||
let port = 7090
|
||||
return `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ExtensionList>
|
||||
<Extension Id="${id}">
|
||||
<HostList>
|
||||
${hosts
|
||||
.map((host) => `<Host Name="${host.name}" Port="${port++}"/>`)
|
||||
.join("\n")}
|
||||
</HostList>
|
||||
</Extension>
|
||||
</ExtensionList>
|
||||
`
|
||||
}
|
||||
15
AdminPanel/plugins/jsx/template/html.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export function joinHtml(name:string,server:string){
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>${name}</title>
|
||||
<script>
|
||||
// 跳转到开发服务器地址
|
||||
window.location.href = "${server}";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
66
AdminPanel/plugins/jsx/template/manifest.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { ICepConfig } from "../types";
|
||||
|
||||
export function joinManifest(config: ICepConfig) {
|
||||
const { id, version, extensionVersion, requiredRuntimeVersion, hosts, parameters, panels } = config
|
||||
const mainId=`${id}`
|
||||
const panel = panels[0]
|
||||
return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId="${id}.body" ExtensionBundleVersion="1.0" Version="6.0"> <!-- MAJOR-VERSION-UPDATE-MARKER -->
|
||||
<ExtensionList>
|
||||
<Extension Id="${mainId}" Version="${extensionVersion}"/>
|
||||
</ExtensionList>
|
||||
<ExecutionEnvironment>
|
||||
<HostList>
|
||||
${hosts.map(item => `<Host Name="${item.name}" Version="${item.version}"/>`).join("\n")}
|
||||
</HostList>
|
||||
<LocaleList>
|
||||
<Locale Code="All"/>
|
||||
</LocaleList>
|
||||
<RequiredRuntimeList>
|
||||
<RequiredRuntime Name="CSXS" Version="${requiredRuntimeVersion}"/> <!-- MAJOR-VERSION-UPDATE-MARKER -->
|
||||
</RequiredRuntimeList>
|
||||
</ExecutionEnvironment>
|
||||
<DispatchInfoList>
|
||||
<Extension Id="${mainId}">
|
||||
<DispatchInfo>
|
||||
<Resources>
|
||||
<MainPath>./index.html</MainPath>
|
||||
<!-- <ScriptPath>./jsx/core.jsx</ScriptPath> -->
|
||||
<CEFCommandLine>
|
||||
${parameters.map(item => `<Parameter>${item}</Parameter>`).join("\n")}
|
||||
</CEFCommandLine>
|
||||
</Resources>
|
||||
<Lifecycle>
|
||||
<AutoVisible>true</AutoVisible>
|
||||
</Lifecycle>
|
||||
<UI>
|
||||
<Type>Panel</Type>
|
||||
<Menu>${panel.displayName}</Menu>
|
||||
<Geometry>
|
||||
<Size>
|
||||
<Height>${panel.height}</Height>
|
||||
<Width>${panel.width}</Width>
|
||||
</Size>
|
||||
<MaxSize>
|
||||
<Height>${panel.maxHeight||panel.height}</Height>
|
||||
<Width>${panel.maxWidth||panel.width}</Width>
|
||||
</MaxSize>
|
||||
<MinSize>
|
||||
<Height>${panel.minHeight||panel.height}</Height>
|
||||
<Width>${panel.minWidth||panel.width}</Width>
|
||||
</MinSize>
|
||||
</Geometry>
|
||||
<Icons>
|
||||
<Icon Type="Normal">./img/highlight.png</Icon>
|
||||
<Icon Type="RollOver">./img/dark.png</Icon>
|
||||
<Icon Type="DarkNormal">./img/highlight.png</Icon>
|
||||
<Icon Type="DarkRollOver">./img/dark.png</Icon>
|
||||
</Icons>
|
||||
</UI>
|
||||
</DispatchInfo>
|
||||
</Extension>
|
||||
</DispatchInfoList>
|
||||
</ExtensionManifest>
|
||||
|
||||
`
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -5,10 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTheme } from '@/hooks/useTheme'
|
||||
|
||||
// 初始化主题
|
||||
const { isDark } = useTheme()
|
||||
// 主题初始化已在 main.ts 中完成
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { isNodeJSEnabled } from "./tool"
|
||||
console.error('isNodeJSEnabled()'+isNodeJSEnabled());
|
||||
|
||||
/**
|
||||
* cep_node 为ps内置的全局变量
|
||||
|
||||
@@ -107,8 +107,31 @@ export const updateTheme = () => {
|
||||
const isLight = brightness > 128;
|
||||
|
||||
applyTheme(bgColorHex, isLight, skinInfo.baseFontSize);
|
||||
|
||||
// 发送主题给 iframe
|
||||
const iframe = document.querySelector('iframe');
|
||||
if (iframe && iframe.contentWindow) {
|
||||
const message: PSThemeMessage = {
|
||||
type: 'PS_THEME',
|
||||
theme: {
|
||||
bgColor: bgColorHex,
|
||||
isLight: isLight,
|
||||
fontSize: skinInfo.baseFontSize
|
||||
}
|
||||
};
|
||||
iframe.contentWindow.postMessage(message, '*');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理来自子 iframe 的请求
|
||||
*/
|
||||
function handleChildMessage(event: MessageEvent) {
|
||||
if (event.data && event.data.type === 'REQUEST_THEME') {
|
||||
updateTheme();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理来自父窗口的主题消息(iframe 模式)
|
||||
*/
|
||||
@@ -138,6 +161,8 @@ export const initThemeListener = () => {
|
||||
logger.log('[Theme] CEP 模式 - 直接监听主题变化');
|
||||
updateTheme();
|
||||
cep.addEventListener('com.adobe.csxs.events.ThemeColorChanged', updateTheme);
|
||||
// 监听来自 iframe 的请求
|
||||
window.addEventListener('message', handleChildMessage);
|
||||
} else {
|
||||
// 纯浏览器模式
|
||||
logger.log('[Theme] 浏览器模式 - 使用默认主题');
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
<template>
|
||||
<div class="iframe-container">
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="toolbar">
|
||||
<a-button size="small" @click="goBack">
|
||||
<template #icon><icon-arrow-left /></template>
|
||||
返回
|
||||
</a-button>
|
||||
<span class="url-display">{{ currentUrl }}</span>
|
||||
<a-button size="small" @click="reload">
|
||||
<template #icon><icon-refresh /></template>
|
||||
刷新
|
||||
</a-button>
|
||||
<a-button size="small" @click="openExternal">
|
||||
<template #icon><icon-export /></template>
|
||||
外部打开
|
||||
</a-button>
|
||||
</div>
|
||||
<!-- 顶部工具栏 (已移除) -->
|
||||
|
||||
<!-- 加载指示器 -->
|
||||
<div v-if="loading" class="loading-overlay">
|
||||
<a-spin size="32" />
|
||||
<p>加载中...</p>
|
||||
<p style="font-size:12px;color:#999;margin-top:10px;">目标地址: {{ currentUrl }}</p>
|
||||
<p style="font-size:12px;color:#999;">开发环境: {{ isDev ? '是' : '否' }}</p>
|
||||
</div>
|
||||
|
||||
<!-- iframe -->
|
||||
@@ -36,39 +23,21 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { IconArrowLeft, IconRefresh, IconExport } from '@arco-design/web-vue/es/icon'
|
||||
import { updateTheme } from '@/utils/theme'
|
||||
|
||||
const router = useRouter()
|
||||
const frameRef = ref<HTMLIFrameElement | null>(null)
|
||||
const loading = ref(true)
|
||||
const isDev = ref(typeof __DEV__ !== 'undefined' ? __DEV__ : false)
|
||||
|
||||
const currentUrl = ref(
|
||||
localStorage.getItem('adminPanelUrl') || (
|
||||
__DEV__
|
||||
? 'http://localhost:5173'
|
||||
: 'https://app.aidg168.uk'
|
||||
)
|
||||
localStorage.getItem('adminPanelUrl') || 'http://localhost:5173'
|
||||
)
|
||||
|
||||
function goBack() {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
function reload() {
|
||||
loading.value = true
|
||||
if (frameRef.value) {
|
||||
frameRef.value.src = currentUrl.value
|
||||
}
|
||||
}
|
||||
|
||||
function openExternal() {
|
||||
window.open(currentUrl.value, '_blank')
|
||||
}
|
||||
|
||||
function onFrameLoad() {
|
||||
loading.value = false
|
||||
console.log('✅ iframe 加载完成')
|
||||
// iframe 加载完成后立即同步主题
|
||||
updateTheme()
|
||||
}
|
||||
|
||||
function onFrameError(e: Event) {
|
||||
@@ -94,24 +63,6 @@ onMounted(() => {
|
||||
background: var(--ps-bg, #1e1e1e);
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: var(--color-bg-2, #2d2d2d);
|
||||
border-bottom: 1px solid var(--ps-border, #444);
|
||||
}
|
||||
|
||||
.url-display {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
color: var(--ps-text, #aaa);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.main-frame {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
|
||||
@@ -19,7 +19,7 @@ export default defineConfig(({ command }) => {
|
||||
legacy({
|
||||
targets: ['chrome 41', 'not IE 11']
|
||||
}),
|
||||
!isBuild && cepPlugin(), // 开发时自动复制到 PS 扩展目录
|
||||
cepPlugin(), // 开发时自动复制到 PS 扩展目录,构建时生成 CEP 结构
|
||||
vue(),
|
||||
tsconfigPaths(),
|
||||
],
|
||||
|
||||