| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- <template>
- <a-drawer
- :open="open"
- title="分析模板库"
- wrap-class-name="ai-template"
- :width="520"
- @close="emit('update:open', false)"
- >
- <div v-if="!groups.length" class="ai-template__empty">没有可用的模板。</div>
- <section v-for="group in groups" :key="group.group" class="ai-template__group">
- <div class="ai-template__group-head">
- <span>{{ group.group }}</span>
- <span class="ai-template__group-count">{{ group.items.length }}</span>
- </div>
- <article v-for="item in group.items" :key="item.id" class="ai-template__item">
- <div class="ai-template__item-head">
- <span class="ai-template__title">{{ item.title }}</span>
- <span v-if="item.builtin" class="ai-template__badge">预置</span>
- <span class="ai-template__spacer"></span>
- <a-button size="small" @click="onPick(item)">插入</a-button>
- <a-button v-if="!item.builtin" size="small" danger type="text" @click="onRemove(item)">删除</a-button>
- </div>
- <p class="ai-template__prompt">{{ item.prompt }}</p>
- </article>
- </section>
- </a-drawer>
- </template>
- <script lang="ts" setup>
- /**
- * 分析模板抽屉:选一个模板填入输入框(只填不发)。
- *
- * 由旧版模板面板迁移并按需裁剪:只保留「选」,
- * 不带存为模板 / 导出导入工具条;沿用历史存储键,样式用 --ai-* 令牌。
- */
- import { computed, ref, watch } from 'vue';
- import { Button, Drawer } from 'ant-design-vue';
- import { useMessage } from '@/core/hooks/web/useMessage';
- import {
- groupTemplates,
- readCustomTemplates,
- removeTemplate,
- type PromptTemplate,
- } from '../utils/promptTemplateLibrary';
- const props = defineProps<{ open: boolean }>();
- const emit = defineEmits<{
- (e: 'update:open', value: boolean): void;
- (e: 'pick', prompt: string): void;
- }>();
- const ADrawer = Drawer;
- const AButton = Button;
- const { showMessage } = useMessage();
- const custom = ref<PromptTemplate[]>(readCustomTemplates());
- const groups = computed(() => groupTemplates(custom.value));
- // 每次打开都重读,避免多标签/外部改动导致列表过期
- watch(
- () => props.open,
- (open) => {
- if (open) {
- custom.value = readCustomTemplates();
- }
- },
- );
- function onPick(item: PromptTemplate) {
- emit('pick', item.prompt);
- emit('update:open', false);
- }
- function onRemove(item: PromptTemplate) {
- custom.value = removeTemplate(item.id);
- showMessage('已删除模板', 'success');
- }
- </script>
- <style lang="less" scoped>
- .ai-template {
- &__empty {
- padding: var(--ai-sp-4) 0;
- font-size: 12px;
- color: var(--ai-text-2);
- text-align: center;
- }
- &__group {
- margin-bottom: var(--ai-sp-4);
- }
- &__group-head {
- display: flex;
- align-items: baseline;
- gap: 6px;
- margin-bottom: var(--ai-sp-2);
- padding-bottom: 4px;
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.04em;
- text-transform: uppercase;
- color: var(--ai-text-2);
- border-bottom: 1px solid var(--ai-border);
- }
- &__group-count {
- font-weight: 400;
- color: var(--ai-text-2);
- }
- &__item {
- padding: var(--ai-sp-2) 0;
- & + & {
- border-top: 1px dashed var(--ai-border);
- }
- }
- &__item-head {
- display: flex;
- align-items: center;
- gap: 6px;
- }
- &__title {
- font-size: 13px;
- font-weight: 600;
- color: var(--ai-text);
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
- &__badge {
- flex: 0 0 auto;
- padding: 0 6px;
- font-size: 10.5px;
- line-height: 17px;
- color: var(--ai-text-2);
- border: 1px solid var(--ai-border);
- border-radius: 4px;
- }
- &__spacer {
- flex: 1 1 auto;
- }
- &__prompt {
- margin: 4px 0 0;
- font-size: 12px;
- line-height: 1.7;
- color: var(--ai-text-2);
- /* 模板正文可能带占位符,保留换行但压到 3 行,避免抽屉变成文章 */
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
- overflow: hidden;
- white-space: pre-wrap;
- word-break: break-word;
- }
- }
- </style>
|