panhui 2 yıl önce
ebeveyn
işleme
29c5687e96

+ 28 - 7
src/api/index.ts

@@ -34,14 +34,16 @@ 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
-        }
+    console.log(authStore.isChatGPTAPI)
+
+    // 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 +161,22 @@ export function fetchCommissionRecords<T>() {
         url: '/commission/records/get'
     })
 }
+
+export function fetchSystemMessage<T>() {
+    return get<T>({
+        url: '/sys-config/system_message'
+    })
+}
+
+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/start.png


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

@@ -0,0 +1,157 @@
+<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 type="text" @click="refreash()" size="large" class="flex-1 !bg-white !border-0 dark:!bg-[#20223C]" round>
+                <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%, #e0f3ff 100%);
+    box-shadow: 0px 2px 6px 0px rgba(144, 194, 201, 0.5);
+    border-radius: 8px;
+
+    &.maskDark {
+        background: #0a0b21;
+        border: 1px solid #15a8aa;
+        box-shadow: none;
+    }
+}
+
+.n-button + .n-button {
+    margin-left: 26px;
+}
+</style>

+ 11 - 6
src/components/common/VipPannel.vue

@@ -69,20 +69,20 @@
             >
                 <div
                     class="choose-btn flex flex-shrink-0 flex-col justify-center items-center text-center h-[86px] border border-[#9EA4B0] dark:border-white rounded-[16px]"
-                    :class="{ prim: chooseMemberId === item.id, recommend: item.id === 4 }"
+                    :class="{ prim: chooseMemberId === item.id, recommend: item.id === 111 }"
                     @click="chooseMemberId = item.id"
                 >
-                    <div class="text-black dark:text-white text-base" :class="{ 'text-[15px]': item.id === 4 }">
+                    <div class="text-black dark:text-white text-base" :class="{ 'text-[15px]': !!originals[item.id as keyof typeof originals] }">
                         {{ item.name }}
                     </div>
                     <div
                         class="text-3xl font-medium mt-[-1px]"
-                        :class="{ 'text-[25px] leading-[28px] mt-[-3px]': item.id === 4 }"
+                        :class="{ 'text-[25px] leading-[28px] mt-[-3px]': !!originals[item.id as keyof typeof originals]}"
                     >
                         <span class="text-base">¥</span>{{ item.price }}
                     </div>
-                    <div class="text-[#A2A49D] text-xs" v-if="item.id === 4">
-                        原价 <span class="line-through">1299</span>
+                    <div class="text-[#A2A49D] text-xs" v-if="!!originals[item.id as keyof typeof originals]">
+                        原价 <span class="line-through">{{ originals[item.id as keyof typeof originals] }}</span>
                     </div>
                     <!-- <template v-if="chooseMemberId == item.id">
                         <img :src="chooseRe" v-if="item.id === 4" alt="" class="choose-img" />
@@ -207,7 +207,12 @@ const chooseMemberInfo = computed(() => {
 })
 
 const userMemberStore = useUserMemberStore()
-const memberships = ref<Array<MemberShip>>([])
+const memberships = ref<Array<any>>([])
+const originals = ref({
+    1: 49.9,
+    2: 139,
+    3: 388
+})
 onMounted(() => {
     userMemberStore.fetchMembers().then(res => {
         memberships.value = res

+ 2 - 0
src/components/common/index.ts

@@ -8,6 +8,7 @@ import Setting from './Setting/SettingIndex.vue'
 import PromptStore from './PromptStore.vue'
 import LoginForm from './LoginForm.vue'
 import MinePannel from './minePannel.vue'
+import MaskPannel from './MaskPannel.vue'
 import VipPannel from './VipPannel.vue'
 import BalancePannel from './BalancePannel.vue'
 import CommissionPannel from './CommissionPannel.vue'
@@ -26,6 +27,7 @@ export {
     Share,
     LoginForm,
     MinePannel,
+    MaskPannel,
     VipPannel,
     BalancePannel,
     CommissionPannel,

+ 5 - 0
src/router/index.ts

@@ -77,6 +77,11 @@ const routes: RouteRecordRaw[] = [
         name: 'mine',
         component: () => import('@/views/page/MineView.vue')
     },
+    {
+        path: '/mask',
+        name: 'mask',
+        component: () => import('@/views/page/MaskView.vue')
+    },
     {
         path: '/rule',
         name: 'rule',

+ 1 - 1
src/store/modules/chat/helper.ts

@@ -7,7 +7,7 @@ export function defaultState(): Chat.ChatState {
     return {
         active: uuid,
         usingContext: true,
-        history: [{ uuid, title: 'New Chat', isEdit: false }],
+        history: [{ uuid, title: 'New Chat', isEdit: false, maskId: null }],
         chat: [{ uuid, data: [] }]
     }
 }

+ 1 - 1
src/store/modules/chat/index.ts

@@ -92,7 +92,7 @@ export const useChatStore = defineStore('chat-store', {
             if (!uuid || uuid === 0) {
                 if (this.history.length === 0) {
                     const uuid = Date.now()
-                    this.history.push({ uuid, title: chat.text, isEdit: false })
+                    this.history.push({ uuid, title: chat.text, isEdit: false, maskId: null })
                     this.chat.push({ uuid, data: [chat] })
                     this.active = uuid
                     this.recordState()

+ 9 - 2
src/store/modules/settings/helper.ts

@@ -1,6 +1,8 @@
 import { ss } from '@/utils/storage'
+import { fetchSystemMessage } from '@/api'
 
 const LOCAL_NAME = 'settingsStorage'
+let defalutSystem = ''
 
 export interface SettingsState {
     systemMessage: string
@@ -10,8 +12,7 @@ export interface SettingsState {
 
 export function defaultSetting(): SettingsState {
     return {
-        systemMessage:
-            "You are ChatGPT, a large language model trained by OpenAI. Follow the user's instructions carefully. Respond using markdown.",
+        systemMessage: defalutSystem,
         temperature: 0.8,
         top_p: 1
     }
@@ -29,3 +30,9 @@ export function setLocalState(setting: SettingsState): void {
 export function removeLocalState() {
     ss.remove(LOCAL_NAME)
 }
+
+export function getSystem() {
+    fetchSystemMessage().then((res: any) => {
+        defalutSystem = res.value
+    })
+}

+ 3 - 1
src/store/modules/settings/index.ts

@@ -1,6 +1,8 @@
 import { defineStore } from 'pinia'
 import type { SettingsState } from './helper'
-import { defaultSetting, getLocalState, removeLocalState, setLocalState } from './helper'
+import { defaultSetting, getLocalState, removeLocalState, setLocalState, getSystem } from './helper'
+
+getSystem()
 
 export const useSettingStore = defineStore('setting-store', {
     state: (): SettingsState => getLocalState(),

+ 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 {

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

@@ -11,7 +11,7 @@ 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'
@@ -463,7 +463,15 @@ 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)
@@ -575,6 +583,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"

+ 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 })

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

@@ -7,6 +7,8 @@ import Footer from './Footer.vue'
 import { useAppStore, useChatStore } from '@/store'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { PromptStore } from '@/components/common'
+import { emit } from 'process'
+import { emitter } from '@/plugins'
 
 const appStore = useAppStore()
 const chatStore = useChatStore()
@@ -17,7 +19,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, maskId: null })
     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>