Selaa lähdekoodia

Merge branch 'mask' of xiongzhu/chatgpt-web into master

panhui 2 vuotta sitten
vanhempi
commit
fadc1bf87a

+ 20 - 7
src/api/index.ts

@@ -34,14 +34,14 @@ export function fetchChatAPIProcess<T = any>(params: {
         options: params.options
     }
 
-    if (authStore.isChatGPTAPI) {
-        data = {
-            ...data,
-            systemMessage: settingStore.systemMessage,
-            temperature: settingStore.temperature,
-            top_p: settingStore.top_p
-        }
+    // if (authStore.isChatGPTAPI) {
+    data = {
+        ...data,
+        systemMessage: settingStore.systemMessage,
+        temperature: settingStore.temperature,
+        top_p: settingStore.top_p
     }
+    // }
 
     return post<T>({
         url: '/chat/chat-process1',
@@ -159,3 +159,16 @@ export function fetchCommissionRecords<T>() {
         url: '/commission/records/get'
     })
 }
+
+export function fetchMasks<T>(data: any) {
+    return post<T>({
+        url: 'admin/mask',
+        data: data
+    })
+}
+
+export function fetchGetMask<T>(id: any) {
+    return get<T>({
+        url: `admin/mask/get/${id}`
+    })
+}

BIN
src/assets/mask-bg-dark.png


BIN
src/assets/mask-bg.png


BIN
src/assets/png-1-dark.png


BIN
src/assets/png-1.png


BIN
src/assets/png-2-dark.png


BIN
src/assets/png-2.png


BIN
src/assets/png-3-dark.png


BIN
src/assets/png-3.png


BIN
src/assets/png-4-dark.png


BIN
src/assets/png-4.png


BIN
src/assets/png-huan-dark.png


BIN
src/assets/png-huan.png


BIN
src/assets/png-mianju-dark.png


BIN
src/assets/png-mianju.png


BIN
src/assets/start.png


+ 164 - 0
src/components/common/MaskPannel.vue

@@ -0,0 +1,164 @@
+<template>
+    <div :style="{ backgroundImage: `url(${isDark ? maskBgDark : maskBg})` }" class="bg-cover px-[30px]">
+        <div class="alimamaShuHeiTi text-[28px] dark:text-white">挑选一个面具</div>
+        <div class="text-base mt-[14px] dark:text-white">现在开始,与面具背后的灵魂碰撞</div>
+        <n-grid :x-gap="26" :y-gap="26" :cols="2" class="py-[40px]">
+            <n-grid-item
+                class="mask h-[140px] flex flex-col items-center py-[10px]"
+                :class="{ maskDark: isDark }"
+                v-for="(item, index) in masks"
+                :key="index"
+                @click="update(item)"
+            >
+                <img :src="isDark ? item['icon']['dark'] : item['icon']['light']" class="w-[62px] h-[62px]" alt="" />
+
+                <div
+                    class="h-[44px] mt-[5px] color-black dark:color-white text-[15px] flex flex-col justify-center font-medium px-[20%] text-center"
+                >
+                    {{ item['name'] }}
+                </div>
+            </n-grid-item>
+        </n-grid>
+
+        <div class="flex py-[20%]">
+            <n-button
+                text
+                @click="refreash()"
+                size="large"
+                class="flex-1 !px-[22px] !rounded-[30px] !bg-white !border-0 dark:!bg-[#20223C]"
+                round
+                :color="isDark ? '#fff' : '#000'"
+            >
+                <template #icon>
+                    <img :src="isDark ? freashIconDark : freashIcon" alt="" />
+                </template>
+                换一批角色
+            </n-button>
+            <n-button type="primary" size="large" class="flex-1" round @click="handleAdd()">
+                <template #icon>
+                    <img :src="startIcon" alt="" />
+                </template>
+                开始
+            </n-button>
+        </div>
+
+        <!-- <n-button v-for="(item, index) in masks" :key="index">
+            {{ item.title }}
+        </n-button> -->
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import { NButton, NGrid, NGridItem, NConfigProvider } from 'naive-ui'
+import { useSettingStore, useChatStore } from '@/store'
+import { fetchMasks } from '@/api'
+import type { SettingsState } from '@/store/modules/settings/helper'
+import { useRouter } from 'vue-router'
+import { useTheme } from '@/hooks/useTheme'
+import maskBg from '@/assets/mask-bg.png'
+import maskBgDark from '@/assets/mask-bg-dark.png'
+import icon1 from '@/assets/png-1.png'
+import icon2 from '@/assets/png-2.png'
+import icon3 from '@/assets/png-3.png'
+import icon4 from '@/assets/png-4.png'
+import icon1Dark from '@/assets/png-1-dark.png'
+import icon2Dark from '@/assets/png-2-dark.png'
+import icon3Dark from '@/assets/png-3-dark.png'
+import icon4Dark from '@/assets/png-4-dark.png'
+import startIcon from '@/assets/start.png'
+import freashIcon from '@/assets/png-huan.png'
+import freashIconDark from '@/assets/png-huan-dark.png'
+
+const icons = [
+    {
+        light: icon1,
+        dark: icon1Dark
+    },
+    {
+        light: icon2,
+        dark: icon2Dark
+    },
+    {
+        light: icon3,
+        dark: icon3Dark
+    },
+    {
+        light: icon4,
+        dark: icon4Dark
+    }
+]
+const { isDark } = useTheme()
+const page = ref(1)
+const finish = ref(false)
+const masks = ref([])
+function getMask() {
+    let iconIndex = Math.floor(Math.random() * 4)
+    fetchMasks({ page: { page: page.value, limit: 4 } }).then((res: any) => {
+        masks.value = res.items.map((item: any, index: number) => {
+            return {
+                ...item,
+                icon: icons[(iconIndex + index) % 4]
+            }
+        })
+        if (res.meta.totalPages === res.meta.currentPage) {
+            finish.value = true
+        } else {
+            finish.value = false
+        }
+    })
+}
+
+onMounted(() => {
+    page.value = 1
+    getMask()
+})
+
+const emit = defineEmits(['closeMask'])
+const chatStore = useChatStore()
+const router = useRouter()
+function update(mask: any) {
+    chatStore.addHistory({ title: mask.name, uuid: Date.now(), isEdit: false, maskId: mask.id })
+    updateSettings({
+        systemMessage: mask.describe
+    })
+    emit('closeMask')
+    // router.back()
+}
+
+const settingStore = useSettingStore()
+function updateSettings(options: Partial<SettingsState>) {
+    settingStore.updateSetting(options)
+}
+
+function refreash() {
+    if (finish.value) {
+        page.value = 1
+    } else {
+        page.value = page.value + 1
+    }
+    getMask()
+}
+function handleAdd() {
+    settingStore.resetSetting()
+    chatStore.addHistory({ title: 'New Chat', uuid: Date.now(), isEdit: false, maskId: null })
+}
+</script>
+
+<style lang="less" scoped>
+.mask {
+    background: linear-gradient(180deg, #fdffff 0%, #e0e5ff 100%);
+    box-shadow: 0px 2px 6px 0px rgba(153, 144, 201, 0.5);
+    border-radius: 8px;
+
+    &.maskDark {
+        background: linear-gradient(310deg, #30155a 0%, #2d2c61 100%);
+        border: 1px solid #FFBEF2;
+        box-shadow: none;
+    }
+}
+
+.n-button + .n-button {
+    margin-left: 26px;
+}
+</style>

+ 3 - 1
src/components/common/index.ts

@@ -14,6 +14,7 @@ import CommissionPannel from './CommissionPannel.vue'
 import OfficalAccount from './OfficalAccount.vue'
 import VipModal from './VipModal.vue'
 import RuleContent from './RuleContent.vue'
+import MaskPannel from './MaskPannel.vue'
 
 export {
     HoverButton,
@@ -31,5 +32,6 @@ export {
     CommissionPannel,
     VipModal,
     RuleContent,
-    OfficalAccount
+    OfficalAccount,
+    MaskPannel
 }

+ 5 - 1
src/router/index.ts

@@ -92,7 +92,11 @@ const routes: RouteRecordRaw[] = [
         name: 'commission',
         component: () => import('@/views/page/CommissionView.vue')
     },
-
+    {
+        path: '/mask',
+        name: 'mask',
+        component: () => import('@/views/page/MaskView.vue')
+    },
     {
         path: '/404',
         name: '404',

+ 1 - 0
src/typings/chat.d.ts

@@ -13,6 +13,7 @@ declare namespace Chat {
         title: string
         isEdit: boolean
         uuid: number
+        maskId: number | null
     }
 
     interface ChatState {

+ 30 - 1
src/views/chat/Chat.vue

@@ -11,13 +11,15 @@ import { useChat } from './hooks/useChat'
 import { useCopyCode } from './hooks/useCopyCode'
 import { useUsingContext } from './hooks/useUsingContext'
 import HeaderComponent from './components/Header/index.vue'
-import { HoverButton, SvgIcon, MinePannel, VipPannel } from '@/components/common'
+import { HoverButton, SvgIcon, MinePannel, VipPannel, MaskPannel } from '@/components/common'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { useChatStore, useAppStore, usePromptStore, useAuthStore, useUserMemberStore } from '@/store'
 import { fetchChatAPIProcess } from '@/api'
 import { t } from '@/locales'
 import { useTheme } from '@/hooks/useTheme'
 import { emitter } from '@/plugins'
+import maskIcon from '@/assets/png-mianju.png'
+import maskDarkIcon from '@/assets/png-mianju-dark.png'
 
 let controller = new AbortController()
 
@@ -463,13 +465,29 @@ onMounted(() => {
             showVipTips.value = !!res
         }
     })
+    emitter.on('changeMask', res => {
+        if (isMobile.value) {
+            router.push('/mask')
+        } else {
+            showMask.value = true
+        }
+    })
 })
+const showMask = ref(false)
 
 const showVip = ref(false)
 const showVipTips = ref(false)
 function goVip() {
     emitter.emit('changeVipShow', true)
 }
+
+function handleAdd() {
+    if (isMobile.value) {
+        router.push('/mask')
+    } else {
+        showMask.value = true
+    }
+}
 </script>
 
 <template>
@@ -523,6 +541,9 @@ function goVip() {
         <footer :class="footerClass">
             <div class="w-full max-w-screen-xl m-auto">
                 <div class="flex items-center justify-between space-x-2">
+                    <HoverButton @click="handleAdd">
+                        <img class="w-[24px] h-[24px]" :src="isDark ? maskDarkIcon : maskIcon" alt="" />
+                    </HoverButton>
                     <HoverButton @click="handleClear">
                         <span class="text-xl text-[#4f555e] dark:text-white">
                             <SvgIcon icon="ri:delete-bin-line" />
@@ -575,6 +596,14 @@ function goVip() {
             </n-card>
         </n-modal>
 
+        <n-modal v-model:show="showMask" transform-origin="center">
+            <n-card :bordered="false" class="!max-w-md !rounded-xl" content-style="padding:0">
+                <div class="!rounded-xl">
+                    <mask-pannel class="!rounded-xl pt-8" @closeMask="showMask = false"></mask-pannel>
+                </div>
+            </n-card>
+        </n-modal>
+
         <n-modal
             v-model:show="showVip"
             :block-scroll="false"

+ 17 - 2
src/views/chat/components/Header/index.vue

@@ -2,6 +2,12 @@
 import { computed, nextTick } from 'vue'
 import { HoverButton, SvgIcon, UserAvatar } from '@/components/common'
 import { useAppStore, useChatStore } from '@/store'
+import maskIcon from '@/assets/png-mianju.png'
+import maskDarkIcon from '@/assets/png-mianju-dark.png'
+import { useTheme } from '@/hooks/useTheme'
+import { emitter } from '@/plugins'
+
+const { isDark } = useTheme()
 
 interface Props {
     usingContext: boolean
@@ -44,6 +50,10 @@ function toggleUsingContext() {
 function goMine() {
     emit('goMine')
 }
+
+function handleAdd() {
+    emitter.emit('changeMask', true)
+}
 </script>
 
 <template>
@@ -64,14 +74,19 @@ function goMine() {
                 {{ currentChatHistory?.title ?? '' }}
             </h1>
             <div class="flex items-center space-x-2">
+
+                <HoverButton @click="handleAdd">
+                    <img class="w-[24px] h-[24px]" :src="isDark ? maskDarkIcon : maskIcon" alt="" />
+                </HoverButton>
+
                 <HoverButton @click="toggleUsingContext">
-                    <span class="text-xl" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
+                    <span class="text-[24px]" :class="{ 'text-[#4b9e5f]': usingContext, 'text-[#a8071a]': !usingContext }">
                         <SvgIcon icon="ri:chat-history-line" />
                     </span>
                 </HoverButton>
 
                 <HoverButton @click="handleExport">
-                    <span class="text-xl text-[#4f555e] dark:text-white">
+                    <span class="text-[24px] text-[#4f555e] dark:text-white">
                         <SvgIcon icon="ri:download-2-line" />
                     </span>
                 </HoverButton>

+ 13 - 2
src/views/chat/layout/sider/List.vue

@@ -2,9 +2,10 @@
 import { computed } from 'vue'
 import { NInput, NPopconfirm, NScrollbar } from 'naive-ui'
 import { SvgIcon } from '@/components/common'
-import { useAppStore, useChatStore } from '@/store'
+import { useAppStore, useChatStore,useSettingStore } from '@/store'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { debounce } from '@/utils/functions/debounce'
+import { fetchGetMask } from '@/api'
 
 const { isMobile } = useBasicLayout()
 
@@ -13,7 +14,17 @@ const chatStore = useChatStore()
 
 const dataSources = computed(() => chatStore.history)
 
-async function handleSelect({ uuid }: Chat.History) {
+const settingStore = useSettingStore()
+async function handleSelect({ uuid, maskId }: Chat.History) {
+    if (maskId) {
+        fetchGetMask(maskId).then((res: any) => {
+            settingStore.updateSetting({
+                systemMessage: res.describe
+            })
+        })
+    } else {
+        settingStore.resetSetting()
+    }
     if (isActive(uuid)) return
 
     if (chatStore.active) chatStore.updateHistory(chatStore.active, { isEdit: false })

+ 3 - 1
src/views/chat/layout/sider/index.vue

@@ -7,6 +7,7 @@ import Footer from './Footer.vue'
 import { useAppStore, useChatStore } from '@/store'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { PromptStore } from '@/components/common'
+import { emitter } from '@/plugins'
 
 const appStore = useAppStore()
 const chatStore = useChatStore()
@@ -17,7 +18,8 @@ const show = ref(false)
 const collapsed = computed(() => appStore.siderCollapsed)
 
 function handleAdd() {
-    chatStore.addHistory({ title: 'New Chat', uuid: Date.now(), isEdit: false })
+    emitter.emit('changeMask', true)
+    // chatStore.addHistory({ title: 'New Chat', uuid: Date.now(), isEdit: false })
     if (isMobile.value) appStore.setSiderCollapsed(true)
 }
 

+ 106 - 0
src/views/page/MaskView.vue

@@ -0,0 +1,106 @@
+<template>
+    <div class="page h-full flex flex-col">
+        <!-- <n-page-header title="面具" @back="handleBack">
+            <template #extra>
+                <div class="w-[22px]"></div>
+            </template>
+        </n-page-header> -->
+        <n-el class="py-3 px-3 fixed top-0 left-0" @click="$router.go(-1)">
+            <n-icon size="24" class="text-gray-900 dark:text-white">
+                <ChevronLeft />
+            </n-icon>
+        </n-el>
+        <mask-pannel class="flex-1 pt-16"></mask-pannel>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { MaskPannel } from '@/components/common'
+import { NPageHeader, NIcon, NEl } from 'naive-ui'
+import { useRouter } from 'vue-router'
+import { ChevronLeft } from '@vicons/tabler'
+
+const router = useRouter()
+function handleBack() {
+    router.back()
+}
+</script>
+
+<style lang="less" scoped>
+.page {
+    color: var(--n-text-color);
+}
+
+.n-card {
+    --n-padding-left: 20px !important;
+    --n-padding-bottom: 10px !important;
+    background-color: transparent;
+}
+
+:deep(.n-page-header) {
+    height: 50px;
+    padding: 0 22px;
+    .n-page-header__main {
+        flex-grow: 1;
+        .n-page-header__title {
+            flex-grow: 1;
+            text-align: center;
+        }
+    }
+}
+.page-top {
+    .f();
+    height: 50px;
+    position: relative;
+    justify-content: center;
+
+    img {
+        width: 24px;
+        height: 24px;
+        position: absolute;
+        top: 13px;
+        left: 22px;
+    }
+
+    .title {
+        font-size: 16px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 24px;
+        text-align: center;
+    }
+}
+
+.share-btn {
+    background: var(--bg2);
+    border-radius: 8px;
+    .f();
+    img {
+        width: 45%;
+        max-width: 70px;
+        display: block;
+    }
+
+    .share-text {
+        flex-grow: 1;
+        padding: 12px 0 12px 12px;
+
+        .text1 {
+            font-size: 16px;
+            font-weight: 500;
+            line-height: 24px;
+        }
+
+        .text2 {
+            font-size: 12px;
+            color: var(--n-text-color);
+            opacity: 0.5;
+            line-height: 24px;
+        }
+    }
+}
+
+.logout {
+    padding: 0 20px 50px;
+}
+</style>