// ==UserScript==
// @name 画图ai提示词管理器-川味面最好吃
// @namespace https://space.bilibili.com/37440705?spm_id_from=333.788.0.0
// @version 4.3
// @description 网页提示词管理器:支持保存、分类、快速使用提示词。请修改@match那行的网址,如果需要多个网站可以多些几行,现在的设置是每个网站都会显示
// @author B站:川味面最好吃
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
// 添加样式
// 添加 Toast 样式
GM_addStyle(`
.toast-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 10000;
}
.toast {
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 20px;
border-radius: 4px;
margin-top: 10px;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* 通用颜色变量 - 亮色模式 */
:root {
--pm-text-color: #ddd;
--pm-bg-color: #333;
--pm-border-color: #555;
--pm-hover-color: #444;
--pm-primary-color: #3a80d2;
--pm-primary-hover: #2a70c2;
--pm-danger-color: #c73c2e;
--pm-secondary-color: #777;
--pm-border-light: #444;
}
/* 深色模式 */
.prompt-manager-dark-mode {
--pm-text-color: #ddd;
--pm-bg-color: #333;
--pm-border-color: #555;
--pm-hover-color: #444;
--pm-primary-color: #3a80d2;
--pm-primary-hover: #2a70c2;
--pm-danger-color: #c73c2e;
--pm-secondary-color: #777;
--pm-border-light: #444;
}
.prompt-manager-menu {
position: fixed;
background: var(--pm-bg-color);
border: 1px solid var(--pm-border-color);
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 8px;
z-index: 9999;
min-width: 150px;
max-height: 400px;
color: var(--pm-text-color);
}
.prompt-manager-toolbar {
display: flex;
justify-content: space-between;
padding-bottom: 8px;
margin-bottom: 8px;
}
.prompt-manager-toolbar button {
background: none;
border: none;
cursor: pointer;
font-size: 14px;
padding: 4px;
color: var(--pm-text-color);
}
.prompt-manager-category {
padding: 4px 8px;
cursor: pointer;
margin: 2px 0;
color: var(--pm-text-color);
}
.prompt-manager-category:hover {
background: var(--pm-hover-color);
border-radius: 4px;
}
#div1{
position: absolute;
height: 100%;
width:0;
top: 0;
left: 0;
}
.prompt-manager-modal {
transform: translateX(-100%);
background: var(--pm-bg-color);
padding: 10px;
border-radius: 8px 0 0 8px;
height: 100%;
z-index: 10000;
min-width: 300px;
max-width: 520px;
color: var(--pm-text-color);
border: 1px solid #666;
border-right: 0;
display: flex
;
flex-direction: column;
justify-content: space-between;
}
.prompt-manager-modal2{
position: fixed;
top: 50%;
left: 20px;
transform: translateY(-50%);
background: var(--pm-bg-color);
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
z-index: 10000;
min-width: 300px;
max-width: 520px;
color: var(--pm-text-color);
}
.settings-section {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--pm-border-light);
}
.settings-section:last-child {
border-bottom: none;
margin-bottom: 15px;
}
.settings-section h4 {
margin: 0 0 10px 0;
color: var(--pm-text-color);
}
/* 触摸设备优化 */
@media (hover: none) {
.prompt-manager-button,
.toolbar-btn,
.prompt-favorite,
.prompt-edit,
.prompt-delete {
min-height: 44px;
min-width: 44px;
}
.prompt-manager-list-item {
padding: 12px 8px;
}
.prompt-actions {
opacity: 1;
}
.prompt-manager-category {
padding: 12px 8px;
}
}
.prompt-manager-input {
width: 100%;
padding: 8px;
margin: 8px 0;
border: 1px solid #ddd;
border-radius: 4px;
color: var(--pm-text-color);
}
.prompt-manager-button {
padding: 8px 16px;
margin: 4px;
border: none;
border-radius: 4px;
background: var(--pm-primary-color);
color: white;
cursor: pointer;
}
.prompt-manager-button:hover {
background: var(--pm-primary-hover);
}
.prompt-manager-button.danger {
background: var(--pm-danger-color);
}
.prompt-manager-button.secondary {
background: #999;
}
.prompt-manager-list {
max-height: 300px;
overflow-y: auto;
margin: 10px 0;
display: flex;
flex-wrap: wrap;
}
.prompt-manager-list-item {
background-color:#222;
margin:2px;
border-radius: 5px;
cursor: pointer;
color: var(--pm-text-color);
max-width:120px;
padding:1px 7px;
}
.prompt-manager-list-item:hover {
background: var(--pm-hover-color);
}
`);
// 数据结构
let data = {
categories: [], // [{id: string, name: string, order: number}]
prompts: [], // [{id: string, text: string, alias: string, categoryId: string, favorite: boolean, useCount: number, isTemplate: boolean, lastUsed: string}]
lastUsedCategoryId: null, // 记录上次使用的分组ID
backups: [], // 自动备份历史 [{date: string, data: Object}]
settings: {
darkMode: false, // 深色模式
modalPosition: null, // 模态框位置
sortBy: 'time', // 排序方式:time(添加时间), name(名称), usage(使用次数)
showFavoriteOnly: false, // 是否只显示收藏的提示词
enableContextMenu: true, // 启用右键菜单
autoBackup: true, // 自动备份
backupInterval: 7, // 备份间隔(天)
maxBackups: 5, // 最大备份数量
categorySort: 'custom' // 分类排序方式:custom(自定义), name(名称)
}
};
// 初始化数据
function initData() {
const savedData = GM_getValue('promptManagerData');
if (savedData) {
try {
data = JSON.parse(savedData);
// 兼容旧版本数据结构
if (!data.settings) {
data.settings = {
darkMode: false,
modalPosition: null,
sortBy: 'time',
showFavoriteOnly: false,
enableContextMenu: true,
autoBackup: true,
backupInterval: 7
};
}
if (!data.backups) {
data.backups = [];
}
// 检查是否需要创建备份
checkBackup();
} catch (e) {
console.error('数据解析错误', e);
// 尝试恢复最近的备份
tryRestore();
}
}
}
// 保存数据
function saveData() {
try {
GM_setValue('promptManagerData', JSON.stringify(data));
} catch (e) {
console.error('保存数据失败', e);
alert('保存数据失败,请检查浏览器存储空间或导出备份数据');
}
}
// 检查是否需要创建备份
function checkBackup() {
if (!data.settings.autoBackup) return;
const now = new Date();
const lastBackup = data.backups[0]?.date ? new Date(data.backups[0].date) : null;
// 如果没有备份或最后一次备份超过指定天数
if (!lastBackup || (now - lastBackup) / (1000 * 60 * 60 * 24) > data.settings.backupInterval) {
// 创建备份,不包含之前的备份数据
const backupData = JSON.parse(JSON.stringify(data));
delete backupData.backups;
// 添加新备份到开头
data.backups.unshift({
date: now.toISOString(),
data: backupData
});
// 保留最多5个备份
if (data.backups.length > 5) {
data.backups = data.backups.slice(0, 5);
}
saveData();
}
}
// 尝试从备份恢复
function tryRestore() {
const savedBackups = GM_getValue('promptManagerBackups');
if (savedBackups) {
try {
const backups = JSON.parse(savedBackups);
if (backups.length > 0) {
// 使用最新的备份
data = backups[0].data;
alert('检测到数据损坏,已自动从最近备份恢复');
return;
}
} catch (e) {
console.error('备份解析错误', e);
}
}
// 如果没有可用备份,重置数据
data = {
categories: [],
prompts: [],
lastUsedCategoryId: null,
backups: [],
settings: {
darkMode: false,
modalPosition: null,
sortBy: 'time',
showFavoriteOnly: false,
enableContextMenu: true,
autoBackup: true,
backupInterval: 7
}
};
alert('无法恢复数据,已重置为默认设置');
}
// 初始化数据
// = GM_getValue('promptManagerData');
// 显示提示信息
function showToast(message, duration = 3000) {
let container = document.querySelector('.toast-container');
if (!container) {
container = document.createElement('div');
container.className = 'toast-container';
document.body.appendChild(container);
}
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = message;
container.appendChild(toast);
setTimeout(() => {
toast.remove();
if (container.children.length === 0) {
container.remove();
}
}, duration);
}
// 创建浮动菜单
function createFloatingMenu(x, y) {
const menu = document.createElement('div');
menu.className = 'prompt-manager-menu';
menu.style.left = x + 'px';
menu.style.top = y + 'px';
const div1=document.createElement('div');
div1.id='div1';
menu.appendChild(div1);
const div2=document.createElement('div');
menu.appendChild(div2);
// 工具栏
const toolbar = document.createElement('div');
toolbar.className = 'prompt-manager-toolbar';
makeDraggable(menu);
const settingsBtn = document.createElement('button');
settingsBtn.innerHTML = '⚙️';
settingsBtn.onclick = showSettings;
const addCategoryBtn = document.createElement('button');
addCategoryBtn.innerHTML = '+🗂️';
addCategoryBtn.onclick = () => showAddCategoryDialog();
toolbar.appendChild(settingsBtn);
toolbar.appendChild(addCategoryBtn);
div2.appendChild(toolbar);
// 分类列表
data.categories.forEach(category => {
const categoryDiv = document.createElement('div');
categoryDiv.className = 'prompt-manager-category';
categoryDiv.textContent = category.name;
categoryDiv.onclick = () => showPromptList(category.id);
div2.appendChild(categoryDiv);
});
document.body.appendChild(menu);
return menu;
}
// 显示添加分类对话框
function showAddCategoryDialog() {
const modal = createModal();
modal.innerHTML = `
新建分类
`;
modal.style.left = '40%';
const input = modal.querySelector('input');
const [confirmBtn, cancelBtn] = modal.querySelectorAll('button');
confirmBtn.onclick = () => {
if (input.value.trim()) {
const newCategory = {
id: Date.now().toString(),
name: input.value.trim()
};
data.categories.push(newCategory);
saveData();
closeModal();
// 刷新菜单
const oldMenu = document.querySelector('.prompt-manager-menu');
if (oldMenu) {
const rect = oldMenu.getBoundingClientRect();
oldMenu.remove();
createFloatingMenu(rect.left, rect.top);
}
}
};
cancelBtn.onclick = closeModal;
}
// 显示提示词列表
function showPromptList(categoryId) {
try{
document.getElementsByClassName('prompt-manager-modal')[0].remove();
}catch(e){}
console.log(document.getElementById('div1').innerHTML)
const prompts = data.prompts.filter(p => p.categoryId === categoryId);
const category = data.categories.find(c => c.id === categoryId);
const modal = createModal();
modal.innerHTML = `
${category.name}
${prompts.map(prompt => `
${prompt.alias || prompt.text}
`).join('')}
`;
// 添加CSS样式
const style = document.createElement('style');
style.textContent = `
.prompt-manager-list-item {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-between;
align-items: center;
position: relative;
padding-left: 5px;
}
.prompt-text {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
}
.prompt-favorite {
background: none;
border: none;
cursor: pointer;
font-size: 16px;
color: gold;
}
.prompt-checkbox {
position: absolute;
left: 5px;
width: 16px;
height: 16px;
cursor: pointer;
opacity: 0;
}
.prompt-checkbox-custom {
position: absolute;
left: 5px;
width: 16px;
height: 16px;
border: 2px solid var(--pm-text-color);
border-radius: 3px;
pointer-events: none;
}
.prompt-checkbox:checked + .prompt-checkbox-custom::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--pm-primary-color);
}
.prompt-manager-list-item.selected {
background-color: rgba(74, 144, 226, 0.1);
}
.batch-actions {
display: none;
margin-bottom: 10px;
gap: 8px;
flex-wrap: wrap;
}
.batch-actions.visible {
display: flex;
}
/* 操作提示和反馈 */
.toast-container {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 10001;
pointer-events: none;
}
.toast {
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 20px;
border-radius: 4px;
margin-top: 10px;
animation: fadeInOut 3s ease-in-out;
}
@keyframes fadeInOut {
0% { opacity: 0; transform: translateY(20px); }
10% { opacity: 1; transform: translateY(0); }
90% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-20px); }
}
/* 触摸设备优化 */
@media (hover: none) {
.prompt-checkbox, .prompt-checkbox-custom {
width: 22px;
height: 22px;
}
.prompt-manager-list-item {
padding-left: 35px;
}
.batch-actions button {
padding: 12px 20px;
}
}
.prompt-actions {
opacity: 0.3;
transition: opacity 0.2s;
}
.prompt-manager-list-item:hover .prompt-actions {
opacity: 1;
}
.prompt-delete, .prompt-edit {
background: none;
border: none;
cursor: pointer;
font-size: 10px;
}
.prompt-manager-list-item.active {
background-color: rgba(74, 144, 226, 0.1);
}
.empty-list-message {
padding: 20px;
text-align: center;
color: #999;
}
.prompt-toolbar {
display: flex;
gap: 8px;
}
.toolbar-btn {
background: none;
border: none;
cursor: pointer;
padding: 4px 8px;
font-size: 16px;
color: var(--pm-text-color);
border-radius: 4px;
}
.toolbar-btn:hover {
background: var(--pm-hover-color);
}
.search-bar {
position: relative;
}
@media (max-width: 768px) {
.prompt-manager-modal {
left: 0 !important;
right: 0 !important;
width: auto !important;
margin: 10px;
max-width: none !important;
}
.prompt-manager-menu {
left: 0 !important;
right: 0 !important;
width: auto !important;
margin: 10px;
}
.prompt-toolbar {
gap: 4px;
}
.toolbar-btn {
padding: 8px;
}
}
`;
document.head.appendChild(style);
// 搜索和过滤功能
const sortBtn = modal.querySelector('#sort-btn');
const favoriteFilterBtn = modal.querySelector('#favorite-filter-btn');
// 排序函数
const sortPrompts = (items) => {
return Array.from(items).sort((a, b) => {
const aPrompt = data.prompts.find(p => p.id === a.dataset.id);
const bPrompt = data.prompts.find(p => p.id === b.dataset.id);
if (!aPrompt || !bPrompt) return 0;
switch (data.settings.sortBy) {
case 'name':
return (aPrompt.alias || aPrompt.text).localeCompare(bPrompt.alias || bPrompt.text);
case 'usage':
return (bPrompt.useCount || 0) - (aPrompt.useCount || 0);
default: // 'time'
return bPrompt.id.localeCompare(aPrompt.id);
}
});
};
// 搜索和过滤函数
// 排序按钮点击事件
sortBtn.addEventListener('click', () => {
switch (data.settings.sortBy) {
case 'time':
data.settings.sortBy = 'name';
sortBtn.textContent = '🔤';
break;
case 'name':
data.settings.sortBy = 'usage';
sortBtn.textContent = '📊';
break;
default:
data.settings.sortBy = 'time';
sortBtn.textContent = '⏱️';
}
saveData();
});
// 收藏过滤按钮点击事件
favoriteFilterBtn.addEventListener('click', () => {
data.settings.showFavoriteOnly = !data.settings.showFavoriteOnly;
favoriteFilterBtn.textContent = data.settings.showFavoriteOnly ? '★' : '☆';
favoriteFilterBtn.title = data.settings.showFavoriteOnly ? '显示全部' : '只看收藏';
saveData();
});
// 提示词点击事件
const items = modal.querySelectorAll('.prompt-manager-list-item');
items.forEach(item => {
// 收藏按钮点击事件
const favoriteBtn = item.querySelector('.prompt-favorite');
favoriteBtn.onclick = (e) => {
e.stopPropagation();
const promptId = item.dataset.id;
const promptIndex = data.prompts.findIndex(p => p.id === promptId);
if (promptIndex !== -1) {
// 切换收藏状态
data.prompts[promptIndex].favorite = !data.prompts[promptIndex].favorite;
favoriteBtn.textContent = data.prompts[promptIndex].favorite ? '★' : '☆';
favoriteBtn.title = data.prompts[promptIndex].favorite ? '取消收藏' : '收藏';
saveData();
}
};
// 提示词文本点击事件
const textSpan = item.querySelector('.prompt-text');
textSpan.onclick = (e) => {
e.stopPropagation(); // 阻止事件冒泡
const promptId = item.dataset.id;
const prompt = data.prompts.find(p => p.id === promptId);
if (!prompt) {
alert('提示词数据已损坏,请尝试刷新页面');
return;
}
let text = prompt.text;
// 如果是模板,处理变量替换
if (prompt.isTemplate) {
// 提取所有变量
const variables = [];
const regex = /\{\{([^}]+)\}\}/g;
let match;
while ((match = regex.exec(text)) !== null) {
if (!variables.includes(match[1])) {
variables.push(match[1]);
}
}
// 如果有变量,提示用户输入
if (variables.length > 0) {
// 收集变量值
const values = {};
for (const variable of variables) {
const value = prompt(`请输入"${variable}"的值:`);
if (value === null) {
// 用户取消了输入
return;
}
values[variable] = value;
}
// 替换所有变量
for (const [variable, value] of Object.entries(values)) {
const regex = new RegExp(`\\{\\{${variable}\\}\\}`, 'g');
text = text.replace(regex, value);
}
}
}
// 检查文本结尾是否是逗号,如果不是则添加逗号
if (!text.endsWith(',')) {
text += ',';
}
// 记录最近聚焦的输入元素
let targetInput = window.lastFocusedInput;
// 如果没有记录或记录的元素不再有效,则尝试查找页面上可见的输入框
if (!targetInput || !document.body.contains(targetInput)) {
// 查找页面上所有的输入框和文本框
const inputs = document.querySelectorAll('input[type="text"], textarea');
targetInput = Array.from(inputs).find(input => {
// 检查元素是否可见且可编辑
const style = window.getComputedStyle(input);
const rect = input.getBoundingClientRect();
return style.display !== 'none' &&
!input.readOnly &&
!input.disabled &&
rect.width > 0 &&
rect.height > 0;
});
}
if (targetInput) {
// 将文本插入到输入框
targetInput.focus();
const start = targetInput.selectionStart || 0;
const end = targetInput.selectionEnd || 0;
targetInput.value = targetInput.value.substring(0, start) + text + targetInput.value.substring(end);
targetInput.setSelectionRange(start + text.length, start + text.length);
// 触发输入事件,确保动态网页能检测到内容变化
const inputEvent = new Event('input', { bubbles: true });
targetInput.dispatchEvent(inputEvent);
// 更新使用次数
const promptId = item.dataset.id;
const promptIndex = data.prompts.findIndex(p => p.id === promptId);
if (promptIndex !== -1) {
data.prompts[promptIndex].useCount = (data.prompts[promptIndex].useCount || 0) + 1;
saveData();
}
}
//closeModal();
};
// 删除按钮点击事件
const deleteBtn = item.querySelector('.prompt-delete');
deleteBtn.onclick = (e) => {
e.stopPropagation();
const promptId = item.dataset.id;
if (confirm('确定要删除这个提示词吗?')) {
try {
data.prompts = data.prompts.filter(p => p.id !== promptId);
saveData();
item.remove();
// 检查列表是否为空
const listItems = modal.querySelectorAll('.prompt-manager-list-item:not([style*="display: none"])');
const listContainer = modal.querySelector('.prompt-manager-list');
if (listItems.length === 0) {
const message = data.settings.showFavoriteOnly ? '没有收藏的提示词' : '没有提示词';
listContainer.innerHTML = `${message}
`;
}
showToast('提示词已删除');
} catch (error) {
console.error('删除提示词失败', error);
showToast('删除失败,请重试');
}
}
};
});
// 工具栏按钮
const shareCategoryBtn = modal.querySelector('#share-category');
const [editCategoryBtn,edititem, closeBtn] = modal.querySelectorAll('.prompt-manager-toolbar button');
// 分享分类按钮点击事件
shareCategoryBtn.onclick = () => {
const category = data.categories.find(c => c.id === categoryId);
if (!category) return;
const prompts = data.prompts.filter(p => p.categoryId === categoryId);
if (prompts.length === 0) {
showToast('当前分类没有提示词可分享');
return;
}
const shareModal = createModal();
shareModal.innerHTML = `
分享分类:${category.name}
`;
const formatSelect = shareModal.querySelector('#share-format');
const previewArea = shareModal.querySelector('textarea');
const copyBtn = shareModal.querySelector('#copy-share');
const downloadBtn = shareModal.querySelector('#download-share');
const closeShareBtn = shareModal.querySelector('.prompt-manager-button.secondary');
// 生成分享内容
const generateContent = (format) => {
switch (format) {
case 'text':
return prompts.map(p => {
const text = p.text.replace(/\n/g, ' ');
return p.alias ? `${text}|${p.alias}` : text;
}).join('\n');
case 'markdown':
return `# ${category.name}\n\n` + prompts.map(p => {
const text = p.text.replace(/\n/g, ' ');
return `- ${p.alias ? `**${p.alias}**: ` : ''}${text}`;
}).join('\n');
case 'json':
return JSON.stringify({
category: category.name,
prompts: prompts.map(p => ({
text: p.text,
alias: p.alias || null
}))
}, null, 2);
}
};
// 更新预览
const updatePreview = () => {
previewArea.value = generateContent(formatSelect.value);
};
formatSelect.onchange = updatePreview;
updatePreview();
// 复制内容
copyBtn.onclick = async () => {
try {
await navigator.clipboard.writeText(previewArea.value);
showToast('内容已复制到剪贴板');
} catch (error) {
console.error('复制失败', error);
// 降级方案
previewArea.select();
document.execCommand('copy');
showToast('内容已复制到剪贴板');
}
};
// 下载文件
downloadBtn.onclick = () => {
const format = formatSelect.value;
const content = generateContent(format);
const blob = new Blob([content], {
type: format === 'json' ? 'application/json' : 'text/plain'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `prompts-${category.name}.${format === 'markdown' ? 'md' : format}`;
a.click();
URL.revokeObjectURL(url);
showToast('文件已开始下载');
};
closeShareBtn.onclick = () => closeModal(shareModal);
};
edititem.onclick=()=>{
showx()
}
showx()
function showx(){
const categories = document.querySelectorAll('.prompt-actions .prompt-delete')
for(let i=0;i {
showEditCategoryDialog(categoryId);
};
closeBtn.onclick = closeModal;
}
// 显示设置界面
function showSettings() {
const modal = createModal();
modal.innerHTML = `
设置
导入导出
每行一个提示词,如果有简称以"|"分隔。每次请只添加一个分组的,因为添加后所有的都会被分到同一个分组
1、点击"+🗂️"
2、在页面中划词可以添加提示词
3、点击提示词可以填入到编辑框里
`;
//modal.style.transform = 'none';
//modal.style.top = '20px';
const darkModeToggle = modal.querySelector('#dark-mode-toggle');
const exportJsonBtn = modal.querySelector('#export-json');
const exportTxtBtn = modal.querySelector('#export-txt');
const [, importBtn, batchImportBtn, helpBtn, clearBtn, closeBtn] = modal.querySelectorAll('.prompt-manager-button');
const fileInput = modal.querySelector('#import-file');
const batchFileInput = modal.querySelector('#batch-import-file');
// 深色模式切换
/*darkModeToggle.onchange = () => {
data.settings.darkMode = darkModeToggle.checked;
saveData();
applyDarkMode();
};*/
// 导出仅包含prompts数组的JSON数据
exportJsonBtn.onclick = () => {
const exportData = { categories: data.categories, prompts: data.prompts };
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
//const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'prompt-manager-data.json';
a.click();
URL.revokeObjectURL(url);
};
importBtn.onclick = () => fileInput.click();
// 批量导入按钮
batchImportBtn.onclick = () => showBatchImportDialog()//batchFileInput.click();
// 批量导入文件处理
batchFileInput.onchange = async () => {
const file = batchFileInput.files[0];
if (file) {
try {
const text = await file.text();
showBatchImportDialog(text);
} catch (e) {
alert('文件读取失败');
}
}
};
fileInput.onchange = async () => {
const file = fileInput.files[0];
if (file) {
try {
const text = await file.text();
const importedData = JSON.parse(text);
if (importedData.categories && importedData.prompts) {
// 保留lastUsedCategoryId或使用导入数据中的值
const currentLastUsedCategory = data.lastUsedCategoryId;
data = importedData;
// 如果导入的数据没有lastUsedCategoryId,保留当前的值
if (!data.lastUsedCategoryId && currentLastUsedCategory) {
data.lastUsedCategoryId = currentLastUsedCategory;
}
saveData();
alert('数据导入成功!');
closeModal();
}
} catch (e) {
alert('导入失败:无效的数据格式');
}
}
};
clearBtn.onclick = () => {
if (confirm('确定要清空所有数据吗?此操作不可恢复!')) {
data = {
categories: [],
prompts: [],
lastUsedCategoryId: null
};
saveData();
closeModal();
}
};
closeBtn.onclick = closeModal;
}
// 显示保存提示词对话框
function showSavePromptDialog(text) {
const modal = createModal2();
modal.innerHTML = `
保存提示词
`;
// 防止点击事件冒泡
modal.addEventListener('click', (e) => {
e.stopPropagation();
});
// 添加拖拽功能
makeDraggable(modal);
const aliasInput = modal.querySelector('input');
const categorySelect = modal.querySelector('select');
const [saveBtn, cancelBtn] = modal.querySelectorAll('button');
saveBtn.onclick = () => {
const categoryId = categorySelect.value;
if (!categoryId) {
alert('请选择分类!');
return;
}
const textArea = modal.querySelector('textarea');
const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false };
const newPrompt = {
id: Date.now().toString(),
text: textArea.value.trim(),
alias: aliasInput.value.trim(),
categoryId: categoryId,
favorite: false,
useCount: 0,
isTemplate: isTemplateCheckbox.checked
};
// 保存提示词的同时记录最后使用的分组ID
data.lastUsedCategoryId = categoryId;
data.prompts.push(newPrompt);
saveData();
closeModal();
};
// 如果有上次使用的分组,自动选中
if (data.lastUsedCategoryId) {
const option = categorySelect.querySelector(`option[value="${data.lastUsedCategoryId}"]`);
if (option) {
categorySelect.value = data.lastUsedCategoryId;
} else {
// 如果找不到对应的分类(可能已被删除),清除记录
data.lastUsedCategoryId = null;
saveData();
}
}
cancelBtn.onclick = closeModal;
}
// 显示批量导入对话框
function showBatchImportDialog(text) {
const modal = createModal();
modal.innerHTML = `
批量导入提示词
每行一个提示词,格式:提示词文本|别名(可选)。导入后需要刷新
`;
const textArea = modal.querySelector('textarea');
const categorySelect = modal.querySelector('select');
const [importBtn, cancelBtn] = modal.querySelectorAll('button');
// 如果有上次使用的分组,自动选中
if (data.lastUsedCategoryId) {
categorySelect.value = data.lastUsedCategoryId;
}
importBtn.onclick = () => {
const categoryId = categorySelect.value;
if (!categoryId) {
alert('请选择分类!');
return;
}
const lines = textArea.value.split('\n').filter(line => line.trim());
if (lines.length === 0) {
alert('没有找到有效的提示词');
return;
}
let importCount = 0;
lines.forEach(line => {
const parts = line.split('|');
const text = parts[0].trim();
const alias = parts.length > 1 ? parts[1].trim() : '';
if (text) {
const newPrompt = {
id: Date.now().toString() + importCount,
text: text,
alias: alias,
categoryId: categoryId,
favorite: false
};
data.prompts.push(newPrompt);
importCount++;
}
});
if (importCount > 0) {
data.lastUsedCategoryId = categoryId;
saveData();
alert(`成功导入 ${importCount} 个提示词`);
closeModal();
} else {
alert('没有找到有效的提示词');
}
};
cancelBtn.onclick = closeModal;
}
// 应用深色模式
function applyDarkMode() {
if (data.settings?.darkMode) {
document.body.classList.add('prompt-manager-dark-mode');
} else {
document.body.classList.remove('prompt-manager-dark-mode');
}
}
// 创建模态框
function createModal() {
const modal = document.createElement('div');
modal.className = 'prompt-manager-modal';
// 如果有保存的位置,使用保存的位置
/* if (data.settings?.modalPosition) {
modal.style.left = data.settings.modalPosition.left + 'px';
modal.style.top = data.settings.modalPosition.top + 'px';
modal.style.transform = 'none';
}*/
// 添加拖拽功能
makeDraggable(modal);
const menu = document.querySelector('#div1').appendChild(modal);
//document.body.appendChild(modal);
return modal;
}
function createModal2() {
const modal = document.createElement('div');
modal.className = 'prompt-manager-modal2';
// 如果有保存的位置,使用保存的位置
if (data.settings?.modalPosition) {
modal.style.left = data.settings.modalPosition.left + 'px';
modal.style.top = data.settings.modalPosition.top + 'px';
modal.style.transform = 'none';
}
//const menu = document.querySelector('#div1').appendChild(modal);
document.body.appendChild(modal);
return modal;
}
// 使元素可拖拽
function makeDraggable(element) {
let isDragging = false;
let offsetX, offsetY;
// 创建拖拽手柄
const dragHandle = document.createElement('div');
dragHandle.style.cssText = `
position: absolute;
top: 0;
left: 0;
right: 0;
height: 30px;
cursor: move;
background-color: transparent;
`;
element.appendChild(dragHandle);
console.log(dragHandle);
// 鼠标按下事件
dragHandle.addEventListener('mousedown', (e) => {
isDragging = true;
// 获取鼠标在元素内的相对位置
const rect = element.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
// 阻止默认行为和冒泡
e.preventDefault();
e.stopPropagation();
});
// 鼠标移动事件
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
// 计算新位置
const x = e.clientX - offsetX;
const y = e.clientY - offsetY;
// 应用新位置
element.style.left = x + 'px';
element.style.top = y + 'px';
element.style.transform = 'none';
// 保存位置到设置
data.settings.modalPosition = { left: x, top: y };
});
// 鼠标释放事件
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
saveData();
}
});
}
// 关闭模态框
function closeModal() {
const modal = document.querySelector('.prompt-manager-modal');
const modal2 = document.querySelector('.prompt-manager-modal2');
if (modal) modal.remove();
if (modal2) modal2.remove();
}
function closeModal2() {
const modal = document.querySelector('.prompt-manager-modal2');
if (modal) modal.remove();
}
// 点击页面任意位置关闭模态框(使用捕获阶段)
document.addEventListener('click', (e) => {
const modal = document.querySelector('.prompt-manager-modal2');
if (modal && !e.target.closest('.prompt-manager-modal2')) {
closeModal2();
}
}, true);
// 显示编辑提示词对话框
function showEditPromptDialog(promptId, text, alias, categoryId) {
const modal = createModal();
modal.innerHTML = `
编辑提示词
`;
// 防止点击事件冒泡
modal.addEventListener('click', (e) => {
e.stopPropagation();
});
const textArea = modal.querySelector('textarea');
const aliasInput = modal.querySelector('input[type="text"]');
const isTemplateCheckbox = modal.querySelector('#is-template') || { checked: false };
const templateHelp = modal.querySelector('.template-help');
const categorySelect = modal.querySelector('select');
const [saveBtn, cancelBtn] = modal.querySelectorAll('button');
// 模板帮助提示
templateHelp.onclick = () => {
alert('模板支持使用变量占位符,格式为 {{变量名}}。\n\n使用时会提示输入变量值,自动替换占位符。\n\n例如:\n"你好,我是{{名字}},我来自{{地点}}。"\n\n使用时会提示输入"名字"和"地点"的值。');
};
saveBtn.onclick = () => {
const newCategoryId = categorySelect.value;
if (!newCategoryId) {
alert('请选择分类!');
return;
}
const newText = textArea.value;
if (!newText.trim()) {
alert('提示词内容不能为空!');
return;
}
// 更新提示词
const promptIndex = data.prompts.findIndex(p => p.id === promptId);
if (promptIndex !== -1) {
data.prompts[promptIndex] = {
...data.prompts[promptIndex],
text: newText,
alias: aliasInput.value.trim(),
categoryId: newCategoryId
};
saveData();
closeModal();
// 如果分类改变了,需要刷新提示词列表
if (newCategoryId !== categoryId) {
showPromptList(newCategoryId);
} else {
showPromptList(categoryId);
}
}
};
cancelBtn.onclick = closeModal;
}
// 显示编辑分类对话框
function showEditCategoryDialog(categoryId) {
const category = data.categories.find(c => c.id === categoryId);
if (!category) return;
const modal = createModal();
modal.innerHTML = `
编辑分类
`;
const nameInput = modal.querySelector('input');
const [saveBtn, deleteBtn, cancelBtn] = modal.querySelectorAll('button');
saveBtn.onclick = () => {
const newName = nameInput.value.trim();
if (newName) {
category.name = newName;
saveData();
closeModal();
// 刷新分类列表
showPromptList(categoryId);
} else {
alert('分类名称不能为空');
}
};
deleteBtn.onclick = () => {
if (confirm(`确定要删除分类"${category.name}"吗?该分类下的所有提示词也将被删除!`)) {
// 删除该分类下的所有提示词
data.prompts = data.prompts.filter(p => p.categoryId !== categoryId);
// 删除分类
data.categories = data.categories.filter(c => c.id !== categoryId);
// 如果删除的是上次使用的分类,清除记录
if (data.lastUsedCategoryId === categoryId) {
data.lastUsedCategoryId = null;
}
saveData();
closeModal();
// 刷新菜单
const menu = document.querySelector('.prompt-manager-menu');
if (menu) {
const rect = menu.getBoundingClientRect();
menu.remove();
createFloatingMenu(rect.left, rect.top);
}
}
};
cancelBtn.onclick = closeModal;
}
// 添加键盘快捷键支持
function setupKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
// ESC键关闭所有对话框
if (e.key === 'Escape') {
closeModal();
const menu = document.querySelector('.prompt-manager-menu');
if (menu) menu.remove();
}
// Ctrl+Shift+P 打开最近使用的分类
if (e.ctrlKey && e.shiftKey && e.key === 'P') {
e.preventDefault();
if (data.lastUsedCategoryId) {
const menu = document.querySelector('.prompt-manager-menu');
if (menu) menu.remove();
showPromptList(data.lastUsedCategoryId);
}
}
});
}
// 初始化
initData();
// 记录最近聚焦的输入元素
window.lastFocusedInput = null;
document.addEventListener('focusin', (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
window.lastFocusedInput = e.target;
}
});
// 监听文本框点击
document.addEventListener('click', (e) => {
const target = e.target;
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
const menu = document.querySelector('.prompt-manager-menu');
if (menu) menu.remove();
const rect = target.getBoundingClientRect();
createFloatingMenu(rect.left - 170, rect.top);
} else if (!e.target.closest('.prompt-manager-menu') && !e.target.closest('.prompt-manager-modal')) {
const menu = document.querySelector('.prompt-manager-menu');
if (menu) menu.remove();
}
});
// 监听选中文本
document.addEventListener('mouseup', (e) => {
// 检查是否在模态框内,如果是则不处理
if (e.target.closest('.prompt-manager-modal' )|| e.target.closest('.prompt-manager-menu')|| e.target.closest('.prompt-manager-modal2')) {
return;
}
const selection = window.getSelection();
const text = selection.toString().trim();
// 如果有选中的文本,则显示保存对话框
if (text) {
// 延迟显示保存对话框,避免与其他点击事件冲突
setTimeout(() => {
const menu = document.querySelector('.prompt-manager-menu');
if (menu) menu.remove();
showSavePromptDialog(text);
}, 100);
}
});
})();