|
323 | 323 | </div> |
324 | 324 |
|
325 | 325 | <!-- Simple Template Editor --> |
326 | | - <div v-if="!form.isAdvanced"> |
327 | | - <label class="block text-sm font-medium mb-1.5"> |
328 | | - {{ t('template.content') }} |
329 | | - <span class="text-xs ml-2 opacity-70"> |
330 | | - {{ t('templateManager.simpleTemplateHint') }} |
331 | | - </span> |
332 | | - </label> |
| 326 | + <NSpace v-if="!form.isAdvanced" vertical :size="8"> |
| 327 | + <NSpace justify="space-between" align="center"> |
| 328 | + <NText> |
| 329 | + {{ t('template.content') }} |
| 330 | + <NText depth="3" style="font-size: 12px; margin-left: 8px;"> |
| 331 | + {{ t('templateManager.simpleTemplateHint') }} |
| 332 | + </NText> |
| 333 | + </NText> |
| 334 | + <NButton |
| 335 | + v-if="!viewingTemplate" |
| 336 | + size="tiny" |
| 337 | + quaternary |
| 338 | + @click="openFullscreenEditor('simple')" |
| 339 | + :title="t('templateManager.fullscreenEdit')" |
| 340 | + > |
| 341 | + <template #icon> |
| 342 | + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4"> |
| 343 | + <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /> |
| 344 | + </svg> |
| 345 | + </template> |
| 346 | + {{ t('templateManager.fullscreen') }} |
| 347 | + </NButton> |
| 348 | + </NSpace> |
333 | 349 | <NInput |
334 | 350 | v-model:value="form.content" |
335 | 351 | type="textarea" |
336 | 352 | :placeholder="t('template.contentPlaceholder')" |
337 | | - :rows="15" |
| 353 | + :autosize="{ minRows: 15, maxRows: 30 }" |
338 | 354 | :readonly="!!viewingTemplate" |
339 | 355 | /> |
340 | | - </div> |
| 356 | + </NSpace> |
341 | 357 |
|
342 | 358 | <!-- Advanced Template Editor --> |
343 | | - <div v-else> |
344 | | - <div class="flex items-center justify-between mb-3"> |
345 | | - <label class="block text-sm font-medium"> |
| 359 | + <NSpace v-else vertical :size="12"> |
| 360 | + <NSpace justify="space-between" align="center"> |
| 361 | + <NText> |
346 | 362 | {{ t('templateManager.messageTemplates') }} |
347 | | - <span class="text-xs ml-2 opacity-70"> |
| 363 | + <NText depth="3" style="font-size: 12px; margin-left: 8px;"> |
348 | 364 | {{ t('templateManager.advancedTemplateHint') }} |
349 | | - </span> |
350 | | - </label> |
| 365 | + </NText> |
| 366 | + </NText> |
351 | 367 | <NButton |
352 | 368 | v-if="!viewingTemplate" |
353 | 369 | @click="addMessage" |
|
361 | 377 | </template> |
362 | 378 | {{ t('templateManager.addMessage') }} |
363 | 379 | </NButton> |
364 | | - </div> |
| 380 | + </NSpace> |
365 | 381 |
|
366 | 382 | <!-- Message List --> |
367 | 383 | <NScrollbar style="max-height: 500px;"> |
|
384 | 400 | { label: t('templateManager.roleAssistant'), value: 'assistant' } |
385 | 401 | ]" |
386 | 402 | /> |
387 | | - |
| 403 | + |
388 | 404 | <!-- Message Content --> |
389 | | - <NInput |
390 | | - v-model:value="message.content" |
391 | | - type="textarea" |
392 | | - :placeholder="t('templateManager.messageContentPlaceholder')" |
393 | | - :rows="3" |
394 | | - :readonly="!!viewingTemplate" |
395 | | - class="flex-1" |
396 | | - /> |
397 | | - |
| 405 | + <NSpace vertical :size="4" style="flex: 1;"> |
| 406 | + <NInput |
| 407 | + v-model:value="message.content" |
| 408 | + type="textarea" |
| 409 | + :placeholder="t('templateManager.messageContentPlaceholder')" |
| 410 | + :autosize="{ minRows: 3, maxRows: 20 }" |
| 411 | + :readonly="!!viewingTemplate" |
| 412 | + /> |
| 413 | + <NButton |
| 414 | + v-if="!viewingTemplate" |
| 415 | + size="tiny" |
| 416 | + quaternary |
| 417 | + @click="openFullscreenEditor('advanced', index)" |
| 418 | + :title="t('templateManager.fullscreenEdit')" |
| 419 | + style="align-self: flex-end;" |
| 420 | + > |
| 421 | + <template #icon> |
| 422 | + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-3 h-3"> |
| 423 | + <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /> |
| 424 | + </svg> |
| 425 | + </template> |
| 426 | + {{ t('templateManager.fullscreen') }} |
| 427 | + </NButton> |
| 428 | + </NSpace> |
| 429 | + |
398 | 430 | <!-- Message Controls --> |
399 | | - <div v-if="!viewingTemplate" class="flex flex-col gap-1 flex-shrink-0"> |
| 431 | + <NSpace v-if="!viewingTemplate" vertical :size="4" style="flex-shrink: 0;"> |
400 | 432 | <NButton |
401 | 433 | quaternary |
402 | 434 | size="tiny" |
|
433 | 465 | </svg> |
434 | 466 | </template> |
435 | 467 | </NButton> |
436 | | - </div> |
| 468 | + </NSpace> |
437 | 469 | </div> |
438 | 470 | </NCard> |
439 | 471 | </NSpace> |
440 | 472 | </NScrollbar> |
441 | | - </div> |
| 473 | + </NSpace> |
442 | 474 |
|
443 | 475 | <!-- Template Preview --> |
444 | 476 | <div v-if="form.isAdvanced && form.messages.length > 0"> |
|
553 | 585 | </NSpace> |
554 | 586 | </template> |
555 | 587 | </NModal> |
| 588 | + |
| 589 | + <!-- Fullscreen Editor Modal --> |
| 590 | + <NModal |
| 591 | + :show="fullscreenEditor.show" |
| 592 | + preset="card" |
| 593 | + :style="{ width: '95vw', height: '90vh', maxWidth: '1400px' }" |
| 594 | + :title="t('templateManager.fullscreenEdit')" |
| 595 | + size="large" |
| 596 | + :bordered="false" |
| 597 | + :segmented="true" |
| 598 | + @update:show="(value: boolean) => !value && closeFullscreenEditor()" |
| 599 | + > |
| 600 | + <NEl style="height: calc(90vh - 140px);"> |
| 601 | + <NInput |
| 602 | + v-model:value="fullscreenEditor.content" |
| 603 | + type="textarea" |
| 604 | + :placeholder="fullscreenEditor.type === 'simple' |
| 605 | + ? t('template.contentPlaceholder') |
| 606 | + : t('templateManager.messageContentPlaceholder')" |
| 607 | + style="height: 100%;" |
| 608 | + :autosize="false" |
| 609 | + /> |
| 610 | + </NEl> |
| 611 | + |
| 612 | + <template #action> |
| 613 | + <NSpace justify="space-between" style="width: 100%;"> |
| 614 | + <NText depth="3" style="font-size: 12px;"> |
| 615 | + {{ t('templateManager.characterCount', { count: fullscreenEditor.content.length }) }} |
| 616 | + </NText> |
| 617 | + <NSpace> |
| 618 | + <NButton @click="closeFullscreenEditor()"> |
| 619 | + {{ t('common.cancel') }} |
| 620 | + </NButton> |
| 621 | + <NButton type="primary" @click="saveFullscreenEditor"> |
| 622 | + {{ t('common.save') }} |
| 623 | + </NButton> |
| 624 | + </NSpace> |
| 625 | + </NSpace> |
| 626 | + </template> |
| 627 | + </NModal> |
556 | 628 | </NModal> |
557 | 629 | </template> |
558 | 630 |
|
559 | 631 | <script setup lang="ts"> |
560 | 632 | import { ref, onMounted, computed, watch, nextTick, inject } from 'vue' |
561 | 633 | import { useI18n } from 'vue-i18n' |
562 | | -import { |
563 | | - NModal, NCard, NTabs, NTabPane, NButton, NTag, NInput, NInputGroup, |
| 634 | +import { |
| 635 | + NModal, NCard, NTabs, NTabPane, NButton, NTag, NInput, NInputGroup, |
564 | 636 | NSelect, NSpace, NText, NH3, NH4, NDivider, NScrollbar, |
565 | 637 | NButtonGroup, NIcon, NCode, NSwitch, NMessageProvider, |
566 | | - NGrid, NGridItem |
| 638 | + NGrid, NGridItem, NEl |
567 | 639 | } from 'naive-ui' |
568 | 640 | import { TemplateProcessor, type Template, type MessageTemplate } from '@prompt-optimizer/core' |
569 | 641 | import { useToast } from '../composables/useToast' |
@@ -643,6 +715,18 @@ const migrationDialog = ref<{ |
643 | 715 | converted: [] |
644 | 716 | }) |
645 | 717 |
|
| 718 | +const fullscreenEditor = ref<{ |
| 719 | + show: boolean |
| 720 | + type: 'simple' | 'advanced' |
| 721 | + messageIndex: number |
| 722 | + content: string |
| 723 | +}>({ |
| 724 | + show: false, |
| 725 | + type: 'simple', |
| 726 | + messageIndex: -1, |
| 727 | + content: '' |
| 728 | +}) |
| 729 | +
|
646 | 730 | // 添加计算属性 |
647 | 731 | const selectedTemplate = computed(() => { |
648 | 732 | switch (props.templateType) { |
@@ -983,6 +1067,36 @@ const applyMigration = async () => { |
983 | 1067 | } |
984 | 1068 | } |
985 | 1069 |
|
| 1070 | +// 打开全屏编辑器 |
| 1071 | +const openFullscreenEditor = (type: 'simple' | 'advanced', messageIndex = -1) => { |
| 1072 | + fullscreenEditor.value = { |
| 1073 | + show: true, |
| 1074 | + type, |
| 1075 | + messageIndex, |
| 1076 | + content: type === 'simple' ? form.value.content : form.value.messages[messageIndex]?.content || '' |
| 1077 | + } |
| 1078 | +} |
| 1079 | +
|
| 1080 | +// 关闭全屏编辑器 |
| 1081 | +const closeFullscreenEditor = () => { |
| 1082 | + fullscreenEditor.value = { |
| 1083 | + show: false, |
| 1084 | + type: 'simple', |
| 1085 | + messageIndex: -1, |
| 1086 | + content: '' |
| 1087 | + } |
| 1088 | +} |
| 1089 | +
|
| 1090 | +// 保存全屏编辑器内容 |
| 1091 | +const saveFullscreenEditor = () => { |
| 1092 | + if (fullscreenEditor.value.type === 'simple') { |
| 1093 | + form.value.content = fullscreenEditor.value.content |
| 1094 | + } else if (fullscreenEditor.value.messageIndex >= 0) { |
| 1095 | + form.value.messages[fullscreenEditor.value.messageIndex].content = fullscreenEditor.value.content |
| 1096 | + } |
| 1097 | + closeFullscreenEditor() |
| 1098 | +} |
| 1099 | +
|
986 | 1100 | // 提交表单 |
987 | 1101 | const handleSubmit = async () => { |
988 | 1102 | try { |
|
0 commit comments