优化优先级
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref, computed, nextTick, watch } from 'vue';
|
||||
import { usePromptStore, splitTokens, normalizeSymbols, parseDetailedToken, constructToken } from '../stores/promptStore';
|
||||
import { usePromptStore, splitTokens, normalizeSymbols, parseDetailedToken, constructToken, toNumericForm, toBracketForm, formatWeight } from '../stores/promptStore';
|
||||
import type { LangCode, PresetFolder } from '../types';
|
||||
import NotificationToast from './NotificationToast.vue';
|
||||
import TranslationPopup from './TranslationPopup.vue';
|
||||
@@ -37,7 +37,13 @@ let rafId: number | null = null;
|
||||
const DRAG_THRESHOLD = 3; // 像素阈值,避免误触
|
||||
const editingIndex = ref<number | null>(null);
|
||||
const presetName = ref('');
|
||||
const selectedFolderId = ref<string>('');
|
||||
// 跨页面切换保留所选文件夹(刷新后重置为默认)
|
||||
const selectedFolderId = computed({
|
||||
get: () => store.editorSelectedFolderId,
|
||||
set: (v: string) => { store.editorSelectedFolderId = v; },
|
||||
});
|
||||
// 保存预设时是否同时标记为收藏
|
||||
const saveAsFavorite = ref(false);
|
||||
const viewMode = ref<'compact' | 'detail'>('compact');
|
||||
const showPresetDropdown = ref(false);
|
||||
const showTranslationPopup = ref(false);
|
||||
@@ -73,9 +79,13 @@ function handleClickOutside(event: Event) {
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
const defaultFolder = store.presetManagement?.settings?.defaultFolder;
|
||||
if (defaultFolder) {
|
||||
selectedFolderId.value = defaultFolder;
|
||||
// 仅首次进入时初始化为默认文件夹;后续页面切换保留用户上次的选择
|
||||
if (!store.editorFolderInitialized) {
|
||||
const defaultFolder = store.presetManagement?.settings?.defaultFolder;
|
||||
if (defaultFolder) {
|
||||
store.editorSelectedFolderId = defaultFolder;
|
||||
}
|
||||
store.editorFolderInitialized = true;
|
||||
}
|
||||
store.searchQuery = ''; // Reset search query to ensure all tags are shown
|
||||
});
|
||||
@@ -134,7 +144,10 @@ const suggestions = ref<string[]>([]);
|
||||
const editSuggestions = ref<string[]>([]);
|
||||
const editorInputRef = ref<InstanceType<typeof EditorInput> | null>(null);
|
||||
const tokenMappingRef = ref<InstanceType<typeof TokenMappingPanel> | null>(null);
|
||||
const priorityStyle = ref<'{}' | '()' | '[]' | '<>' | 'suffix'>('{}');
|
||||
// 优先级模式开关:false = 括号嵌套,true = 数字权重后缀
|
||||
const numericMode = ref(false);
|
||||
// 括号嵌套时使用的括号样式(默认圆括号)
|
||||
const bracketStyle = ref<'()' | '{}' | '[]' | '<>'>('()');
|
||||
const priorityStep = ref(0.1);
|
||||
function splitTokensLocal(txt: string): string[] {
|
||||
return splitTokens(txt);
|
||||
@@ -166,25 +179,38 @@ function roundToDecimals(v: number, decimals: number): number {
|
||||
const m = Math.pow(10, decimals);
|
||||
return Math.round(v * m) / m;
|
||||
}
|
||||
function adjustWeight(core: string, delta: number): string {
|
||||
const idx = core.lastIndexOf(':');
|
||||
let base = core;
|
||||
let w: number | null = null;
|
||||
if (idx > -1) {
|
||||
const num = parseFloat(core.slice(idx + 1).trim());
|
||||
if (!isNaN(num)) { base = core.slice(0, idx); w = num; }
|
||||
}
|
||||
const stepStr = String(priorityStep.value);
|
||||
const decimals = stepStr.includes('.') ? stepStr.split('.')[1]!.length : 0;
|
||||
const cur = w == null ? 1.0 : w;
|
||||
let nw = cur + delta;
|
||||
function stepDecimals(): number {
|
||||
const s = String(priorityStep.value);
|
||||
return s.includes('.') ? (s.split('.')[1]?.length ?? 0) : 0;
|
||||
}
|
||||
|
||||
nw = roundToDecimals(nw, decimals);
|
||||
// 数字权重模式:确保 () 容器,按步进调整显式权重(默认 1,即无后缀)
|
||||
function adjustNumericWeight(token: string, deltaSteps: number): string {
|
||||
const { core, weight, prefix, suffix } = parseDetailedToken(token);
|
||||
if (prefix || suffix) return token;
|
||||
const base = weight ?? 1;
|
||||
let next = roundToDecimals(base + deltaSteps * priorityStep.value, stepDecimals());
|
||||
if (next < 0) next = 0;
|
||||
if (next === 1) return `(${core})`;
|
||||
return `(${core}:${formatWeight(next)})`;
|
||||
}
|
||||
|
||||
// If weight is 1, return base without suffix
|
||||
if (nw === 1) return base;
|
||||
// 括号嵌套模式:在最外层再套一层选定括号
|
||||
function addBracketLayer(token: string): string {
|
||||
const { core, weight, wrappers, prefix, suffix } = parseDetailedToken(token);
|
||||
const newWrappers = [bracketStyle.value, ...wrappers];
|
||||
return constructToken(core, weight, newWrappers, prefix, suffix);
|
||||
}
|
||||
|
||||
return base + ':' + nw;
|
||||
// 括号嵌套模式:去掉最外层括号;若移除后无 () 承载裸权重则一并清除
|
||||
function removeBracketLayer(token: string): string {
|
||||
const { core, weight, wrappers, prefix, suffix } = parseDetailedToken(token);
|
||||
if (prefix || suffix) return token;
|
||||
if (wrappers.length === 0) return core;
|
||||
const newWrappers = wrappers.slice(1);
|
||||
const hasParen = newWrappers.includes('()');
|
||||
const keepWeight = weight !== undefined && weight !== 1 && hasParen ? weight : undefined;
|
||||
return constructToken(core, keepWeight, newWrappers, prefix, suffix);
|
||||
}
|
||||
const text = ref('');
|
||||
|
||||
@@ -338,25 +364,11 @@ function replaceCnComma() { applyFullPrompt(normalizeSymbols(text.value)); }
|
||||
function formatPrompt() { applyFullPrompt(normalizePromptLocal(text.value)); }
|
||||
|
||||
function unifyPriorityStyle() {
|
||||
const tokens = splitTokens(text.value);
|
||||
const processed = tokens.map(token => {
|
||||
const { core, weight, wrappers } = parseDetailedToken(token);
|
||||
let result = core;
|
||||
let currentWrappers = [...wrappers];
|
||||
|
||||
if (weight !== undefined && weight !== 1) {
|
||||
const lastWrapper = currentWrappers[currentWrappers.length - 1];
|
||||
if (lastWrapper === '()') {
|
||||
currentWrappers.pop();
|
||||
}
|
||||
const wStr = Number.isInteger(weight) ? weight.toString() : weight.toFixed(2).replace(/\.?0+$/, '');
|
||||
result = `(${result}:${wStr})`;
|
||||
}
|
||||
|
||||
return store.wrapToken(result, currentWrappers);
|
||||
});
|
||||
applyFullPrompt(processed.join(', '));
|
||||
showNotification('已统一优先级样式', 'success');
|
||||
const list = splitTokens(text.value).map(token =>
|
||||
numericMode.value ? toNumericForm(token) : toBracketForm(token)
|
||||
);
|
||||
applyFullPrompt(list.join(', '));
|
||||
showNotification(numericMode.value ? '已统一为数字权重' : '已统一为括号样式', 'success');
|
||||
}
|
||||
|
||||
// 新增功能方法
|
||||
@@ -416,34 +428,18 @@ function addWrapperToToken(index: number) {
|
||||
const tokens = splitTokensLocal(text.value);
|
||||
if (index < 0 || index >= tokens.length) return;
|
||||
const token = tokens[index]!;
|
||||
const parsed = store.parseTokenWrappers(token);
|
||||
const core = parsed?.core ?? token;
|
||||
const wrappers = parsed?.wrappers ?? [];
|
||||
if (priorityStyle.value === 'suffix') {
|
||||
const newCore = adjustWeight(core, +priorityStep.value);
|
||||
tokens[index] = store.wrapToken(newCore, wrappers);
|
||||
} else {
|
||||
const newWrappers = [...wrappers, priorityStyle.value];
|
||||
tokens[index] = store.wrapToken(core, newWrappers);
|
||||
}
|
||||
tokens[index] = numericMode.value ? adjustNumericWeight(token, +1) : addBracketLayer(token);
|
||||
applyFullPrompt(tokens.join(', '));
|
||||
showNotification('已添加优先级', 'success');
|
||||
showNotification(numericMode.value ? '已提升权重' : '已添加优先级', 'success');
|
||||
}
|
||||
|
||||
function removeWrapperFromToken(index: number) {
|
||||
const tokens = splitTokensLocal(text.value);
|
||||
if (index < 0 || index >= tokens.length) return;
|
||||
const token = tokens[index]!;
|
||||
const { core, wrappers } = store.parseTokenWrappers(token);
|
||||
if (priorityStyle.value === 'suffix') {
|
||||
const newCore = adjustWeight(core, -priorityStep.value);
|
||||
tokens[index] = store.wrapToken(newCore, wrappers);
|
||||
} else if (wrappers.length > 0) {
|
||||
const newWrappers = wrappers.slice(0, -1);
|
||||
tokens[index] = store.wrapToken(core, newWrappers);
|
||||
}
|
||||
tokens[index] = numericMode.value ? adjustNumericWeight(token, -1) : removeBracketLayer(token);
|
||||
applyFullPrompt(tokens.join(', '));
|
||||
showNotification('已调整优先级', 'success');
|
||||
showNotification(numericMode.value ? '已降低权重' : '已移除优先级', 'success');
|
||||
}
|
||||
|
||||
function getTokenWrapperInfo(token: string) {
|
||||
@@ -784,10 +780,16 @@ function savePreset() {
|
||||
type: 'positive',
|
||||
content: store.promptText,
|
||||
description: '从编辑器快速保存',
|
||||
folderId: folderId
|
||||
folderId: folderId,
|
||||
isFavorite: saveAsFavorite.value
|
||||
});
|
||||
|
||||
showNotification(`预设「${name}」已保存到预设管理`, 'success');
|
||||
showNotification(
|
||||
saveAsFavorite.value
|
||||
? `预设「${name}」已保存并收藏`
|
||||
: `预设「${name}」已保存到预设管理`,
|
||||
'success'
|
||||
);
|
||||
presetName.value = '';
|
||||
}
|
||||
|
||||
@@ -857,13 +859,14 @@ function isRemoveDisabled(token: string): boolean {
|
||||
<div class="pe-root">
|
||||
<EditorToolbar :languages="store.languages as LangCode[]" v-model:selected-lang="selectedLang"
|
||||
v-model:preset-name="presetName" v-model:selected-folder-id="selectedFolderId"
|
||||
v-model:save-as-favorite="saveAsFavorite"
|
||||
v-model:show-preset-dropdown="showPresetDropdown" :folder-tree="folderTree" :flattened-folders="flattenedFolders"
|
||||
@copy="copyLeft" @save-preset="savePreset" @preset-load="handlePresetLoad" @preset-save="handlePresetSave"
|
||||
@preset-delete="handlePresetDelete" @preset-rename="handlePresetRename" />
|
||||
|
||||
<div class="pe-main">
|
||||
<EditorInput ref="editorInputRef" v-model:text="text" v-model:priority-style="priorityStyle"
|
||||
v-model:priority-step="priorityStep" :suggestions="suggestions"
|
||||
<EditorInput ref="editorInputRef" v-model:text="text" v-model:numeric-mode="numericMode"
|
||||
v-model:bracket-style="bracketStyle" v-model:priority-step="priorityStep" :suggestions="suggestions"
|
||||
:get-suggestions="(prefix, limit) => store.getSuggestions(prefix, limit)"
|
||||
@update-suggestions="updateSuggestionsFromText" @copy="copyLeft" @replace-cn-comma="replaceCnComma"
|
||||
@format-prompt="formatPrompt" @unify-priority="unifyPriorityStyle" @toggle-underscore="toggleUnderscoreSpace"
|
||||
@@ -871,7 +874,7 @@ function isRemoveDisabled(token: string): boolean {
|
||||
|
||||
<TokenMappingPanel ref="tokenMappingRef" :tokens="tokens" :selected-lang="selectedLang"
|
||||
v-model:view-mode="viewMode" :dragging-index="draggingIndex" :over-index="overIndex" :insert-side="insertSide"
|
||||
:is-dragging="isDragging" :edit-suggestions="editSuggestions" :priority-style="priorityStyle"
|
||||
:is-dragging="isDragging" :edit-suggestions="editSuggestions" :numeric-mode="numericMode"
|
||||
:display-trans="displayTrans" :is-unmapped="isUnmapped" :get-token-wrapper-info="getTokenWrapperInfo"
|
||||
:has-weight-suffix="hasWeightSuffix" :get-suggestions="(prefix, limit) => store.getSuggestions(prefix, limit)"
|
||||
@pointer-down="onPointerDown" @panel-dragover="handlePanelDragOver" @panel-dragleave="handlePanelDragLeave"
|
||||
|
||||
Reference in New Issue
Block a user