|
|
@@ -198,20 +198,34 @@
|
|
|
</div>
|
|
|
<!-- 会话列表弹框 -->
|
|
|
<div v-if="showSessionPopup" ref="sessionPopupRef" class="session-popup" @click.stop @pointerdown.stop>
|
|
|
+ <div class="session-popup-header">
|
|
|
+ <span>选择会话</span>
|
|
|
+ <span class="session-count">{{ selectedSessions.length }}/5</span>
|
|
|
+ </div>
|
|
|
<div class="session-list">
|
|
|
<div
|
|
|
v-for="(task, index) in filteredSessionList"
|
|
|
:key="task.id"
|
|
|
class="session-item"
|
|
|
- :class="{ active: index === activeSessionIndex }"
|
|
|
+ :class="{
|
|
|
+ active: index === activeSessionIndex,
|
|
|
+ selected: isSessionSelected(task.id),
|
|
|
+ disabled: (selectedSessions.length >= 5 && !isSessionSelected(task.id)) || task.id === props.currentTaskId,
|
|
|
+ }"
|
|
|
@click="handleSelectSession(task)"
|
|
|
>
|
|
|
+ <div class="session-checkbox" :class="{ checked: isSessionSelected(task.id) }">
|
|
|
+ <span v-if="isSessionSelected(task.id)" class="check-mark">✓</span>
|
|
|
+ </div>
|
|
|
<div class="session-item-icon"></div>
|
|
|
<span class="session-item-name">{{ task.name }}</span>
|
|
|
</div>
|
|
|
<div v-if="filteredSessionList.length === 0" class="session-empty">暂无匹配会话</div>
|
|
|
</div>
|
|
|
- <div class="session-popup-footer">输入内容以搜索对话</div>
|
|
|
+ <div class="session-popup-footer">
|
|
|
+ <span v-if="selectedSessions.length >= 5" class="max-hint">最多选择5个会话</span>
|
|
|
+ <span v-else>点击选择会话(最多5个)</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -236,6 +250,7 @@
|
|
|
initialThinkLevel?: string;
|
|
|
initialEditMode?: string;
|
|
|
taskList?: Task[];
|
|
|
+ currentTaskId?: string;
|
|
|
}>(),
|
|
|
{
|
|
|
contextUsed: 0,
|
|
|
@@ -245,6 +260,7 @@
|
|
|
initialThinkLevel: 'off',
|
|
|
initialEditMode: 'full',
|
|
|
taskList: () => [],
|
|
|
+ currentTaskId: '',
|
|
|
}
|
|
|
);
|
|
|
|
|
|
@@ -257,7 +273,7 @@
|
|
|
(e: 'model-change', modelKey: string): void;
|
|
|
(e: 'think-level-change', levelKey: string): void;
|
|
|
(e: 'edit-mode-change', modeKey: string): void;
|
|
|
- (e: 'insert-session', taskId: string, taskName: string): void;
|
|
|
+ (e: 'update:selectedSessions', sessions: Array<{ id: string; name: string }>): void;
|
|
|
}>();
|
|
|
|
|
|
const handleSelectModel = (item: ModelOption) => {
|
|
|
@@ -444,9 +460,14 @@
|
|
|
const showSessionPopup = ref(false);
|
|
|
const activeSessionIndex = ref(0);
|
|
|
const selectedSessions = ref<Array<{ id: string; name: string }>>([]);
|
|
|
+ const sessionPopupManual = ref(false);
|
|
|
let isRemovingTag = false;
|
|
|
let sessionJustSelected = false;
|
|
|
|
|
|
+ const isSessionSelected = (sessionId: string) => {
|
|
|
+ return selectedSessions.value.some((s) => s.id === sessionId);
|
|
|
+ };
|
|
|
+
|
|
|
const sessionSearchText = computed(() => {
|
|
|
const val = props.modelValue || '';
|
|
|
const hashIndex = val.lastIndexOf('#');
|
|
|
@@ -490,6 +511,7 @@
|
|
|
|
|
|
const handleInsertSession = () => {
|
|
|
showPopup.value = false;
|
|
|
+ sessionPopupManual.value = true;
|
|
|
showSessionPopup.value = true;
|
|
|
const cur = props.modelValue || '';
|
|
|
const needsSpace = cur && !cur.endsWith(' ') ? ' ' : '';
|
|
|
@@ -501,10 +523,16 @@
|
|
|
};
|
|
|
|
|
|
const handleSelectSession = (task: Task) => {
|
|
|
- selectedSessions.value = [{ id: task.id, name: task.name }];
|
|
|
- showSessionPopup.value = false;
|
|
|
+ if (task.id === props.currentTaskId) return;
|
|
|
+ const idx = selectedSessions.value.findIndex((s) => s.id === task.id);
|
|
|
+ if (idx >= 0) {
|
|
|
+ selectedSessions.value.splice(idx, 1);
|
|
|
+ } else {
|
|
|
+ if (selectedSessions.value.length >= 5) return;
|
|
|
+ selectedSessions.value.push({ id: task.id, name: task.name });
|
|
|
+ }
|
|
|
removeSearchTag();
|
|
|
- emit('insert-session', task.id, task.name);
|
|
|
+ emit('update:selectedSessions', [...selectedSessions.value]);
|
|
|
};
|
|
|
|
|
|
const removeSearchTag = () => {
|
|
|
@@ -531,10 +559,12 @@
|
|
|
|
|
|
const removeSession = (sessionId: string) => {
|
|
|
selectedSessions.value = selectedSessions.value.filter((s) => s.id !== sessionId);
|
|
|
+ emit('update:selectedSessions', [...selectedSessions.value]);
|
|
|
};
|
|
|
|
|
|
const handleTextareaInput = (val: string) => {
|
|
|
emit('update:modelValue', val);
|
|
|
+ if (sessionPopupManual.value) return;
|
|
|
const hashIndex = val.lastIndexOf('#');
|
|
|
if (hashIndex === -1) {
|
|
|
showSessionPopup.value = false;
|
|
|
@@ -554,11 +584,13 @@
|
|
|
if (selectedSessions.value.length > 0) {
|
|
|
e.preventDefault();
|
|
|
selectedSessions.value.pop();
|
|
|
+ emit('update:selectedSessions', [...selectedSessions.value]);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
onClickOutside(sessionPopupRef, () => {
|
|
|
showSessionPopup.value = false;
|
|
|
+ sessionPopupManual.value = false;
|
|
|
});
|
|
|
|
|
|
const handleInsertCommand = () => {
|
|
|
@@ -1308,6 +1340,23 @@
|
|
|
z-index: 1000;
|
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
|
|
|
|
|
|
+ .session-popup-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10px 14px 8px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #e0e6ed;
|
|
|
+ border-bottom: 1px solid rgba(63, 80, 106, 0.3);
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .session-count {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #3a8fd4;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.session-list {
|
|
|
flex: 1;
|
|
|
overflow-y: auto;
|
|
|
@@ -1330,6 +1379,42 @@
|
|
|
background: rgba(10, 132, 255, 0.2);
|
|
|
}
|
|
|
|
|
|
+ &.selected {
|
|
|
+ background: rgba(10, 132, 255, 0.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ opacity: 0.4;
|
|
|
+ cursor: not-allowed;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: transparent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .session-checkbox {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ border: 1.5px solid rgba(255, 255, 255, 0.25);
|
|
|
+ border-radius: 3px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &.checked {
|
|
|
+ background: #3a8fd4;
|
|
|
+ border-color: #3a8fd4;
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-mark {
|
|
|
+ font-size: 11px;
|
|
|
+ color: #fff;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.session-item-icon {
|
|
|
width: 18px;
|
|
|
height: 18px;
|
|
|
@@ -1363,6 +1448,10 @@
|
|
|
text-align: center;
|
|
|
border-top: 1px solid rgba(63, 80, 106, 0.3);
|
|
|
flex-shrink: 0;
|
|
|
+
|
|
|
+ .max-hint {
|
|
|
+ color: #faad14;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|