完成大量美化,zustand迁移,动态表格修复

This commit is contained in:
2026-05-02 02:08:53 +08:00
parent f0e7e75ffb
commit 7fc9e10c99
53 changed files with 2954 additions and 1462 deletions

View File

@@ -0,0 +1,130 @@
import { create } from 'zustand';
/**
* CharacterCard UI 状态 Store
* 管理角色卡列表的 UI 交互状态(非持久化)
*/
const useCharacterCardUIStore = create((set) => ({
// ==================== 状态 ====================
// 筛选标签
filterTag: '',
// 是否处于编辑模式
isEditing: false,
// 编辑表单数据
editForm: null,
// 当前页码
currentPage: 1,
// 每页显示数量
pageSize: 12,
// ==================== Actions ====================
/**
* 设置筛选标签
* @param {string} tag - 标签名
*/
setFilterTag: (tag) => {
set({ filterTag: tag, currentPage: 1 }); // 重置页码
},
/**
* 清空筛选
*/
clearFilter: () => {
set({ filterTag: '', currentPage: 1 });
},
/**
* 进入编辑模式
* @param {Object} character - 角色数据
*/
startEditing: (character) => {
set({
isEditing: true,
editForm: {
name: character.name,
description: character.description || '',
personality: character.personality || '',
scenario: character.scenario || '',
first_mes: character.first_mes || '',
mes_example: character.mes_example || '',
categories: character.categories || [],
tags: character.tags || []
}
});
},
/**
* 退出编辑模式
*/
cancelEditing: () => {
set({
isEditing: false,
editForm: null
});
},
/**
* 更新编辑表单字段
* @param {string} field - 字段名
* @param {*} value - 字段值
*/
updateEditForm: (field, value) => {
set((state) => ({
editForm: {
...state.editForm,
[field]: value
}
}));
},
/**
* 设置页码
* @param {number} page - 页码
*/
setCurrentPage: (page) => {
set({ currentPage: page });
},
/**
* 设置每页显示数量
* @param {number} size - 每页数量
*/
setPageSize: (size) => {
set({ pageSize: size, currentPage: 1 }); // 重置页码
},
/**
* 下一页
*/
nextPage: () => {
set((state) => ({ currentPage: state.currentPage + 1 }));
},
/**
* 上一页
*/
prevPage: () => {
set((state) => ({ currentPage: Math.max(1, state.currentPage - 1) }));
},
/**
* 重置所有 UI 状态
*/
reset: () => {
set({
filterTag: '',
isEditing: false,
editForm: null,
currentPage: 1,
pageSize: 12
});
}
}));
export default useCharacterCardUIStore;

View File

@@ -28,6 +28,10 @@ const usePresetStore = create((set, get) => ({
// 参数设置折叠状态
isParametersExpanded: true,
// 分页状态
currentPage: 1,
pageSize: 8,
// 预设组件列表
promptComponents: [
{
@@ -129,17 +133,22 @@ const usePresetStore = create((set, get) => ({
// 记录原始数据用于调试
console.log('从后端获取的预设数据:', presetData);
// 提取参数并更新状态,确保所有参数都有默认值
// 提取参数并更新状态,支持内部结构和SillyTavern结构
const parameters = {
temperature: presetData.temperature !== undefined ? presetData.temperature : 1.0,
frequency_penalty: presetData.frequency_penalty !== undefined ? presetData.frequency_penalty : 0.0,
presence_penalty: presetData.presence_penalty !== undefined ? presetData.presence_penalty : 0.0,
top_p: presetData.top_p !== undefined ? presetData.top_p : 1.0,
top_k: presetData.top_k !== undefined ? presetData.top_k : 0,
frequency_penalty: presetData.frequency_penalty !== undefined ? presetData.frequency_penalty :
(presetData.frequencyPenalty !== undefined ? presetData.frequencyPenalty : 0.0),
presence_penalty: presetData.presence_penalty !== undefined ? presetData.presence_penalty :
(presetData.presencePenalty !== undefined ? presetData.presencePenalty : 0.0),
top_p: presetData.top_p !== undefined ? presetData.top_p :
(presetData.topP !== undefined ? presetData.topP : 1.0),
top_k: presetData.top_k !== undefined ? presetData.top_k :
(presetData.topK !== undefined ? presetData.topK : 0),
max_context: presetData.openai_max_context !== undefined ? presetData.openai_max_context :
(presetData.max_context !== undefined ? presetData.max_context : 1000000),
max_tokens: presetData.openai_max_tokens !== undefined ? presetData.openai_max_tokens :
(presetData.max_tokens !== undefined ? presetData.max_tokens : 30000),
(presetData.max_tokens !== undefined ? presetData.max_tokens :
(presetData.maxLength !== undefined ? presetData.maxLength : 30000)),
max_context_unlocked: presetData.max_context_unlocked !== undefined ? presetData.max_context_unlocked : false,
stream_openai: presetData.stream_openai !== undefined ? presetData.stream_openai : true,
seed: presetData.seed !== undefined ? presetData.seed : -1,
@@ -149,9 +158,30 @@ const usePresetStore = create((set, get) => ({
// 记录映射后的参数用于调试
console.log('映射后的参数:', parameters);
// 处理预设组件
// 处理预设组件 - 支持内部结构和SillyTavern结构
let components = [];
if (presetData.prompts && Array.isArray(presetData.prompts)) {
// 优先使用内部结构的 entries
if (presetData.entries && Array.isArray(presetData.entries)) {
components = presetData.entries.map(entry => ({
identifier: entry.identifier,
name: entry.name,
content: entry.content || '',
enabled: entry.enabled !== false,
role: entry.role === 'system' ? 0 : entry.role === 'user' ? 1 : 2,
system_prompt: entry.role === 'system',
marker: entry.isSystemNode || false
}));
// 按 order 排序
components.sort((a, b) => {
const orderA = presetData.entries.find(e => e.identifier === a.identifier)?.order || 0;
const orderB = presetData.entries.find(e => e.identifier === b.identifier)?.order || 0;
return orderA - orderB;
});
}
// 兼容SillyTavern结构的 prompts
else if (presetData.prompts && Array.isArray(presetData.prompts)) {
// 获取当前角色的prompt_order添加更严格的检查
const currentOrder = (presetData.prompt_order &&
Array.isArray(presetData.prompt_order) &&
@@ -182,7 +212,6 @@ const usePresetStore = create((set, get) => ({
}
}
// 更新状态,确保参数容器展开
set({
selectedPreset: presetId,
@@ -209,23 +238,31 @@ const usePresetStore = create((set, get) => ({
saveCurrentAsPreset: async ({ name }) => {
const state = get();
try {
// 构建预设数据
// 构建预设数据 - 使用内部专有结构
const presetData = {
...state.parameters,
prompts: state.promptComponents.map(component => ({
// GenerationPreset 部分 - 采样参数
id: `preset_${Date.now()}`,
name: name,
temperature: state.parameters.temperature,
topP: state.parameters.top_p,
topK: state.parameters.top_k,
frequencyPenalty: state.parameters.frequency_penalty,
presencePenalty: state.parameters.presence_penalty,
maxLength: state.parameters.max_tokens,
isDefault: false,
// PromptPresetView 部分 - prompt组件列表
characterId: 'global', // 全局预设,不绑定特定角色
entries: state.promptComponents.map((component, index) => ({
identifier: component.identifier,
name: component.name,
enabled: component.enabled !== false,
content: component.content || '',
role: component.role,
system_prompt: component.system_prompt,
marker: component.marker
})),
prompt_order: [{
order: state.promptComponents.map(component => ({
identifier: component.identifier,
enabled: component.enabled !== false
}))
}]
order: index,
role: component.role === 0 ? 'system' : component.role === 1 ? 'user' : 'ai',
tokenCount: component.content ? component.content.length : 0,
isSystemNode: component.marker || false
}))
};
// 发送到后端
@@ -234,10 +271,7 @@ const usePresetStore = create((set, get) => ({
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
preset_name: name,
...presetData
})
body: JSON.stringify(presetData)
});
if (!response.ok) {
@@ -248,7 +282,7 @@ const usePresetStore = create((set, get) => ({
// 添加到本地预设列表
const newPreset = {
id: name,
id: presetData.id,
name,
description: '',
component_count: state.promptComponents.length,
@@ -257,7 +291,7 @@ const usePresetStore = create((set, get) => ({
set((state) => ({
presets: [...state.presets, newPreset],
selectedPreset: name
selectedPreset: presetData.id
}));
return result;
@@ -350,6 +384,26 @@ const usePresetStore = create((set, get) => ({
identifier: component.identifier,
enabled: component.enabled !== false
}));
},
// 设置当前页
setCurrentPage: (page) => set({ currentPage: page }),
// 设置每页数量
setPageSize: (size) => set({ pageSize: size, currentPage: 1 }),
// 获取当前页的预设列表
getCurrentPagePresets: () => {
const { presets, currentPage, pageSize } = get();
const startIndex = (currentPage - 1) * pageSize;
const endIndex = startIndex + pageSize;
return presets.slice(startIndex, endIndex);
},
// 获取总页数
getTotalPages: () => {
const { presets, pageSize } = get();
return Math.ceil(presets.length / pageSize);
}
}));

View File

@@ -4,3 +4,4 @@ export { default as useApiConfigStore } from './ApiConfigSlice';
export { default as usePresetStore } from './PresetSlice';
export { default as useWorldBookStore } from './WorldBookSlice';
export { default as useCharacterStore } from './CharacterSlice';
export { default as useCharacterCardUIStore } from './CharacterCardUISlice';