| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>生成模板 - 文生图</title>
- <!-- 引入Font Awesome图标 -->
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- <!-- 引入自定义CSS -->
- <link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico"/>
- <style>
- /* 自定义提示框样式 */
- .custom-alert {
- position: fixed;
- top: 10%;
- left: 50%;
- transform: translate(-50%, -50%);
- padding: 15px 25px;
- border-radius: 8px;
- color: white;
- font-size: 14px;
- font-weight: 500;
- z-index: 10000;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
- opacity: 0;
- visibility: hidden;
- transition: all 0.3s ease;
- max-width: 80%;
- text-align: center;
- }
- .custom-alert.show {
- opacity: 1;
- visibility: visible;
- }
- .custom-alert.error {
- background-color: #e74c3c;
- }
- .custom-alert.success {
- background-color: #28a745;
- }
- .custom-alert.warning {
- background-color: #ffc107;
- color: #333;
- }
- .custom-alert.info {
- background-color: #17a2b8;
- }
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- /* 标题样式 */
- .page-title {
- font-size: 24px;
- font-weight: bold;
- margin-bottom: 25px;
- color: #333;
- }
- /* 内容区域 */
- .content-area {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 30px;
- }
- /* 左侧输入区域 */
- .input-section {
- background-color: #fff;
- border-radius: 8px;
- padding: 20px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
- }
- /* 右侧预览区域 */
- .preview-section {
- background-color: #fff;
- border-radius: 8px;
- padding: 20px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
- }
- /* 表单组样式 */
- .form-group {
- margin-bottom: 20px;
- }
- .form-group label {
- display: block;
- font-size: 14px;
- font-weight: bold;
- color: #333;
- margin-bottom: 8px;
- }
- /* 文本输入区域 */
- .prompt-textarea {
- width: 100%;
- height: 150px;
- padding: 12px;
- border: 1px solid #ddd;
- border-radius: 8px;
- resize: vertical;
- font-size: 14px;
- line-height: 1.5;
- }
- /* 参数设置区域 */
- .params-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
- gap: 15px;
- }
- .param-item {
- margin-bottom: 15px;
- }
- .param-item label {
- display: block;
- font-size: 13px;
- font-weight: bold;
- color: #333;
- margin-bottom: 5px;
- }
- .param-item select, .param-item input[type="number"] {
- width: 100%;
- padding: 8px 12px;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-size: 14px;
- }
- /* 提示词示例 */
- .prompt-examples {
- background-color: #f8f9fa;
- border-radius: 8px;
- padding: 15px;
- margin-bottom: 20px;
- }
- .prompt-examples h4 {
- font-size: 14px;
- font-weight: bold;
- margin-bottom: 10px;
- color: #333;
- }
- .example-list {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- }
- .example-tag {
- font-size: 12px;
- background-color: #e9ecef;
- color: #666;
- padding: 4px 10px;
- border-radius: 4px;
- cursor: pointer;
- transition: background-color 0.2s;
- }
- .example-tag:hover {
- background-color: #dee2e6;
- }
- /* 按钮样式 */
- .button-group {
- display: flex;
- gap: 10px;
- }
- .btn {
- padding: 12px 24px;
- border: none;
- border-radius: 8px;
- font-size: 14px;
- cursor: pointer;
- transition: background-color 0.2s;
- }
- .btn-primary {
- background-color: #007bff;
- color: #fff;
- }
- .btn-primary:hover {
- background-color: #0056b3;
- }
- .btn-secondary {
- background-color: #6c757d;
- color: #fff;
- }
- .btn-secondary:hover {
- background-color: #545b62;
- }
- /* 预览区域 */
- .preview-container {
- width: 100%;
- min-height: 300px;
- background-color: #f8f9fa;
- border-radius: 8px;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-bottom: 20px;
- overflow: hidden;
- }
- .preview-image {
- max-width: 100%;
- max-height: 100%;
- object-fit: contain;
- }
- .preview-placeholder {
- font-size: 14px;
- color: #666;
- text-align: center;
- }
- /* 模板信息 */
- .template-info {
- margin-bottom: 20px;
- }
- .template-info h4 {
- font-size: 14px;
- font-weight: bold;
- margin-bottom: 10px;
- color: #333;
- }
- .template-form input {
- width: 100%;
- padding: 10px 12px;
- border: 1px solid #ddd;
- border-radius: 8px;
- font-size: 14px;
- margin-bottom: 10px;
- }
- /* 响应式设计 */
- @media (max-width: 768px) {
- .content-area {
- grid-template-columns: 1fr;
- }
- .clear-btn, .optimize-btn, .arrow-btn {
- flex: 1;
- }
- }
- .optimize-btn {
- background-color: #ffffff;
- color: #4b5563;
- padding: 10px 18px;
- border: 1px solid #d1d5db;
- border-radius: 8px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- gap: 6px;
- }
- .optimize-btn:hover {
- background-color: #f9fafb;
- border-color: #9ca3af;
- transform: translateY(-1px);
- }
- .clear-btn {
- background-color: #ffffff;
- color: #dc3545;
- border: 1px solid #f87171;
- border-radius: 8px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
- display: flex;
- align-items: center;
- gap: 6px;
- }
- .clear-btn:hover {
- background-color: #fee2e2;
- border-color: #ef4444;
- transform: translateY(-1px);
- }
- /* 操作按钮 */
- .prompt-actions {
- gap: 8px;
- }
- .clear-btn, .optimize-btn {
- padding: 8px 12px;
- font-size: 13px;
- }
- /* 菜单样式 */
- .menu-container {
- background-color: #f5f7fa;
- border-radius: 8px;
- padding: 10px;
- margin-bottom: 20px;
- display: flex;
- gap: 10px;
- }
- .menu-item {
- flex: 1;
- }
- .menu-item a {
- display: block;
- padding: 12px;
- background-color: white;
- border: 1px solid #e1e8ed;
- border-radius: 6px;
- text-align: center;
- text-decoration: none;
- color: #657786;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.3s ease;
- }
- .menu-item a:hover {
- background-color: #e8f0fe;
- border-color: #1da1f2;
- color: #1da1f2;
- }
- .menu-item.active a {
- background-color: #1da1f2;
- border-color: #1da1f2;
- color: white;
- }
- .menu-item i {
- margin-right: 6px;
- font-size: 16px;
- }
- </style>
- </head>
- <body>
- <div class="container">
- <!-- 菜单功能区 -->
- <div class="menu-container">
- <div class="menu-item active">
- <a href="{:url('user/index')}">
- <i class="fas fa-image"></i>
- 文生图
- </a>
- </div>
- <div class="menu-item">
- <a href="{:url('user/text_to_video')}">
- <i class="fas fa-video"></i>
- 文生视频
- </a>
- </div>
- </div>
- <div class="content-area">
- <!-- 左侧输入区域 -->
- <div class="input-section">
- <h3 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">文生图生成参数设置</h3>
- <!-- 提示词示例 -->
- <div class="prompt-examples">
- <label for="prompt">提示词</label>
- <textarea id="prompt" class="prompt-textarea" placeholder="请输入您想要生成的图像描述,越详细越好..."></textarea>
- </div>
- <!-- 生成参数 -->
- <div class="form-group">
- <label>生成参数</label>
- <div class="params-grid">
- <div class="param-item">
- <label for="style">风格</label>
- <select id="style">
- <option value="">默认</option>
- <option value="anime">动漫</option>
- <option value="oil">油画</option>
- <option value="landscape">风景</option>
- <option value="portrait">人像</option>
- </select>
- </div>
- <div class="param-item">
- <label for="imageSize">尺寸</label>
- <select id="imageSize">
- <option value="1:1">1:1</option>
- <option value="4:3">4:3</option>
- <option value="3:4">3:4</option>
- <option value="16:9">16:9</option>
- <option value="9:16">9:16</option>
- </select>
- </div>
- </div>
- </div>
- <div class="button-group">
- <button class="clear-btn" onclick="clearPrompt()">
- <i class="fas fa-trash"></i>
- 清空
- </button>
- <button class="optimize-btn" onclick="optimizePrompt()">
- <i class="fas fa-magic"></i>
- 一键优化
- </button>
- <button class="btn btn-primary" id="generateBtn" onclick="generateImage()">
- <i class="fas fa-arrow-up"></i>
- 生成图像
- </button>
- </div>
- </div>
- <!-- 右侧预览区域 -->
- <div class="preview-section">
- <h3 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">图像预览</h3>
- <!-- 预览容器 -->
- <div id="imageResult" class="preview-container">
- <div class="preview-placeholder">
- <p>点击"生成图像"按钮开始创建您的模板</p>
- <p style="font-size: 12px; margin-top: 10px; color: #999;">生成时间可能需要几秒到几十秒不等</p>
- </div>
- </div>
- <!-- 模板信息 -->
- <div class="template-info">
- <h4>模板信息</h4>
- <div class="template-form">
- <input type="text" id="templateName" placeholder="请输入模板名称">
- </div>
- </div>
- <!-- 保存按钮 -->
- <div class="button-group">
- <button class="btn btn-primary" id="saveBtn" disabled onclick="saveTemplate()">保存为模板</button>
- <button class="btn btn-secondary" id="downloadBtn" disabled onclick="downloadImage()">下载图像</button>
- </div>
- </div>
- </div>
- </div>
- <script>
- // 自定义提示框函数
- function showAlert(message, type = 'info', duration = 3000) {
- // 检查是否已存在提示框容器,如果不存在则创建
- let alertElement = document.getElementById('customAlert');
- if (!alertElement) {
- alertElement = document.createElement('div');
- alertElement.id = 'customAlert';
- alertElement.className = 'custom-alert';
- document.body.appendChild(alertElement);
- }
- alertElement.textContent = message;
- alertElement.className = `custom-alert ${type}`;
- // 显示提示框
- alertElement.classList.add('show');
- // 自动隐藏
- setTimeout(() => {
- alertElement.classList.remove('show');
- }, duration);
- }
- // 生成图片函数
- function generateImage() {
- const promptText = document.querySelector('.prompt-textarea').value.trim();
- const imageStyle = document.getElementById('style').value;
- const imageSize = document.getElementById('imageSize').value;
- const imageResultDiv = document.getElementById('imageResult');
- // 检查是否有提示词
- if (!promptText) {
- showAlert('请先输入图片描述', 'warning');
- return;
- }
- // 显示加载状态
- imageResultDiv.innerHTML = `
- <div class="image-loading">
- <i class="fas fa-spinner fa-spin"></i>
- <p>正在生成图片,请稍候...</p>
- <p style="font-size: 12px; margin-top: 10px; color: #999;">生成时间可能需要几秒到几十秒不等</p>
- </div>
- `;
- // 拼接风格和尺寸到提示词末尾
- let fullPrompt = promptText;
- if (imageStyle) {
- fullPrompt += '风格:' + imageStyle;
- }
- if (imageSize) {
- fullPrompt += '尺寸比例:' + imageSize;
- }
- // 发送请求到文生图接口
- $.ajax({
- url: '/index.php/api/work_order/GetTxtToImg',
- type: 'POST',
- dataType: 'json',
- data: {
- status_val: '文生图',
- prompt: fullPrompt,
- model: 'gemini-3-pro-image-preview',
- style: imageStyle,
- size: imageSize
- },
- success: function(response) {
- // 处理成功响应
- if (response.code === 0 && response.data && response.data.url) {
- // 显示生成的图片
- imageResultDiv.innerHTML = `
- <div class="image-container">
- <img src="${response.data.url}" alt="生成的图片" class="generated-image" id="previewImage" style="max-width: 100%; height: auto; max-height: 600px; cursor: pointer;">
- </div>
- `;
- // 启用下载和保存按钮
- document.getElementById('downloadBtn').disabled = false;
- document.getElementById('saveBtn').disabled = false;
- // 添加图片放大模态框(如果还不存在)
- if (!document.getElementById('imageModal')) {
- const modal = document.createElement('div');
- modal.id = 'imageModal';
- modal.style.cssText = `
- display: none;
- position: fixed;
- z-index: 9999;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- background-color: rgba(0, 0, 0, 0.9);
- justify-content: center;
- align-items: center;
- `;
- modal.style.display = 'flex';
- modal.style.display = 'none';
- const modalContent = document.createElement('img');
- modalContent.id = 'modalImage';
- modalContent.style.cssText = `
- max-width: 90%;
- max-height: 90%;
- margin: auto;
- `;
- const closeBtn = document.createElement('span');
- closeBtn.innerHTML = '×';
- closeBtn.style.cssText = `
- position: absolute;
- top: 20px;
- right: 35px;
- color: #f1f1f1;
- font-size: 40px;
- font-weight: bold;
- transition: 0.3s;
- cursor: pointer;
- `;
- closeBtn.onclick = function() {
- modal.style.display = 'none';
- };
- modal.appendChild(closeBtn);
- modal.appendChild(modalContent);
- document.body.appendChild(modal);
- // 点击模态框背景关闭
- modal.onclick = function(event) {
- if (event.target.id === 'imageModal') {
- this.style.display = 'none';
- }
- };
- }
- // 为生成的图片添加点击事件
- const generatedImage = imageResultDiv.querySelector('.generated-image');
- generatedImage.onclick = function() {
- const modal = document.getElementById('imageModal');
- const modalImage = document.getElementById('modalImage');
- modalImage.src = this.src;
- modal.style.display = 'flex';
- };
- // 键盘ESC键关闭
- document.addEventListener('keydown', function(event) {
- if (event.key === 'Escape') {
- const modal = document.getElementById('imageModal');
- if (modal && modal.style.display === 'flex') {
- modal.style.display = 'none';
- }
- }
- });
- } else {
- // 显示错误信息
- imageResultDiv.innerHTML = `
- <div class="image-error">
- <i class="fas fa-exclamation-triangle"></i>
- <p>图片生成失败:${response.msg || '未知错误'}</p>
- </div>
- `;
- }
- },
- error: function(xhr, status, error) {
- // 处理网络错误
- imageResultDiv.innerHTML = `
- <div class="image-error">
- <i class="fas fa-exclamation-triangle"></i>
- <p>图像生成失败</p>
- </div>
- `;
- }
- });
- }
- // 一键优化提示词功能
- function optimizePrompt() {
- const textarea = document.querySelector('.prompt-textarea');
- const optimizeBtn = document.querySelector('.optimize-btn');
- if (textarea && textarea.value.trim() !== '') {
- // 显示加载状态
- const originalBtnText = optimizeBtn.innerHTML;
- optimizeBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 优化中...';
- optimizeBtn.disabled = true;
- // 构造请求参数
- const params = {
- status_val: '文生文',
- prompt: textarea.value,
- model: 'gemini-2.0-flash'
- };
- // 发送AJAX请求
- $.ajax({
- url: '/index.php/api/work_order/GetTxtToTxt',
- type: 'POST',
- data: params,
- dataType: 'json',
- success: function(data) {
- console.log(data);
- // 恢复按钮状态
- optimizeBtn.innerHTML = originalBtnText;
- optimizeBtn.disabled = false;
- // 优化成功,更新文本框内容
- textarea.value = data.content;
- textarea.scrollTop = textarea.scrollHeight;
- updateCharCount();
- // 显示优化成功提示
- const alert = document.createElement('div');
- alert.className = 'alert alert-success';
- alert.innerHTML = '提示词已优化!';
- alert.style.position = 'fixed';
- alert.style.top = '20px';
- alert.style.right = '20px';
- alert.style.zIndex = '9999';
- document.body.appendChild(alert);
- // 3秒后移除提示
- setTimeout(() => {
- alert.remove();
- }, 3000);
- }
- });
- } else {
- showAlert('请先输入提示词!', 'warning');
- }
- }
- // 清空提示词功能
- function clearPrompt() {
- const textarea = document.querySelector('.prompt-textarea');
- if (textarea) {
- textarea.value = '';
- textarea.focus();
- }
- }
- // 保存模板函数
- function saveTemplate() {
- // 获取所有需要的参数
- const templateName = document.getElementById('templateName').value;
- const prompt = document.getElementById('prompt').value.trim();
- const style = document.getElementById('style').value;
- const imageSize = document.getElementById('imageSize').value;
- const previewImage = document.getElementById('previewImage');
- // 验证必填项
- if (!templateName.trim()) {
- showAlert('请输入模板名称', 'error');
- return;
- }
- if (!prompt) {
- showAlert('请输入提示词', 'error');
- return;
- }
- if (!previewImage || !previewImage.src) {
- showAlert('请先生成图片', 'error');
- return;
- }
- // 准备请求参数
- // 将完整URL转换为相对路径
- let imageUrl = previewImage.src;
- try {
- const url = new URL(imageUrl);
- imageUrl = url.pathname;
- } catch (e) {
- // 如果已经是相对路径,直接使用
- }
- const params = {
- chinese_description: prompt,
- template_image_url: imageUrl,
- template_name: templateName,
- style: style,
- size: imageSize,
- type: '文生图' // 固定为文生图类型
- };
- // 显示加载状态
- const saveBtn = document.getElementById('saveBtn');
- const originalText = saveBtn.innerHTML;
- saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 保存中...';
- saveBtn.disabled = true;
- // 发送AJAX请求
- $.ajax({
- url: '/index.php/api/work_order/Add_Product_Template',
- type: 'POST',
- dataType: 'json',
- data: params,
- success: function(response) {
- if (response.code === 0) {
- showAlert('模板保存成功!', 'success');
- // 清空模板名称输入框
- document.getElementById('templateName').value = '';
- } else {
- showAlert('模板保存失败:' + (response.msg || '未知错误'), 'error');
- }
- },
- error: function(xhr, status, error) {
- console.error('AJAX请求失败:', error);
- showAlert('网络错误,模板保存失败', 'error');
- },
- complete: function() {
- // 恢复按钮状态
- saveBtn.innerHTML = originalText;
- saveBtn.disabled = false;
- }
- });
- }
- // 下载图像函数
- function downloadImage() {
- const previewImage = document.getElementById('previewImage');
- if (previewImage && previewImage.src) {
- // 创建临时链接下载图片
- const link = document.createElement('a');
- link.href = previewImage.src;
- // 生成更有意义的文件名
- const timestamp = new Date().getTime();
- const promptText = document.querySelector('.prompt-textarea').value.trim();
- // 从提示词中提取前20个字符作为文件名的一部分
- const promptPart = promptText.substring(0, 20).replace(/[^\w\u4e00-\u9fa5]/g, '') || 'image';
- // 组合文件名:提示词部分_时间戳.jpg
- const fileName = `${promptPart}_${timestamp}.jpg`;
- link.download = fileName;
- link.click();
- }
- }
- </script>
- </body>
- </html>
|