CzRger 2 місяців тому
батько
коміт
652e0fde05

+ 4 - 1
src/components/czr-ui/CzrDialog.vue

@@ -36,7 +36,10 @@
       :class="{ isFull: full !== false }"
       v-loading="loading"
     >
-      <div class="__czr-dialog-content">
+      <div
+        class="__czr-dialog-content"
+        :class="{ 'no-foot': !(showClose || showSubmit) }"
+      >
         <slot />
       </div>
       <div

+ 3 - 0
src/style/czr.scss

@@ -230,6 +230,9 @@
           flex: 1;
           overflow-y: auto;
           padding: 1rem 1.5rem 0;
+          &.no-foot {
+            padding-bottom: 1.5rem;
+          }
         }
         .__czr-dialog-foot {
           width: 100%;

+ 40 - 4
src/views/manage/app/make/index.vue

@@ -79,14 +79,22 @@
                   class="flex h-12 w-full items-center gap-2.5 bg-[url('@/assets/images/knowledge/knowledge-back-test.png')] bg-[length:100%_100%] bg-no-repeat px-6"
                 >
                   <div class="mr-auto font-bold text-[#303133]">提示词</div>
-                  <CzrButton type="normal" title="保存为模板" />
-                  <CzrButton type="normal" title="使用模板" />
+                  <CzrButton
+                    type="normal"
+                    title="保存为模板"
+                    @click="onAddTipsTemplate"
+                  />
+                  <CzrButton
+                    type="normal"
+                    title="使用模板"
+                    @click="onTipsTemplate"
+                  />
                 </div>
                 <div class="flex-1 p-4">
                   <textarea
                     class="h-full w-full"
-                    style="resize: none"
-                    ref="ref_textarea"
+                    style="resize: none; line-height: 1.4"
+                    ref="ref_tips"
                     v-model="state.form.tips"
                   ></textarea>
                 </div>
@@ -550,6 +558,14 @@
       :transfer="state.modelSelect.transfer"
       @refresh="getModel"
     />
+    <tipsTemplate
+      v-model:show="state.tipsTemplate.show"
+      @insert="(val) => ((state.form.tips = val), ref_tips.focus())"
+    />
+    <tipsTemplateDetail
+      v-model:show="state.tipsTemplateDetail.show"
+      :transfer="state.tipsTemplateDetail.transfer"
+    />
   </div>
 </template>
 
@@ -574,6 +590,8 @@ import { isValue, YMDHms } from '@/utils/czr-util'
 import Sortable from 'sortablejs'
 import { debounce } from 'lodash'
 import chat from '@/views/chat/index.vue'
+import tipsTemplate from './template/index.vue'
+import tipsTemplateDetail from './template/detail.vue'
 
 const DictionaryStore = useDictionaryStore()
 const route = useRoute()
@@ -616,6 +634,13 @@ const state: any = reactive({
     show: false,
     transfer: {},
   },
+  tipsTemplate: {
+    show: false,
+  },
+  tipsTemplateDetail: {
+    show: false,
+    transfer: {},
+  },
   prologuesAdd: {
     value: '',
   },
@@ -623,6 +648,7 @@ const state: any = reactive({
   isDebug: false,
 })
 const ref_form = ref()
+const ref_tips = ref()
 const ref_prologue = ref()
 const ref_prologueBody = ref()
 const debugError = computed(() => {
@@ -792,6 +818,16 @@ const autoSave = debounce((v) => {
     state.isDebug = false
   }, 1000)
 }, 3000)
+const onAddTipsTemplate = () => {
+  state.tipsTemplateDetail.transfer = {
+    mode: 'add',
+    tips: state.form.tips + '',
+  }
+  state.tipsTemplateDetail.show = true
+}
+const onTipsTemplate = () => {
+  state.tipsTemplate.show = true
+}
 onMounted(() => {
   initDictionary()
   initDetail()

+ 170 - 0
src/views/manage/app/make/template/detail.vue

@@ -0,0 +1,170 @@
+<template>
+  <CzrDialog
+    :show="show"
+    :title="titleCpt"
+    @onClose="$emit('update:show', false)"
+    @onSubmit="onSubmit"
+    width="62.5rem"
+    height="auto"
+    max-height="90%"
+    :loading="state.loading"
+  >
+    <div class="bm-form">
+      <CzrForm ref="ref_form" :form-view="isViewCpt" layout="y">
+        <CzrFormColumn
+          required
+          :span="24"
+          label="提示词名称"
+          v-model:param="state.form.name"
+        />
+        <CzrFormColumn
+          :span="24"
+          label="提示词描述"
+          v-model:param="state.form.description"
+          type="textarea"
+          :rows="2"
+        />
+        <CzrFormColumn
+          required
+          :span="24"
+          label="提示词"
+          v-model:param="state.form.tips"
+          type="textarea"
+          :rows="16"
+        />
+      </CzrForm>
+    </div>
+  </CzrDialog>
+</template>
+
+<script setup lang="ts">
+import {
+  computed,
+  getCurrentInstance,
+  nextTick,
+  reactive,
+  ref,
+  watch,
+} from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
+
+const AppStore = useAppStore()
+const DictionaryStore = useDictionaryStore()
+const DialogStore = useDialogStore()
+const emit = defineEmits(['update:show', 'refresh'])
+const { proxy } = getCurrentInstance()
+const props = defineProps({
+  show: { default: false },
+  transfer: <any>{},
+})
+const state: any = reactive({
+  loading: false,
+  form: {},
+})
+const ref_form = ref()
+const titleCpt = computed(() => {
+  let t = '提示词模板'
+  switch (props.transfer.mode) {
+    case 'add':
+      t = '创建' + t
+      break
+    case 'edit':
+      t = '编辑' + t
+      break
+    case 'view':
+      t = '查看' + t
+      break
+  }
+  return t
+})
+const isViewCpt = computed(() => props.transfer?.mode === 'view')
+watch(
+  () => props.show,
+  (n) => {
+    if (n) {
+      initDictionary()
+      state.form = {}
+      if (props.transfer.mode !== 'add') {
+        initData()
+      } else {
+        state.form.tips = props.transfer.tips || ''
+      }
+      nextTick(() => {
+        ref_form.value.reset()
+      })
+    }
+  },
+)
+const initData = () => {
+  // state.loading = true
+  // appDetail(props.transfer.id)
+  //   .then(({ data }: any) => {
+  //     state.form = data
+  //     if (data.icon) {
+  //       state.icon = [{ url: data.icon, name: data.icon }]
+  //     }
+  //   })
+  //   .catch(() => {})
+  //   .finally(() => {
+  //     state.loading = false
+  //   })
+}
+const onSubmit = () => {
+  ref_form.value
+    .submit()
+    .then(() => {
+      DialogStore.confirm({
+        content: `请确认是否提交?`,
+        onSubmit: () => {
+          // state.loading = true
+          // state.form.icon = state.icon[0].url
+          // if (props.transfer.mode === 'add') {
+          //   appAdd(state.form)
+          //     .then(() => {
+          //       ElMessage.success(`${titleCpt.value}成功!`)
+          //       emit('update:show', false)
+          //       emit('refresh')
+          //     })
+          //     .catch(() => {})
+          //     .finally(() => {
+          //       state.loading = false
+          //     })
+          // } else if (props.transfer.mode === 'edit') {
+          //   appEdit(state.form)
+          //     .then(() => {
+          //       ElMessage.success(`${titleCpt.value}成功!`)
+          //       emit('update:show', false)
+          //       emit('refresh')
+          //     })
+          //     .catch(() => {})
+          //     .finally(() => {
+          //       state.loading = false
+          //     })
+          // } else if (props.transfer.mode === 'copy') {
+          //   appCopy(state.form.id, state.form)
+          //     .then(() => {
+          //       ElMessage.success(`${titleCpt.value}成功!`)
+          //       emit('update:show', false)
+          //       emit('refresh')
+          //     })
+          //     .catch(() => {})
+          //     .finally(() => {
+          //       state.loading = false
+          //     })
+          // }
+        },
+      })
+    })
+    .catch((e) => {
+      ElMessage({
+        message: e[0].message,
+        grouping: true,
+        type: 'warning',
+      })
+    })
+}
+const initDictionary = () => {}
+</script>
+
+<style lang="scss" scoped></style>

+ 175 - 0
src/views/manage/app/make/template/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <CzrDialog
+    :show="show"
+    :title="titleCpt"
+    @onClose="$emit('update:show', false)"
+    width="80%"
+    height="90%"
+    :loading="state.loading"
+    :show-close="false"
+    :show-submit="false"
+  >
+    <div class="bm-form flex h-full w-full flex-col p-4">
+      <div class="flex items-center">
+        <CzrButton
+          :type="state.tab === Tab.System ? 'primary' : 'normal'"
+          title="系统"
+          @click="state.tab = Tab.System"
+        />
+        <CzrButton
+          :type="state.tab === Tab.User ? 'primary' : 'normal'"
+          title="个人"
+          @click="state.tab = Tab.User"
+          class="ml-4"
+        />
+        <CzrFormColumn
+          width="15.63rem"
+          class="__czr-table-form-column ml-auto"
+          :span="24"
+          label-width="0px"
+          v-model:param="state.text"
+          placeholder="输入关键词以检索"
+          :prefix-icon="Search"
+        />
+      </div>
+      <div class="mt-4 grid flex-1 grid-cols-3 gap-4 overflow-hidden">
+        <div
+          class="col-span-1 mr-2 flex flex-col gap-2 overflow-y-auto pr-2 pb-1"
+        >
+          <template v-for="item in state.list[state.tab]">
+            <div
+              class="__hover flex flex-col rounded-lg px-4 py-3"
+              style="border: var(--czr-border)"
+              :style="`${state.selected?.id == item.id ? 'border-color: var(--czr-main-color);background-color: rgba(var(--czr-main-color-rgb), 0.1)' : ''}`"
+              @click="state.selected = item"
+            >
+              <div class="font-bold text-[#2E3238]">{{ item.name }}</div>
+              <div class="mt-2 text-sm text-[#606266]" v-title>
+                {{ item.description }}
+              </div>
+            </div>
+          </template>
+        </div>
+        <div
+          class="col-span-2 flex flex-col overflow-hidden pr-1"
+          v-if="state.selected"
+        >
+          <div
+            class="flex-1 overflow-y-auto bg-gradient-to-b from-[#2853F7]/10 to-[#ffffff]/10 p-4 text-base text-[#606266] shadow"
+            style="line-height: 1.4"
+          >
+            水水水水水水水水水水水水水水水水水水<br />
+            水水水水水水水水水水水水水水水水水水<br />
+          </div>
+          <div class="mt-4 flex justify-end gap-4">
+            <div
+              class="__czr-dialog-foot_submit __hover"
+              @click="onCopy(state.selected.description)"
+            >
+              复制
+            </div>
+            <div
+              class="__czr-dialog-foot_cancel __hover"
+              @click="onInsert(state.selected.description)"
+            >
+              插入
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </CzrDialog>
+</template>
+
+<script setup lang="ts">
+import {
+  computed,
+  getCurrentInstance,
+  nextTick,
+  reactive,
+  ref,
+  watch,
+} from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
+import { copy } from '@/utils/czr-util'
+import CzrDialog from '@/components/czr-ui/CzrDialog.vue'
+import { Search } from '@element-plus/icons-vue'
+import { debounce } from 'lodash'
+import { pluginDel } from '@/api/modules/model'
+
+const AppStore = useAppStore()
+const DictionaryStore = useDictionaryStore()
+const DialogStore = useDialogStore()
+const emit = defineEmits(['update:show', 'insert'])
+const props = defineProps({
+  show: { default: false },
+  transfer: <any>{},
+})
+enum Tab {
+  System = 'system',
+  User = 'user',
+}
+const state: any = reactive({
+  tab: Tab.System,
+  text: '',
+  list: {
+    [Tab.System]: [],
+    [Tab.User]: [],
+  },
+  selected: null,
+})
+const titleCpt = computed(() => {
+  let t = '提示词模板'
+  return t
+})
+const isViewCpt = computed(() => props.transfer?.mode === 'view')
+watch(
+  () => props.show,
+  (n) => {
+    if (n) {
+      initData()
+      state.selected = null
+      initDictionary()
+    }
+  },
+)
+const setText = debounce((v) => {
+  initData()
+}, 1000)
+watch(
+  () => state.text,
+  (n) => {
+    setText(n)
+  },
+)
+const initData = () => {
+  const arr = []
+  for (let i = 0; i < 20; i++) {
+    arr.push({
+      id: i,
+      name: '通用结构' + i,
+      description:
+        '顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶',
+    })
+  }
+  state.list.system = arr
+}
+const onCopy = (str) => {
+  copy(str)
+  ElMessage.success('复制成功!')
+}
+const onInsert = (str) => {
+  DialogStore.confirm({
+    title: '插入确认',
+    content: `插入后将覆盖提示词内容,请确认是否插入?`,
+    onSubmit: () => {
+      emit('insert', str)
+      emit('update:show', false)
+    },
+  })
+}
+const initDictionary = () => {}
+</script>
+
+<style lang="scss" scoped></style>