首页调整

dev
haoyuntao 7 months ago
parent 297b2ae453
commit 3e63234a7c
  1. 3
      src/components/avatar-upload/avatar-upload.vue
  2. 2
      src/manifest.json
  3. 1
      src/packages/pages/ai_creation/ai_creation.vue
  4. 177
      src/packages/pages/ai_talk/ai_talk.vue
  5. 55
      src/packages/pages/ai_talk/components/follow-official.vue
  6. 168
      src/packages/pages/ai_talk/components/ios-privacy-popup.vue
  7. 158
      src/packages/pages/ai_talk/components/mp-privacy-popup.vue
  8. 89
      src/packages/pages/ai_talk/components/problem-example-popup.vue
  9. 76
      src/packages/pages/ai_talk/components/problem-example.vue
  10. 102
      src/packages/pages/ai_talk/components/session-item.vue
  11. 90
      src/packages/pages/ai_talk/components/session-popup.vue
  12. 31
      src/packages/pages/ai_talk/components/session.vue
  13. 81
      src/packages/pages/ai_talk/components/useSessionList.ts
  14. 47
      src/pages.json
  15. 3
      src/pages/app/app.vue
  16. 339
      src/pages/index/index.vue
  17. 176
      src/pages/index/index1.vue
  18. 18
      src/pages/login/components/update-user-info.vue
  19. 1
      src/pages/login/login.vue
  20. BIN
      src/static/images/user/banner.png
  21. 2
      src/uni_modules/vk-uview-ui/components/u-image/u-image.vue

@ -72,6 +72,7 @@ const styles = computed<CSSProperties>(() => {
})
const chooseAvatar = async (e: any) => {
console.log(props.modelValue)
// #ifdef APP-PLUS
if (client == 6) {
// const res = await uni.showModal({
@ -89,11 +90,13 @@ const chooseAvatar = async (e: any) => {
// #endif
// #ifndef MP-WEIXIN
console.log(props)
router.navigateTo({
path: '/uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper?destWidth=300&rectWidth=200&fileType=jpg'
})
// #endif
// #ifdef MP-WEIXIN
console.log(props)
const path = e.detail?.avatarUrl
if (path) {
uploadImageIng(path)

@ -139,7 +139,7 @@
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wxba391e34eddf2cc7",
"appid" : "wx15c8046399298d65",
"optimization" : {
"subPackages" : true
},

@ -7,6 +7,7 @@
/>
<!-- #endif -->
</page-meta>
<view class="ai-creation">
<view class="flex-1 min-h-0">
<scroll-view scroll-y class="h-full">

@ -0,0 +1,177 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="h-full flex flex-col">
<view class="flex-1 min-h-0 bg-white">
<chat-scroll-view
v-model="chatList"
ref="chatRef"
:type="1"
:otherId="sessionActive"
:showAdd="true"
:safeAreaInsetBottom="false"
:avatar="appStore.getChatConfig.chat_logo"
bottom="100rpx"
>
<template #top>
<follow-official
:show="!!appStore.config.is_follow_official"
:title="appStore.getLoginConfig.involved_text"
/>
<session v-model="showPopup" />
</template>
<template #empty>
<view class="w-full">
<div
class="my-[60rpx] text-center text-[50rpx] font-medium"
>
{{ appStore.getChatConfig.chat_title }}
</div>
<problem-example
v-if="problem.length"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
@show-more="showExamplePopup = true"
/>
<view
v-if="indexData?.tips?.show"
class="bg-page flex flex-col items-center p-[30rpx] mt-[20rpx] m-[40rpx]"
>
<view class="flex items-center">
<u-icon name="warning" :size="40" />
<view class="text-lg ml-[10rpx] break-all">{{
indexData?.tips?.title
}}</view>
</view>
<view
class="text-content text-sm mt-[20rpx] break-all"
>
{{ indexData?.tips?.sub_title }}
</view>
</view>
</view>
</template>
</chat-scroll-view>
<!-- 会话弹窗 -->
<session-popup v-model="showPopup" />
<!-- 会话弹窗 -->
<problem-example-popup
v-model="showExamplePopup"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
/>
<!-- 公告弹窗 -->
<notice-popup></notice-popup>
<!-- #ifdef MP -->
<!-- 微信小程序隐私弹窗 -->
<MpPrivacyPopup></MpPrivacyPopup>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<!-- 苹果App隐私弹窗 -->
<IosPrivacyPopup
v-if="getClient() == ClientEnum.IOS"
@refresh="refreshHandler"
></IosPrivacyPopup>
<!-- #endif -->
</view>
<!-- <canvas canvas-id="canvasId" id="canvasId"></canvas> -->
<tabbar />
</view>
</template>
<script setup lang="ts">
import { onHide, onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import { reactive, ref, watch } from 'vue'
import { useAppStore } from '@/stores/app'
import { getDecorate } from '@/api/shop'
import { getSamplesLists } from '@/api/chat'
import SessionPopup from './components/session-popup.vue'
import FollowOfficial from './components/follow-official.vue'
import NoticePopup from '@/components/notice-popup/notice-popup.vue'
import ProblemExample from './components/problem-example.vue'
import Session from './components/session.vue'
import ProblemExamplePopup from './components/problem-example-popup.vue'
// #ifdef MP
import MpPrivacyPopup from './components/mp-privacy-popup.vue'
// #endif
// #ifdef APP-PLUS
import { getClient } from '@/utils/client'
import { ClientEnum } from '@/enums/appEnums'
import IosPrivacyPopup from './components/ios-privacy-popup.vue'
// #endif
import { shallowRef } from 'vue'
import { useSessionList } from './components/useSessionList'
import agreement from '@/components/agreement/agreement.vue'
const { getSessionLists, sessionActive } = useSessionList()
const showPopup = ref(false)
const showExamplePopup = ref(false)
const problem = ref([])
//
const chatList = ref<any[]>([])
const chatRef = shallowRef()
//
const indexData = reactive({
tips: {
show: 0,
title: '',
sub_title: ''
}
})
//
const posterRef = shallowRef()
const modelKey = ref('')
const getProblemExample = async () => {
problem.value = await getSamplesLists()
}
const getDecorateFunc = async () => {
try {
const { data } = await getDecorate({ id: 8 })
indexData.tips = JSON.parse(data)[1]?.content
} catch (error) {
console.log('获取装修数据失败=>', error)
}
}
const appStore = useAppStore()
const showChatView = ref(true)
const refreshHandler = async () => {
await appStore.getConfig()
await getDecorateFunc()
await getSessionLists()
await getProblemExample()
}
// onHide(() => {
// showChatView.value = false
// })
onShow(async () => {
getDecorateFunc()
getSessionLists()
getProblemExample()
})
onPullDownRefresh(async () => {
refreshHandler()
uni.stopPullDownRefresh()
})
</script>
<style>
page {
height: 100%;
overflow: hidden;
}
</style>

@ -0,0 +1,55 @@
<template>
<view
class="bg-primary flex px-[20rpx] items-center py-[16rpx]"
v-if="show && isShow"
>
<view class="flex-1 line-clamp-1 min-w-0 text-btn-text">
{{ title }}
</view>
<router-navigate to="/packages/pages/follow_official/follow_official">
<u-button
class="flex-none"
:plain="true"
type="primary"
size="medium"
shape="circle"
hover-class="none"
:custom-style="{
height: '60rpx'
}"
>
前往关注
</u-button>
</router-navigate>
<view class="text-btn-text ml-[10rpx]" @click.stop="close">
<u-icon name="close" />
</view>
</view>
</template>
<script setup lang="ts">
import { IS_CLOSE_FOLLOW_OA } from '@/enums/constantEnums'
import cache from '@/utils/cache'
import { onBeforeMount } from 'vue'
import { ref } from 'vue'
const props = withDefaults(
defineProps<{
title?: string
show?: boolean
}>(),
{
title: '👉🏻关注公众号,下次访问不迷路',
show: false
}
)
const isShow = ref(false)
const close = () => {
cache.set(IS_CLOSE_FOLLOW_OA, true, 24 * 60 * 60)
isShow.value = false
}
onBeforeMount(() => {
isShow.value = !cache.get(IS_CLOSE_FOLLOW_OA)
})
</script>

@ -0,0 +1,168 @@
<template>
<!-- modal:隐私授权弹窗-->
<view v-if="show" class="modal-box" @tap.stop @touchmove.stop.prevent>
<view class="modal-mask"></view>
<view class="modal-dialog" @tap.stop>
<view class="title">服务协议及隐私政策</view>
<view class="content">
为了更好的保障您的合法权益请点击
<text
class="text-[#101010]"
hover-class="hover"
@click="
openAgreement(
'/packages/pages/agreement/agreement?type=service'
)
"
>
用户协议
</text>
<text
class="text-[#101010]"
hover-class="hover"
@click="
openAgreement(
'/packages/pages/agreement/agreement?type=privacy'
)
"
>
隐私政策
</text>
并仔细阅读如您同意全部内容请点击同意开始使用我们的服务
</view>
<view class="btn-box">
<button
class="btn disagree"
hover-class="hover"
@click="disagreePrivacy"
>
不同意
</button>
<button
class="btn bg-primary text-white"
hover-class="hover"
@click="agreePrivacy"
>
同意并继续
</button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { nextTick, ref } from 'vue'
import cache from '@/utils/cache'
import { HAS_READ_PRIVACY } from '@/enums/constantEnums'
const emit = defineEmits<{
(event: 'refresh'): void
}>()
const show = ref<boolean>(false)
//
const openAgreement = (url: string) => {
uni.navigateTo({ url })
}
// 退App
const disagreePrivacy = () => {
uni.$u.toast('同意隐私政策后继续使用')
}
//
const agreePrivacy = async () => {
emit('refresh')
await nextTick()
show.value = false
cache.set(HAS_READ_PRIVACY, true)
}
if (!cache.get(HAS_READ_PRIVACY)) show.value = true
</script>
<style scoped>
.modal-box {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100vh;
width: 100vw;
z-index: 9999;
background-color: #ffffff;
}
.modal-box .modal-mask {
position: absolute;
z-index: 9999;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.modal-box .modal-dialog {
box-sizing: border-box;
position: absolute;
z-index: 99999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
padding: 40rpx 20rpx;
background: #ffffff;
border-radius: 20rpx;
}
.modal-box .title {
text-align: center;
color: #333;
font-weight: bold;
font-size: 34rpx;
}
.modal-box .content {
display: block;
font-size: 28rpx;
color: #666;
margin-top: 20rpx;
text-align: justify;
line-height: 1.6;
padding: 10rpx 20rpx;
}
.modal-box .btn-box {
margin-top: 30rpx;
padding: 0 30rpx;
padding-bottom: 10rpx;
display: flex;
text-align: center;
}
.modal-box .btn::after {
border: none;
display: none;
}
.modal-box .btn-box .btn {
width: 50%;
height: 76rpx;
line-height: 76rpx;
margin: 0 10rpx;
padding: 0;
align-items: center;
justify-content: center;
border-radius: 60px;
font-size: 28rpx;
font-weight: 500;
}
.modal-box .disagree {
color: #0f0f0f;
background: #f5f5f5;
}
</style>

@ -0,0 +1,158 @@
<template>
<!-- modal:隐私授权弹窗-->
<view v-if="show" class="modal-box" @tap.stop>
<view class="dialog" @tap.stop>
<view class="title">隐私政策提示</view>
<view class="content">
欢迎使用{{
appStore.getChatConfig.chat_title
}}小程序请您在使用前点击
<text
class="text-[#243245]"
hover-class="hover"
@click="openContract"
>
{{ name }}
</text>
并仔细阅读如您同意全部内容请点击同意开始使用我们的服务
</view>
<view class="btn-box">
<button
class="btn disagree"
hover-class="hover"
@click="disagreePrivacy"
>
不同意
</button>
<button
class="btn bg-primary text-white"
hover-class="hover"
id="agree-btn"
open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="agreePrivacy"
>
同意
</button>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useAppStore } from '@/stores/app'
const appStore = useAppStore()
const name = ref<string>('')
const show = ref<boolean>(false)
interface PrivacyRes {
errMsg: string
privacyContractName: string
needAuthorization: boolean
}
if (wx.getPrivacySetting) {
wx.getPrivacySetting({
success(res: PrivacyRes) {
console.log(res)
name.value = res.privacyContractName
show.value = res.needAuthorization
}
})
}
const openContract = () => {
wx.openPrivacyContract({
success: () => {},
fail: () => {}
})
}
const disagreeHandle = () => {
//
show.value = false
}
const disagreePrivacy = () => {
uni.$u.toast('同意隐私政策后可继续使用')
// wx.exitMiniProgram()
}
const agreePrivacy = () => {
show.value = false
}
</script>
<style scoped>
.modal-box {
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 99999;
}
.modal-box .dialog {
box-sizing: border-box;
position: absolute;
bottom: 0;
width: 100%;
padding: 40rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #ffffff;
border-radius: 20rpx 20rpx 0 0;
}
.modal-box .title {
text-align: center;
color: #333;
font-weight: bold;
font-size: 34rpx;
}
.modal-box .content {
display: block;
font-size: 28rpx;
color: #666;
margin-top: 20rpx;
text-align: justify;
line-height: 1.6;
padding: 10rpx 20rpx;
}
.modal-box .btn-box {
margin-top: 50rpx;
padding: 0 30rpx;
padding-bottom: 30rpx;
display: flex;
text-align: center;
}
.modal-box .btn::after {
border: none;
display: none;
}
.modal-box .btn-box .btn {
width: 50%;
height: 76rpx;
line-height: 76rpx;
margin: 0 10rpx;
padding: 0;
align-items: center;
justify-content: center;
border-radius: 60px;
font-size: 28rpx;
font-weight: 500;
}
.modal-box .disagree {
color: #0f0f0f;
background: #f5f5f5;
}
</style>

@ -0,0 +1,89 @@
<template>
<u-popup
v-model="show"
height="1000rpx"
mode="bottom"
safe-area-inset-bottom
border-radius="14"
closeable
>
<view class="py-[30rpx] h-full flex flex-col">
<view class="text-2xl font-medium px-[30rpx]">问题示例</view>
<view>
<scroll-view :scroll-x="true" class="whitespace-nowrap">
<view class="inline-block py-[20rpx]">
<view class="flex px-[15rpx]">
<view
class="mx-[15rpx] leading-[72rpx] px-[40rpx] bg-primary-light-9 text-primary rounded-[8rpx]"
:class="{
'!text-btn-text !bg-primary':
currentTab == index
}"
v-for="(item, index) in data"
:key="item.id"
@click="currentTab = index"
>
<view>{{ item.name }}</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view
class="border-0 border-t border-light border-solid flex-1 min-h-0"
>
<scroll-view class="h-full" :scroll-y="true">
<view class="px-[30rpx] py-[20rpx]">
<template v-if="currentSample.length">
<view
v-for="item in currentSample"
:key="item.id"
class="py-[10rpx]"
>
<view
class="text-center px-[20rpx] bg-page rounded py-[20rpx]"
@click="clickItem(item.content)"
>
{{ item.content }}
</view>
</view>
</template>
<template v-else>
<view class="py-[150rpx]">
<u-empty text="暂无数据" mode="data"></u-empty>
</view>
</template>
</view>
</scroll-view>
</view>
</view>
</u-popup>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
const props = defineProps<{
data: any[]
modelValue: boolean
}>()
const emit = defineEmits<{
(event: 'update:modelValue', value: boolean): void
(event: 'click-item', value: string): void
}>()
const show = computed({
get: () => {
return props.modelValue
},
set: (value) => {
emit('update:modelValue', value)
}
})
const currentTab = ref(0)
const currentSample = computed(() => props.data[currentTab.value]?.sample || [])
const clickItem = (value: string) => {
show.value = false
emit('click-item', value)
}
</script>

@ -0,0 +1,76 @@
<template>
<view class="problem-example px-[10rpx]">
<view class="flex">
<view
v-for="item in sliceData"
:key="item.id"
class="flex-1 mx-[10rpx]"
>
<view
class="flex flex-col justify-center items-center mb-[20rpx]"
>
<image
v-if="item.image"
class="w-[88rpx] h-[88rpx]"
:src="item.image"
alt=""
/>
<view
class="text-[30rpx] font-medium mt-[32rpx] line-clamp-1"
>
{{ item.name }}
</view>
</view>
<view>
<view
v-for="sample in slice3InData(item.sample)"
:key="sample.id"
class="bg-page mb-[20rpx] px-[20rpx] py-[15rpx] flex justify-center rounded-[12rpx] cursor-pointer"
@click="clickItem(sample.content)"
>
<view class="line-clamp-2 text-sm text-center">
{{ sample.content }}
</view>
</view>
</view>
</view>
</view>
<view class="py-[10rpx]" @click="emit('show-more')" v-if="isShowMore">
<view class="text-sm text-muted flex items-center justify-center">
查看更多
<u-icon name="arrow-right" size="26" />
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
data: any[]
}>()
const emit = defineEmits<{
(event: 'click-item', value: string): void
(event: 'show-more'): void
}>()
const num = 3
const slice3InData = (data: any[]) => {
return data.slice(0, num)
}
const sliceData = computed(() => {
return slice3InData(props.data)
})
const isShowMore = computed(() => {
if (props.data?.length > num) {
return true
}
if (props.data?.some((item) => item.sample.length > num)) {
return true
}
return false
})
const clickItem = (value: string) => {
emit('click-item', value)
}
</script>

@ -0,0 +1,102 @@
<template>
<view
class="px-[20rpx] h-[80rpx] flex items-center rounded-[8rpx] mb-[20rpx] cursor-pointer"
:class="{
' bg-page': isActive
}"
@click="activeId = itemId"
>
<u-icon name="chat" />
<view class="ml-[20rpx] flex-1 min-w-0">
<u-input
height="50"
v-if="isEdit"
:custom-style="{
fontSize: '26rpx'
}"
v-model="nameInput"
border
/>
<view v-else class="line-clamp-1">{{ name }}</view>
</view>
<template v-if="isActive">
<template v-if="isEdit">
<view
class="cursor-pointer mx-[12rpx] flex h-full"
@click="handleEdit"
>
<u-icon name="checkbox-mark" />
</view>
<view
class="cursor-pointer flex h-full"
@click="isEdit = false"
>
<u-icon name="close" />
</view>
</template>
<template v-else>
<view
class="cursor-pointer mr-[12rpx] flex h-full"
@click="isEdit = true"
>
<u-icon name="edit-pen" />
</view>
<view
class="cursor-pointer flex h-full"
@click="emit('delete', itemId)"
>
<u-icon name="trash" />
</view>
</template>
</template>
</view>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
const props = withDefaults(
defineProps<{
modelValue: number | string
name: string
itemId: number | string
}>(),
{}
)
const emit = defineEmits(['update:modelValue', 'edit', 'delete'])
const nameInput = ref('')
const isEdit = ref(false)
const activeId = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
const isActive = computed(() => activeId.value === props.itemId)
const handleEdit = () => {
isEdit.value = false
emit('edit', props.itemId, nameInput.value)
}
watch(
() => props.modelValue,
() => {
isEdit.value = false
}
)
watch(
() => props.name,
(value) => {
nameInput.value = value
},
{
immediate: true
}
)
</script>

@ -0,0 +1,90 @@
<template>
<u-popup v-model="show" mode="left" width="480rpx" safe-area-inset-bottom>
<view class="flex flex-col h-full relative z-[9999]">
<view class="px-[20rpx] py-[20rpx]">
<u-button
type="primary"
:custom-style="{ width: '100%' }"
@click="sessionAddLock"
:loading="isLock"
>
+ 新建会话
</u-button>
</view>
<view class="flex-1 min-h-0">
<scroll-view scroll-y class="h-full">
<view class="px-[20rpx]">
<view v-for="item in sessionLists" :key="item.id">
<session-item
v-model="sessionActive"
:item-id="item.id"
:name="item.name"
@edit="sessionEdit"
@delete="sessionDelete"
/>
</view>
</view>
</scroll-view>
</view>
<view class="px-[20rpx] py-[20rpx]">
<u-button
:custom-style="{ width: '100%' }"
@click="sessionClear"
>
删除所有会话
</u-button>
</view>
</view>
</u-popup>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useAppStore } from '@/stores/app'
import { useSessionList } from './useSessionList'
import { useLockFn } from '@/hooks/useLockFn'
import SessionItem from './session-item.vue'
import { watch } from 'vue'
const props = defineProps({
modelValue: {
type: Boolean
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: boolean): void
}>()
const show = computed({
get: () => {
return props.modelValue
},
set: (value) => {
emit('update:modelValue', value)
}
})
const {
sessionLists,
sessionAdd,
sessionEdit,
sessionDelete,
sessionClear,
sessionActive
} = useSessionList()
const { lockFn: sessionAddLock, isLock } = useLockFn(async () => {
await sessionAdd()
})
const appStore = useAppStore()
watch(
() => appStore.getChatConfig,
() => {
if (appStore.getChatConfig.is_reopen) {
sessionAddLock()
appStore.getChatConfig.is_reopen = 0
}
},
{
immediate: true
}
)
</script>

@ -0,0 +1,31 @@
<template>
<view class="bg-[#333] text-white flex items-center px-[20rpx] py-[24rpx]">
<u-icon name="list" :size="40" @click="show = true" />
<view class="flex-1 line-clamp-1 ml-[20rpx]">{{ currentSession }}</view>
<view class="text-xs flex items-center" @click="sessionAdd">
<u-icon name="plus-circle" class="mr-[8rpx]" size="36" />
新建
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useSessionList } from './useSessionList'
const props = defineProps({
modelValue: {
type: Boolean
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: boolean): void
}>()
const show = computed({
get: () => {
return props.modelValue
},
set: (value) => {
emit('update:modelValue', value)
}
})
const { currentSession, sessionAdd } = useSessionList()
</script>

@ -0,0 +1,81 @@
import {
chatCategoryAdd,
chatCategoryClear,
chatCategoryDelete,
chatCategoryEdit,
getChatCategoryLists
} from '@/api/chat'
import { computed, ref } from 'vue'
const sessionActive = ref(0)
const sessionLists = ref<any[]>([])
export function useSessionList() {
const getSessionLists = async () => {
try {
const data = await getChatCategoryLists({ page_type: 0 })
sessionLists.value = data?.lists || []
if (sessionActive.value === 0) {
initSessionActive()
}
return sessionLists.value
} catch (error) {
sessionLists.value = []
initSessionActive()
}
}
const sessionAdd = async () => {
await chatCategoryAdd({})
await getSessionLists()
initSessionActive()
}
const sessionDelete = async (id: number) => {
const res = await uni.showModal({
title: '确定删除该会话?'
})
if (res.confirm) {
await chatCategoryDelete({ id })
await getSessionLists()
initSessionActive()
}
}
const sessionClear = async () => {
const res = await uni.showModal({
title: '确定清除所有会话?'
})
if (res.confirm) {
await chatCategoryClear()
await getSessionLists()
initSessionActive()
}
}
const sessionEdit = async (id: number, name: string) => {
await chatCategoryEdit({ id, name })
getSessionLists()
}
const initSessionActive = () => {
sessionActive.value = sessionLists.value[0]?.id || 0
}
const currentSession = computed(() => {
return (
sessionLists.value.find(
(session) => session.id === sessionActive.value
)?.name || ''
)
})
return {
getSessionLists,
sessionActive,
sessionLists,
sessionAdd,
sessionEdit,
sessionDelete,
sessionClear,
currentSession
}
}

@ -10,16 +10,16 @@
"share": true
}
},
{
"path": "pages/ai_creation/ai_creation",
"style": {
"navigationBarTitleText": "AI创作",
"enablePullDownRefresh": true
},
"meta": {
"share": true
}
},
// {
// "path": "pages/ai_creation/ai_creation",
// "style": {
// "navigationBarTitleText": "AI创作",
// "enablePullDownRefresh": true
// },
// "meta": {
// "share": true
// }
// },
{
"path": "pages/skills/skills",
"style": {
@ -102,6 +102,15 @@
"share": true
}
},
{
"path": "pages/ai_talk/ai_talk",
"style": {
"navigationBarTitleText": "AI对话"
},
"meta": {
"share": true
}
},
{
"path": "pages/drawing/drawing",
"style": {
@ -408,6 +417,16 @@
"share": false,
"auth": false
}
},
{
"path" : "pages/ai_creation/ai_creation",
"style" :
{
"navigationBarTitleText" : "AI创作"
},
"meta": {
"auth": false
}
}
]
}
@ -429,10 +448,10 @@
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/ai_creation/ai_creation",
"text": "创作"
},
// {
// "pagePath": "pages/ai_creation/ai_creation",
// "text": "创作"
// },
{
"pagePath": "pages/skills/skills",
"text": "技能"

@ -48,6 +48,7 @@ const decorate = ref<any[]>([])
const getData = async () => {
const data = await getDecorate({ id: 7 })
decorate.value = JSON.parse(data.data)
}
const showList = computed(() => {
return (
@ -71,7 +72,7 @@ const onJump = (row: any) => {
const navigateType = nativeTabList.includes(row.link.path)
? 'switchTab'
: 'navigateTo'
navigateTo(row.link, false, navigateType)
navigateTo(row.link, false, 'navigateTo')
}
onShow(() => {

@ -7,170 +7,213 @@
/>
<!-- #endif -->
</page-meta>
<view class="h-full flex flex-col">
<view class="flex-1 min-h-0 bg-white">
<chat-scroll-view
v-model="chatList"
ref="chatRef"
:type="1"
:otherId="sessionActive"
:showAdd="true"
:safeAreaInsetBottom="false"
:avatar="appStore.getChatConfig.chat_logo"
bottom="100rpx"
<view class="app">
<!-- <uni-swiper-dot class="uni-swiper-dot-box" @clickItem=clickItem :info="info" :current="current" :mode="mode"
field="content">
<swiper class="swiper-box" @change="change" :current="swiperDotIndex">
<swiper-item v-for="(item, index) in info" :key="index">
<view class="swiper-item" :class="'swiper-item' + index">
</view>
</swiper-item>
</swiper>
</uni-swiper-dot> -->
<swiper class="swiper" circular :indicator-dots="indicatorDots" :autoplay="autoplay" :interval="interval"
:duration="duration">
<swiper-item v-for="(item, index) in info" :key="index">
<view class="swiper-item">
<u-image
src="@/static/images/user/banner.png"
width="750"
height="300"
></u-image>
</view>
</swiper-item>
</swiper>
<view class="u-image">
<u-image
src="@/static/images/user/invite.png"
width="710"
height="160"
border-radius="16"
></u-image>
</view>
<view class="main">
<view
class="menu-item text-center"
v-for="(item, index) in showList"
:key="index"
@click="onJump(item)"
>
<template #top>
<follow-official
:show="!!appStore.config.is_follow_official"
:title="appStore.getLoginConfig.involved_text"
/>
<session v-model="showPopup" />
</template>
<template #empty>
<view class="w-full">
<div
class="my-[60rpx] text-center text-[50rpx] font-medium"
>
{{ appStore.getChatConfig.chat_title }}
</div>
<problem-example
v-if="problem.length"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
@show-more="showExamplePopup = true"
/>
<view
v-if="indexData?.tips?.show"
class="bg-page flex flex-col items-center p-[30rpx] mt-[20rpx] m-[40rpx]"
>
<view class="flex items-center">
<u-icon name="warning" :size="40" />
<view class="text-lg ml-[10rpx] break-all">{{
indexData?.tips?.title
}}</view>
</view>
<view
class="text-content text-sm mt-[20rpx] break-all"
>
{{ indexData?.tips?.sub_title }}
</view>
</view>
</view>
</template>
</chat-scroll-view>
<!-- 会话弹窗 -->
<session-popup v-model="showPopup" />
<!-- 会话弹窗 -->
<problem-example-popup
v-model="showExamplePopup"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
/>
<!-- 公告弹窗 -->
<notice-popup></notice-popup>
<!-- #ifdef MP -->
<!-- 微信小程序隐私弹窗 -->
<MpPrivacyPopup></MpPrivacyPopup>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<!-- 苹果App隐私弹窗 -->
<IosPrivacyPopup
v-if="getClient() == ClientEnum.IOS"
@refresh="refreshHandler"
></IosPrivacyPopup>
<!-- #endif -->
<u-image
:src="getImageUrl(item.image)"
class="items-center"
width="130"
height="130"
mode="aspectFit"
border-radius="16"
></u-image>
<view class="mt-[16rpx] font-medium text-xl">
{{ item.title }}
</view>
<view class="mt-[12rpx] text-sm text-[#999999] line-clamp-2">
{{ item.desc }}
</view>
</view>
</view>
<!-- <canvas canvas-id="canvasId" id="canvasId"></canvas> -->
<tabbar />
</view>
</template>
<script setup lang="ts">
import { onHide, onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import { reactive, ref, watch } from 'vue'
import { useAppStore } from '@/stores/app'
import { getDecorate } from '@/api/shop'
import { getSamplesLists } from '@/api/chat'
import SessionPopup from './components/session-popup.vue'
import FollowOfficial from './components/follow-official.vue'
import NoticePopup from '@/components/notice-popup/notice-popup.vue'
import ProblemExample from './components/problem-example.vue'
import Session from './components/session.vue'
import ProblemExamplePopup from './components/problem-example-popup.vue'
// #ifdef MP
import MpPrivacyPopup from './components/mp-privacy-popup.vue'
// #endif
// #ifdef APP-PLUS
import { getClient } from '@/utils/client'
import { ClientEnum } from '@/enums/appEnums'
import IosPrivacyPopup from './components/ios-privacy-popup.vue'
// #endif
import { shallowRef } from 'vue'
import { useSessionList } from './components/useSessionList'
import agreement from '@/components/agreement/agreement.vue'
const { getSessionLists, sessionActive } = useSessionList()
const showPopup = ref(false)
const showExamplePopup = ref(false)
const problem = ref([])
//
const chatList = ref<any[]>([])
const chatRef = shallowRef()
//
const indexData = reactive({
tips: {
show: 0,
title: '',
sub_title: ''
}
})
//
const posterRef = shallowRef()
const modelKey = ref('')
const getProblemExample = async () => {
problem.value = await getSamplesLists()
}
import { computed, ref } from 'vue'
import { useAppStore } from '@/stores/app'
import { navigateTo } from '@/utils/util'
import { onPullDownRefresh, onShow } from '@dcloudio/uni-app'
const getDecorateFunc = async () => {
try {
const { data } = await getDecorate({ id: 8 })
indexData.tips = JSON.parse(data)[1]?.content
} catch (error) {
console.log('获取装修数据失败=>', error)
}
const { getImageUrl, getConfig } = useAppStore()
const decorate = ref<any[]>([])
const getData = async () => {
const data = await getDecorate({ id: 7 })
decorate.value=JSON.parse(data.data)
decorate?.value[0]?.content.data.forEach(
(item: any) => {
if(item.link.path==="/pages/index/index") item.link.path="/packages/pages/ai_talk/ai_talk"
else if(item.link.path==="/pages/ai_creation/ai_creation") item.link.path= "/packages/pages/ai_creation/ai_creation"
}
)
// decorate.value =
console.log(decorate.value ,'===========decorate.value ')
}
const showList = computed(() => {
return (
decorate?.value[0]?.content.data.filter(
(item: any) => item.is_show == 1
) || []
)
})
getData()
const info=[{
colorClass: 'uni-bg-red',
url: '@/static/images/user/banner.png',
content: '内容 A'
},
{
colorClass: 'uni-bg-green',
url: '@/static/images/user/banner.png',
content: '内容 B'
},
{
colorClass: 'uni-bg-blue',
url: '@/static/images/user/banner.png',
content: '内容 C'
}
]
const appStore = useAppStore()
const showChatView = ref(true)
const refreshHandler = async () => {
await appStore.getConfig()
await getDecorateFunc()
await getSessionLists()
await getProblemExample()
const autoplay=true
const indicatorDots=true
const interval=ref(2000)
const duration=ref(500)
//
const nativeTabList = [
'/pages/index/index',
'/pages/skills/skills',
'/pages/app/app',
'/pages/user/user'
]
const onJump = (row: any) => {
const navigateType = nativeTabList.includes(row.link.path)
? 'switchTab'
: 'navigateTo'
navigateTo(row.link, false, navigateType)
}
// onHide(() => {
// showChatView.value = false
// })
onShow(async () => {
getDecorateFunc()
getSessionLists()
getProblemExample()
onShow(() => {
getConfig()
})
onPullDownRefresh(async () => {
refreshHandler()
await getData()
uni.stopPullDownRefresh()
})
</script>
<style lang="scss" scoped>
.app {
min-height: 100vh;
background: linear-gradient(to right, #e8fdf8, #ffffff, #e5f7ff);
}
.header {
padding: 30rpx;
padding-bottom: 0;
.title {
display: inline-block;
font-size: 40rpx;
font-weight: bold;
background: -webkit-linear-gradient(90deg, #19e8b7, #00abff);
background: -moz-linear-gradient(90deg, #19e8b7, #00abff);
background: -o-linear-gradient(90deg, #19e8b7, #00abff);
background: linear-gradient(90deg, #19e8b7, #00abff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
-moz-background-clip: text;
-moz-text-fill-color: transparent;
-o-background-clip: text;
-o-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
}
.u-image{
margin: 25rpx 20rpx 20rpx;
}
.main {
flex: 1;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 24rpx;
<style>
page {
height: 100%;
overflow: hidden;
.menu-item {
display: inline-block;
margin-bottom: 20rpx;
padding: 20rpx;
width: 340rpx;
//height: 380rpx;
border-radius: 16rpx;
background-color: #ffffff;
box-shadow: 0 3rpx 10rpx #e3e3e3;
.items-center{
margin: 0 auto;
}
}
}
.uni-margin-wrap {
width: 690rpx;
width: 100%;
}
.swiper {
height: 300rpx;
}
.swiper-item {
display: block;
height: 300rpx;
line-height: 300rpx;
text-align: center;
}
.swiper-list {
margin-top: 40rpx;
margin-bottom: 0;
}
.uni-common-mt {
margin-top: 60rpx;
position: relative;
}
.info {
position: absolute;
right: 20rpx;
}
.uni-padding-wrap {
width: 550rpx;
padding: 0 100rpx;
}
</style>

@ -0,0 +1,176 @@
<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar
:front-color="$theme.navColor"
:background-color="$theme.navBgColor"
/>
<!-- #endif -->
</page-meta>
<view class="h-full flex flex-col">
<view class="flex-1 min-h-0 bg-white">
<chat-scroll-view
v-model="chatList"
ref="chatRef"
:type="1"
:otherId="sessionActive"
:showAdd="true"
:safeAreaInsetBottom="false"
:avatar="appStore.getChatConfig.chat_logo"
bottom="100rpx"
>
<template #top>
<follow-official
:show="!!appStore.config.is_follow_official"
:title="appStore.getLoginConfig.involved_text"
/>
<session v-model="showPopup" />
</template>
<template #empty>
<view class="w-full">
<div
class="my-[60rpx] text-center text-[50rpx] font-medium"
>
{{ appStore.getChatConfig.chat_title }}
</div>
<problem-example
v-if="problem.length"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
@show-more="showExamplePopup = true"
/>
<view
v-if="indexData?.tips?.show"
class="bg-page flex flex-col items-center p-[30rpx] mt-[20rpx] m-[40rpx]"
>
<view class="flex items-center">
<u-icon name="warning" :size="40" />
<view class="text-lg ml-[10rpx] break-all">{{
indexData?.tips?.title
}}</view>
</view>
<view
class="text-content text-sm mt-[20rpx] break-all"
>
{{ indexData?.tips?.sub_title }}
</view>
</view>
</view>
</template>
</chat-scroll-view>
<!-- 会话弹窗 -->
<session-popup v-model="showPopup" />
<!-- 会话弹窗 -->
<problem-example-popup
v-model="showExamplePopup"
:data="problem"
@click-item="(value:any) => chatRef.sendLock(value)"
/>
<!-- 公告弹窗 -->
<notice-popup></notice-popup>
<!-- #ifdef MP -->
<!-- 微信小程序隐私弹窗 -->
<MpPrivacyPopup></MpPrivacyPopup>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<!-- 苹果App隐私弹窗 -->
<IosPrivacyPopup
v-if="getClient() == ClientEnum.IOS"
@refresh="refreshHandler"
></IosPrivacyPopup>
<!-- #endif -->
</view>
<!-- <canvas canvas-id="canvasId" id="canvasId"></canvas> -->
<tabbar />
</view>
</template>
<script setup lang="ts">
import { onHide, onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import { reactive, ref, watch } from 'vue'
import { useAppStore } from '@/stores/app'
import { getDecorate } from '@/api/shop'
import { getSamplesLists } from '@/api/chat'
import SessionPopup from './components/session-popup.vue'
import FollowOfficial from './components/follow-official.vue'
import NoticePopup from '@/components/notice-popup/notice-popup.vue'
import ProblemExample from './components/problem-example.vue'
import Session from './components/session.vue'
import ProblemExamplePopup from './components/problem-example-popup.vue'
// #ifdef MP
import MpPrivacyPopup from './components/mp-privacy-popup.vue'
// #endif
// #ifdef APP-PLUS
import { getClient } from '@/utils/client'
import { ClientEnum } from '@/enums/appEnums'
import IosPrivacyPopup from './components/ios-privacy-popup.vue'
// #endif
import { shallowRef } from 'vue'
import { useSessionList } from './components/useSessionList'
import agreement from '@/components/agreement/agreement.vue'
const { getSessionLists, sessionActive } = useSessionList()
const showPopup = ref(false)
const showExamplePopup = ref(false)
const problem = ref([])
//
const chatList = ref<any[]>([])
const chatRef = shallowRef()
//
const indexData = reactive({
tips: {
show: 0,
title: '',
sub_title: ''
}
})
//
const posterRef = shallowRef()
const modelKey = ref('')
const getProblemExample = async () => {
problem.value = await getSamplesLists()
}
const getDecorateFunc = async () => {
try {
const { data } = await getDecorate({ id: 8 })
indexData.tips = JSON.parse(data)[1]?.content
} catch (error) {
console.log('获取装修数据失败=>', error)
}
}
const appStore = useAppStore()
const showChatView = ref(true)
const refreshHandler = async () => {
await appStore.getConfig()
await getDecorateFunc()
await getSessionLists()
await getProblemExample()
}
// onHide(() => {
// showChatView.value = false
// })
onShow(async () => {
getDecorateFunc()
getSessionLists()
getProblemExample()
})
onPullDownRefresh(async () => {
refreshHandler()
uni.stopPullDownRefresh()
})
</script>
<style>
page {
height: 100%;
overflow: hidden;
}
</style>

@ -23,13 +23,14 @@
<u-form-item required label="头像" :labelWidth="120">
<view class="flex-1">
<avatar-upload
v-model="avatar"
:modelValue="avatar"
@upload="uploadImg"
></avatar-upload>
</view>
</u-form-item>
<u-form-item required label="昵称" :labelWidth="120">
<u-form-item required label="昵称" :labelWidth="120">
<input
:value="nickname"
class="flex-1 h-[60rpx]"
name="nickname"
type="nickname"
@ -60,7 +61,7 @@
<script lang="ts" setup>
import { uploadImage } from '@/api/app'
import { computed, ref } from 'vue'
import { computed, ref,onMounted } from 'vue'
const props = defineProps({
show: {
type: Boolean
@ -90,7 +91,14 @@ const showPopup = computed({
})
const avatar = ref()
const nickname=ref('')
onMounted(()=>{
console.log(props.userInfo,'====props')
if(props.userInfo?.avatar){
avatar.value=props.userInfo.avatar
nickname.value=props.userInfo.nickname
}
})
const uploadImg = async (file: string) => {
uni.showLoading({
title: '正在上传中...'
@ -108,7 +116,7 @@ const uploadImg = async (file: string) => {
}
const handleSubmit = (e: any) => {
const { nickname } = e.detail.value
const { nickname } = props.userInfo// e.detail.value
if (!avatar.value) return uni.$u.toast('请添加头像')
if (!nickname) return uni.$u.toast('请输入昵称')
emit('update', {

@ -73,6 +73,7 @@
</view>
<update-user-info
v-if="loginData.hasOwnProperty('avatar')"
v-model:show="showLoginPopup"
:logo="websiteConfig.shop_logo"
:title="websiteConfig.shop_name"

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

@ -183,6 +183,7 @@ export default {
// addUnit()pxrpx
style.width = this.$u.addUnit(this.width);
style.height = this.$u.addUnit(this.height);
style.margin='0 auto';
// 50%
style.borderRadius = this.shape == 'circle' ? '50%' : this.$u.addUnit(this.borderRadius);
// hidden
@ -191,6 +192,7 @@ export default {
style.opacity = this.opacity;
style.transition = `opacity ${Number(this.durationTime) / 1000}s ease-in-out`;
}
return style;
}
},

Loading…
Cancel
Save