panhui 3 лет назад
Родитель
Сommit
6463f9678e

BIN
src/assets/icon_fenxiang-dark.png


BIN
src/assets/icon_fenxiang.png


BIN
src/assets/icon_xufei-dark.png


BIN
src/assets/icon_xufei.png


+ 5 - 0
src/components/common/AgentPannel.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 41 - 0
src/components/common/MomentsPannel.vue

@@ -0,0 +1,41 @@
+<template>
+    <n-list hoverable clickable>
+        <n-list-item @click="goAgent()">
+            <n-thing title="相见恨晚" content-style="margin-top: 10px;">
+                <template #description>
+                    <n-space size="small" style="margin-top: 4px">
+                        <n-tag :bordered="false" type="info" size="small"> 暑夜 </n-tag>
+                        <n-tag :bordered="false" type="info" size="small"> 晚春 </n-tag>
+                    </n-space>
+                </template>
+                奋勇呀然后休息呀<br />
+                完成你伟大的人生
+            </n-thing>
+        </n-list-item>
+        <n-list-item>
+            <n-thing title="他在时间门外" content-style="margin-top: 10px;">
+                <template #description>
+                    <n-space size="small" style="margin-top: 4px">
+                        <n-tag :bordered="false" type="info" size="small"> 环形公路 </n-tag>
+                        <n-tag :bordered="false" type="info" size="small"> 潜水艇司机 </n-tag>
+                    </n-space>
+                </template>
+                最新的打印机<br />
+                复制着彩色傀儡<br />
+                早上好我的罐头先生<br />
+                让他带你去被工厂敲击
+            </n-thing>
+        </n-list-item>
+    </n-list>
+</template>
+
+<script setup lang="ts">
+import { NList, NListItem, NThing, NSpace, NTag } from 'naive-ui'
+import { useRouter } from 'vue-router';
+
+
+
+function goAgent(){
+    
+}
+</script>

+ 41 - 3
src/components/common/VipPannel.vue

@@ -32,7 +32,7 @@
                             }"
                             class="alimamaShuHeiTi"
                         >
-                            专属权益
+                            走马AI优势
                         </n-gradient-text>
                     </template>
 
@@ -72,7 +72,10 @@
                     :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]': !!originals[item.id as keyof typeof originals] }">
+                    <div
+                        class="text-black dark:text-white text-base"
+                        :class="{ 'text-[15px]': !!originals[item.id as keyof typeof originals] }"
+                    >
                         {{ item.name }}
                     </div>
                     <div
@@ -99,6 +102,19 @@
 
         <div class="btn-list flex items-align"></div>
 
+        <div
+            class="my-5 mx-5 px-4 py-2 rounded-lg bg-[#E8F6F7] dark:bg-[#15A8AA1A]"
+            v-if="tips[chooseMemberId as keyof typeof tips] && tips[chooseMemberId as keyof typeof tips].length > 0"
+        >
+            <div
+                class="text-xs text-[#15A8AA] font-medium tips-info leading-6"
+                v-for="(item,index) in tips[chooseMemberId as keyof typeof tips]"
+                :key="index"
+            >
+                {{ item }}
+            </div>
+        </div>
+
         <div class="px-6 py-3 mt-4 btn bg-white dark:bg-[#0F1014]">
             <n-button class="alimamaShuHeiTi" type="primary" size="large" round block @click="submit" :loading="loading"
                 ><span class="text-lg mr-1">¥{{ chooseMemberInfo?.price || 0 }} </span>
@@ -213,9 +229,16 @@ const originals = ref({
     2: 177,
     3: 708
 })
+const tips = ref({
+    1: ['30天内无限量对话'],
+    2: [],
+    3: ['365天内无限量对话', '图片接口无限量', '专业客服指导使用', '更多接口服务优先体验权']
+})
 onMounted(() => {
     userMemberStore.fetchMembers().then(res => {
-        memberships.value = res
+        memberships.value = res.filter(item => {
+            return item.enabled
+        })
         let info = res.find(item => {
             return item.id === 4
         })
@@ -407,4 +430,19 @@ function goChat() {
         --n-font-size: 16px;
     }
 }
+
+.tips-info {
+    position: relative;
+    padding-left: 16px;
+    &::before {
+        content: '';
+        width: 8px;
+        height: 8px;
+        background: #15a8aa;
+        border-radius: 8px;
+        position: absolute;
+        left: 0;
+        top: 8px;
+    }
+}
 </style>

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

@@ -9,6 +9,8 @@ import PromptStore from './PromptStore.vue'
 import LoginForm from './LoginForm.vue'
 import MinePannel from './minePannel.vue'
 import MaskPannel from './MaskPannel.vue'
+import MomentsPannel from './MomentsPannel.vue'
+import AgentPannel from './AgentPannel.vue'
 import VipPannel from './VipPannel.vue'
 import BalancePannel from './BalancePannel.vue'
 import CommissionPannel from './CommissionPannel.vue'
@@ -33,5 +35,7 @@ export {
     CommissionPannel,
     VipModal,
     RuleContent,
-    OfficalAccount
+    OfficalAccount,
+    MomentsPannel,
+    AgentPannel
 }

+ 10 - 1
src/router/index.ts

@@ -97,7 +97,16 @@ const routes: RouteRecordRaw[] = [
         name: 'commission',
         component: () => import('@/views/page/CommissionView.vue')
     },
-
+    {
+        path: '/moments',
+        name: 'moments',
+        component: () => import('@/views/page/MomentsView.vue')
+    },
+    {
+        path: '/agent',
+        name: 'agent',
+        component: () => import('@/views/page/AgentView.vue')
+    },
     {
         path: '/404',
         name: '404',

+ 6 - 0
src/store/modules/chat/index.ts

@@ -41,6 +41,12 @@ export const useChatStore = defineStore('chat-store', {
             }
         },
 
+        getHistoryByUuid(uuid: number) {
+            return this.history.find(item => {
+                return item.uuid === uuid
+            })
+        },
+
         async deleteHistory(index: number) {
             this.history.splice(index, 1)
             this.chat.splice(index, 1)

+ 1 - 0
src/store/modules/memberShip/helper.ts

@@ -8,6 +8,7 @@ export interface MemberShip {
     id: number
     name: String
     price: number
+    enabled?: boolean
 }
 
 export interface UserMember {

+ 22 - 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, MaskPannel } from '@/components/common'
+import { HoverButton, SvgIcon, MinePannel, VipPannel, MaskPannel, Share } from '@/components/common'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { useChatStore, useAppStore, usePromptStore, useAuthStore, useUserMemberStore } from '@/store'
 import { fetchChatAPIProcess } from '@/api'
@@ -20,6 +20,7 @@ import { useTheme } from '@/hooks/useTheme'
 import { emitter } from '@/plugins'
 import maskIcon from '@/assets/png-mianju.png'
 import maskDarkIcon from '@/assets/png-mianju-dark.png'
+import { fetchGetMask } from '@/api'
 
 let controller = new AbortController()
 
@@ -61,6 +62,17 @@ dataSources.value.forEach((item, index) => {
     if (item.loading) updateChatSome(+uuid, index, { loading: false })
 })
 
+const iconId = ref(0)
+const histroyData = computed(() => chatStore.getHistoryByUuid(+uuid))
+const maskId = computed(() => {
+    return histroyData.value?.maskId
+})
+if (histroyData.value?.maskId) {
+    fetchGetMask(histroyData.value?.maskId).then((res: any) => {
+        iconId.value = res.iconId
+    })
+}
+
 const userMemberStore = useUserMemberStore()
 function handleSubmit() {
     if (!userMemberStore.isVip()) {
@@ -472,6 +484,9 @@ onMounted(() => {
             showMask.value = true
         }
     })
+    emitter.on('changeShare', res => {
+        showShareModal.value = true
+    })
 })
 const showMask = ref(false)
 
@@ -488,6 +503,8 @@ function handleAdd() {
         showMask.value = true
     }
 }
+
+const showShareModal = ref(false)
 </script>
 
 <template>
@@ -522,6 +539,8 @@ function handleAdd() {
                                 :inversion="item.inversion"
                                 :error="item.error"
                                 :loading="item.loading"
+                                :iconId="iconId"
+                                :maskId="maskId"
                                 @regenerate="onRegenerate(index)"
                                 @delete="handleDelete(index)"
                             />
@@ -632,6 +651,8 @@ function handleAdd() {
                 <img src="@/assets/png-tanchuang-huiyuan.png" @click="goVip" class="w-[80%] max-w-sm" alt="" />
             </n-modal>
         </NConfigProvider>
+
+        <share v-model:show="showShareModal" />
     </div>
 </template>
 

+ 47 - 3
src/views/chat/components/Message/Avatar.vue

@@ -1,13 +1,50 @@
 <script lang="ts" setup>
 import { computed } from 'vue'
 import { NAvatar, useOsTheme } from 'naive-ui'
-import { useUserStore, useAppStore } from '@/store'
+import { useUserStore, useAppStore, useChatStore } from '@/store'
 import { isString } from '@/utils/is'
 import defaultAvatar from '@/assets/avatar.png'
 import { useTheme } from '@/hooks/useTheme'
+import { useRoute, useRouter } from 'vue-router'
+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'
+
+const icons = [
+    {
+        light: icon1,
+        dark: icon1Dark
+    },
+    {
+        light: icon2,
+        dark: icon2Dark
+    },
+    {
+        light: icon3,
+        dark: icon3Dark
+    },
+    {
+        light: icon4,
+        dark: icon4Dark
+    }
+]
+
+const route = useRoute()
+const { uuid } = route.params as { uuid: string }
+const chatStore = useChatStore()
+const histroyData = computed(() => chatStore.getHistoryByUuid(+uuid))
+
+console.log()
 
 interface Props {
     image?: boolean
+    iconId?: number
+    maskId?: number | null
 }
 defineProps<Props>()
 
@@ -31,7 +68,14 @@ const { isDark } = useTheme()
         <NAvatar :size="32" v-else :src="defaultAvatar" :style="{ backgroundColor: 'transparent' }" />
     </template>
     <span v-else class="text-[28px] dark:text-white">
-        <img src="@/assets/logo.png" v-if="isDark" alt="" />
-        <img src="@/assets/logo1.png" v-else alt="" />
+        <template v-if="maskId">
+            <template v-if="iconId">
+                <img :src="isDark ? icons[iconId - 1].dark : icons[iconId - 1].light" alt="" />
+            </template>
+        </template>
+        <template v-else>
+            <img src="@/assets/logo.png" v-if="isDark" alt="" />
+            <img src="@/assets/logo1.png" v-else alt="" />
+        </template>
     </span>
 </template>

+ 3 - 1
src/views/chat/components/Message/index.vue

@@ -15,6 +15,8 @@ interface Props {
     inversion?: boolean
     error?: boolean
     loading?: boolean
+    iconId?: number
+    maskId?: number | null
 }
 
 interface Emit {
@@ -83,7 +85,7 @@ function handleRegenerate() {
 <template>
     <div ref="messageRef" class="flex w-full mb-6 overflow-hidden" :class="[{ 'flex-row-reverse': inversion }]">
         <div class="flex items-center justify-center flex-shrink-0 h-8 basis-8" :class="[inversion ? 'ml-2' : 'mr-2']">
-            <AvatarComponent :image="inversion" />
+            <AvatarComponent :image="inversion" :iconId="iconId" :maskId="maskId"/>
         </div>
         <div class="overflow-hidden text-sm" :class="[inversion ? 'items-end' : 'items-start']">
             <p class="text-xs text-[#b4bbc4]" :class="[inversion ? 'text-right' : 'text-left']">

+ 63 - 14
src/views/chat/layout/sider/Footer.vue

@@ -1,14 +1,20 @@
 <script setup lang="ts">
-import { defineAsyncComponent, ref } from 'vue'
+import { defineAsyncComponent, ref, computed } from 'vue'
 import { HoverButton, SvgIcon, UserAvatar } from '@/components/common'
-import { NButton } from 'naive-ui'
+import { NButton, NIcon } from 'naive-ui'
 import { useRouter } from 'vue-router'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
-import { useAppStore, useUserStore } from '@/store'
+import { useAppStore, useUserStore, useUserMemberStore } from '@/store'
 import { emitter } from '@/plugins'
 import { storeToRefs } from 'pinia'
 import Setting from '@/components/common/Setting/SettingIndex.vue'
 import { inject } from 'vue'
+import { ChevronRight } from '@vicons/tabler'
+import { useTheme } from '@/hooks/useTheme'
+import vipImg from '@/assets/icon_xufei.png'
+import shareImg from '@/assets/icon_fenxiang.png'
+import vipDarkImg from '@/assets/icon_xufei-dark.png'
+import shareDarkImg from '@/assets/icon_fenxiang-dark.png'
 
 const show = ref(false)
 
@@ -30,22 +36,65 @@ function goMine() {
         emitter.emit('changeMineShow', true)
     }
 }
+
+function share() {
+    emitter.emit('changeShare', true)
+}
+
+const userMemberStore = useUserMemberStore()
+const isVip = computed(() => {
+    return userMemberStore.isVip()
+})
+
+function goVip() {
+    emitter.emit('changeVipShow', true)
+}
+
+const { isDark } = useTheme()
 </script>
 
 <template>
-    <footer class="flex items-center justify-between min-w-0 p-4 overflow-hidden border-t dark:border-neutral-800">
-        <div class="flex-1 flex-shrink-0 overflow-hidden">
-            <n-button text @click="goMine">
-                <UserAvatar />
-            </n-button>
+    <footer class="min-w-0 p-4 overflow-hidden border-t dark:border-neutral-800">
+        <div class="flex items-center justify-between cursor-pointer pb-3" @click="goMine">
+            <span class="text-[#000] text-sm dark:text-[#fff] font-medium">个人主页</span>
+            <div class="flex items-center">
+                <span class="text-[#939599] text-xs mr-1">查看</span>
+                <n-icon color="#939599">
+                    <ChevronRight />
+                </n-icon>
+            </div>
         </div>
+        <div class="flex items-center justify-between">
+            <div class="flex-1 flex-shrink-0 overflow-hidden">
+                <n-button text @click="goMine">
+                    <UserAvatar />
+                </n-button>
+            </div>
+
+            <HoverButton @click="show = true">
+                <span class="text-xl text-[#4f555e] dark:text-white">
+                    <SvgIcon icon="ri:settings-4-line" />
+                </span>
+            </HoverButton>
 
-        <HoverButton @click="show = true">
-            <span class="text-xl text-[#4f555e] dark:text-white">
-                <SvgIcon icon="ri:settings-4-line" />
-            </span>
-        </HoverButton>
+            <Setting v-model:visible="show" />
+        </div>
 
-        <Setting v-model:visible="show" />
+        <div @click="goVip" class="bg-[#F5F7FA] dark:bg-[#18191E] px-[10px] mt-3 h-[36px] flex cursor-pointer items-center rounded-lg">
+            <img :src="isDark ? vipDarkImg : vipImg" class="w-[18px] h-[18px] block" alt="" />
+            <span class="text-xs ml-[8px] dark:#fff">{{ isVip ? '会员续费' : '开通会员' }}</span>
+            <div class="flex-1"></div>
+            <n-icon color="#939599">
+                <ChevronRight />
+            </n-icon>
+        </div>
+        <div @click="share" class="bg-[#F5F7FA] dark:bg-[#18191E] px-[10px] mt-3 h-[36px] cursor-pointer flex items-center rounded-lg">
+            <img :src="isDark ? shareDarkImg : shareImg" class="w-[18px] h-[18px] block" alt="" />
+            <span class="text-xs ml-[8px] dark:#fff">分享好友</span>
+            <div class="flex-1"></div>
+            <n-icon color="#939599">
+                <ChevronRight />
+            </n-icon>
+        </div>
     </footer>
 </template>

+ 39 - 0
src/views/page/AgentView.vue

@@ -0,0 +1,39 @@
+<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>
+        <agent-pannel></agent-pannel>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { NPageHeader } from 'naive-ui'
+import { useRouter } from 'vue-router'
+import { AgentPannel } from '@/components/common'
+
+const router = useRouter()
+function handleBack() {
+    router.back()
+}
+</script>
+
+<style lang="less" scoped>
+.page {
+    color: var(--n-text-color);
+}
+
+: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;
+        }
+    }
+}
+</style>

+ 40 - 0
src/views/page/MomentsView.vue

@@ -0,0 +1,40 @@
+<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>
+        <moments-pannel></moments-pannel>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { NPageHeader } from 'naive-ui'
+import { useRouter } from 'vue-router'
+import { MomentsPannel } from '@/components/common'
+
+
+const router = useRouter()
+function handleBack() {
+    router.back()
+}
+</script>
+
+<style lang="less" scoped>
+.page {
+    color: var(--n-text-color);
+}
+
+: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;
+        }
+    }
+}
+</style>