Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 685c6d0910 | |||
| 03231e611c | |||
| e917befe02 | |||
| 4e92ec2000 | |||
| 2da15786c8 | |||
| 8e27c27abf | |||
| 76ead609d5 | |||
| 521a0bf4b3 | |||
|
|
2d3cd6796e | ||
| e383bbbcf0 | |||
| 6f879a0bc8 | |||
| d78368b4ec | |||
| 226ddf8305 | |||
| 98c1d50ca5 | |||
| 8211e0b91b | |||
| 17a05aab4c | |||
| ff9227c3b8 | |||
| 5aba9afdd5 | |||
| 0351bd8dc6 | |||
| 3b8e604853 | |||
| fbb19c4603 |
@@ -6,14 +6,16 @@
|
|||||||
"placeholder": "快告诉智念您在想什么~",
|
"placeholder": "快告诉智念您在想什么~",
|
||||||
"loginDesc": "您好,欢迎来到智念科技",
|
"loginDesc": "您好,欢迎来到智念科技",
|
||||||
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/dh_logo.png",
|
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/dh_logo.png",
|
||||||
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_large.png",
|
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/zn/zn_large.png",
|
||||||
|
"ipLargeImageWidth": 395,
|
||||||
|
"ipLargeImageHeight": 335,
|
||||||
|
"ipLargeTotalFrames": 71,
|
||||||
|
"ipLargeColumns": 1,
|
||||||
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_small.png",
|
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_small.png",
|
||||||
"ipLargeImageHeight": 19687,
|
"ipSmallImageWidth": 128,
|
||||||
"ipSmallImageHeight": 3744,
|
"ipSmallImageHeight": 128,
|
||||||
"ipLargeImageStep": 147,
|
"ipSmallTotalFrames": 117,
|
||||||
"ipSmallImageStep": 117,
|
"ipSmallColumns": 1
|
||||||
"ipLargeTime": 4,
|
|
||||||
"ipSmallTime": 4
|
|
||||||
},
|
},
|
||||||
"duohua": {
|
"duohua": {
|
||||||
"clientId": "2",
|
"clientId": "2",
|
||||||
@@ -23,13 +25,15 @@
|
|||||||
"loginDesc": "您好,欢迎来到朵花温泉",
|
"loginDesc": "您好,欢迎来到朵花温泉",
|
||||||
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/dh_logo.png",
|
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/dh_logo.png",
|
||||||
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_large.png",
|
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_large.png",
|
||||||
|
"ipLargeImageWidth": 263,
|
||||||
|
"ipLargeImageHeight": 210,
|
||||||
|
"ipLargeTotalFrames": 147,
|
||||||
|
"ipLargeColumns": 1,
|
||||||
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_small.png",
|
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_small.png",
|
||||||
"ipLargeImageHeight": 19687,
|
"ipSmallImageWidth": 128,
|
||||||
"ipSmallImageHeight": 3744,
|
"ipSmallImageHeight": 128,
|
||||||
"ipLargeImageStep": 147,
|
"ipSmallTotalFrames": 117,
|
||||||
"ipSmallImageStep": 117,
|
"ipSmallColumns": 1
|
||||||
"ipLargeTime": 4,
|
|
||||||
"ipSmallTime": 4
|
|
||||||
},
|
},
|
||||||
"tianmu": {
|
"tianmu": {
|
||||||
"clientId": "4",
|
"clientId": "4",
|
||||||
@@ -39,12 +43,14 @@
|
|||||||
"loginDesc": "您好,欢迎来到天沐温泉",
|
"loginDesc": "您好,欢迎来到天沐温泉",
|
||||||
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/tm_logo.png",
|
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/tm_logo.png",
|
||||||
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_large.png",
|
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_large.png",
|
||||||
|
"ipLargeImageWidth": 395,
|
||||||
|
"ipLargeImageHeight": 335,
|
||||||
|
"ipLargeTotalFrames": 71,
|
||||||
|
"ipLargeColumns": 1,
|
||||||
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_small.png",
|
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_small.png",
|
||||||
"ipLargeImageHeight": 9514,
|
"ipSmallImageWidth": 128,
|
||||||
"ipSmallImageHeight": 4736,
|
"ipSmallImageHeight": 128,
|
||||||
"ipLargeImageStep": 71,
|
"ipSmallTotalFrames": 148,
|
||||||
"ipSmallImageStep": 148,
|
"ipSmallColumns": 1
|
||||||
"ipLargeTime": 4,
|
|
||||||
"ipSmallTime": 6
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
|
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
|
||||||
import { getEvnUrl } from "@/request/api/config";
|
import { getEvnUrl } from "@/request/base/config";
|
||||||
import { refreshToken } from "@/hooks/useGoLogin";
|
import { refreshToken } from "@/hooks/useGoLogin";
|
||||||
import { getAccessToken } from "@/constant/token";
|
import { getAccessToken } from "@/constant/token";
|
||||||
|
|
||||||
|
|||||||
112
src/components/Sprite/SpriteAnimator.vue
Normal file
112
src/components/Sprite/SpriteAnimator.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<view class="sprite-animator" :style="spriteStyle" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
src: string
|
||||||
|
frameWidth: number
|
||||||
|
frameHeight: number
|
||||||
|
totalFrames: number
|
||||||
|
columns: number
|
||||||
|
displayWidth: number
|
||||||
|
fps?: number
|
||||||
|
autoplay?: boolean
|
||||||
|
loop?: boolean
|
||||||
|
}>(), {
|
||||||
|
fps: 12,
|
||||||
|
autoplay: true,
|
||||||
|
loop: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/* JS 精确逐帧方案(使用 setInterval,确保整数偏移、无插值) */
|
||||||
|
const currentFrame = ref(0)
|
||||||
|
let intervalId: number | null = null
|
||||||
|
|
||||||
|
const play = () => {
|
||||||
|
stop()
|
||||||
|
const safeFps = Math.max(1, Math.floor(props.fps || 12))
|
||||||
|
const durationPerFrame = 1000 / safeFps
|
||||||
|
// 强制整数像素偏移,使用 setInterval 在各运行时更可靠
|
||||||
|
const setter = (globalThis as any).setInterval || setInterval
|
||||||
|
intervalId = setter(() => {
|
||||||
|
const safeTotal = Math.max(1, Math.floor(props.totalFrames || 0))
|
||||||
|
if (currentFrame.value >= safeTotal - 1) {
|
||||||
|
if (props.loop) {
|
||||||
|
currentFrame.value = 0
|
||||||
|
} else {
|
||||||
|
stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentFrame.value++
|
||||||
|
}
|
||||||
|
}, durationPerFrame) as unknown as number
|
||||||
|
}
|
||||||
|
|
||||||
|
const stop = () => {
|
||||||
|
if (intervalId) {
|
||||||
|
clearInterval(intervalId)
|
||||||
|
intervalId = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('[SpriteAnimator] mounted', { autoplay: props.autoplay, fps: props.fps })
|
||||||
|
if (props.autoplay) play()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => stop())
|
||||||
|
|
||||||
|
const spriteStyle = computed(() => {
|
||||||
|
const {
|
||||||
|
src,
|
||||||
|
frameWidth: rawFrameWidth,
|
||||||
|
frameHeight: rawFrameHeight,
|
||||||
|
totalFrames: rawTotalFrames,
|
||||||
|
columns: rawColumns,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const frameWidth = Math.max(1, Math.floor(rawFrameWidth || 0))
|
||||||
|
const frameHeight = Math.max(1, Math.floor(rawFrameHeight || 0))
|
||||||
|
const totalFrames = Math.max(1, Math.floor(rawTotalFrames || 0))
|
||||||
|
let columns = Math.floor(Number(rawColumns) || 0)
|
||||||
|
if (!columns || columns <= 0) columns = Math.min(1, totalFrames)
|
||||||
|
columns = Math.min(columns, totalFrames)
|
||||||
|
|
||||||
|
const displayWidth = props.displayWidth || frameWidth
|
||||||
|
|
||||||
|
const rows = Math.ceil(totalFrames / columns)
|
||||||
|
const imageWidth = columns * frameWidth
|
||||||
|
const imageHeight = rows * frameHeight
|
||||||
|
|
||||||
|
const scale = displayWidth / frameWidth
|
||||||
|
const displayHeight = Math.round(frameHeight * scale)
|
||||||
|
|
||||||
|
const scaledImageWidth = Math.round(imageWidth * scale)
|
||||||
|
const scaledImageHeight = Math.round(imageHeight * scale)
|
||||||
|
|
||||||
|
if (currentFrame.value < 0) currentFrame.value = 0
|
||||||
|
if (currentFrame.value >= totalFrames) currentFrame.value = totalFrames - 1
|
||||||
|
const col = currentFrame.value % columns
|
||||||
|
const row = Math.floor(currentFrame.value / columns)
|
||||||
|
|
||||||
|
const offsetX = Math.round(col * frameWidth * scale)
|
||||||
|
const offsetY = Math.round(row * frameHeight * scale)
|
||||||
|
|
||||||
|
const styleStr = `width: ${Math.round(displayWidth)}px; height: ${displayHeight}px; background-image: url("${src}"); background-repeat: no-repeat; background-size: ${scaledImageWidth}px ${scaledImageHeight}px; background-position: -${offsetX}px -${offsetY}px;`
|
||||||
|
return styleStr as any
|
||||||
|
})
|
||||||
|
|
||||||
|
// 对外暴露
|
||||||
|
defineExpose({ play, stop, currentFrame })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sprite-animator {
|
||||||
|
display: block;
|
||||||
|
will-change: background-position;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
47
src/components/SurveyQuestionnaire/index.vue
Normal file
47
src/components/SurveyQuestionnaire/index.vue
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<view class="survey-questionnaire w-vw-24">
|
||||||
|
<view class="bg-white border-box border-ff overflow-hidden rounded-20">
|
||||||
|
<view class="border-box flex flex-items-center flex-justify-between bg-EEF8FF">
|
||||||
|
<text class="font-size-18 font-500 color-171717 text-left ml-12">
|
||||||
|
调查问卷
|
||||||
|
</text>
|
||||||
|
<image class="w-102 h-72" :src="surveyData.logoUrl" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<image class="w-full" :src="surveyData.bannerUrl" mode="widthFix" />
|
||||||
|
|
||||||
|
<view class="h-44 m-12 rounded-50 bg-button color-white flex flex-items-center flex-justify-center"
|
||||||
|
@click="handleCall">
|
||||||
|
前往填写
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getAccessToken } from "@/constant/token";
|
||||||
|
import { defineProps, computed } from "vue";
|
||||||
|
import { navigateTo } from "../../router";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
toolCall: {
|
||||||
|
type: Object,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const surveyData = computed(() => {
|
||||||
|
if (props.toolCall?.data) {
|
||||||
|
return JSON.parse(props.toolCall?.data);
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCall = () => {
|
||||||
|
const token = getAccessToken();
|
||||||
|
navigateTo(surveyData.value.jumpUrl, { token: token });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -7,13 +7,6 @@ export const MessageRole = {
|
|||||||
OTHER: "OTHER",
|
OTHER: "OTHER",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MessageType = {
|
|
||||||
// 文本消息
|
|
||||||
TEXT: "TEXT",
|
|
||||||
// 图片消息
|
|
||||||
IMAGE: "IMAGE",
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 组件的名称
|
/// 组件的名称
|
||||||
export const CompName = {
|
export const CompName = {
|
||||||
// 快速预定卡片
|
// 快速预定卡片
|
||||||
@@ -28,6 +21,8 @@ export const CompName = {
|
|||||||
pictureAndCommodityCard: "pictureAndCommodityCard",
|
pictureAndCommodityCard: "pictureAndCommodityCard",
|
||||||
// 输入车牌卡片
|
// 输入车牌卡片
|
||||||
enterLicensePlateCard: "enterLicensePlateCard",
|
enterLicensePlateCard: "enterLicensePlateCard",
|
||||||
|
// 调查问卷卡片
|
||||||
|
callSurveyQuestionnaire: "callSurveyQuestionnaire",
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 发送的指令类型
|
/// 发送的指令类型
|
||||||
|
|||||||
@@ -1,40 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="bg-white rounded-12 overflow-hidden mb-12">
|
<view class="bg-white rounded-12 overflow-hidden mb-12">
|
||||||
<view class="flex flex-items-center border-box p-12 border-bottom">
|
<view class="flex flex-items-center border-box p-12 border-bottom">
|
||||||
<view class="font-size-16 font-500 color-000 line-height-24 flex-full"
|
<view class="font-size-16 font-500 color-000 line-height-24 flex-full">入住信息</view>
|
||||||
>入住信息</view
|
|
||||||
>
|
|
||||||
<view class="right">
|
<view class="right">
|
||||||
<Stepper v-model="count" unit="间" />
|
<Stepper v-model="count" unit="间" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="border-box pl-12 pr-12">
|
<view class="border-box pl-12 pr-12">
|
||||||
<view
|
<view class="border-box border-bottom pt-12 pb-12 flex flex-items-center" v-for="(item, index) in userFormList"
|
||||||
class="border-box border-bottom pt-12 pb-12 flex flex-items-center"
|
:key="index">
|
||||||
v-for="(item, index) in userFormList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<view class="font-size-14 font-500 color-525866 mr-12"> 住客姓名 </view>
|
<view class="font-size-14 font-500 color-525866 mr-12"> 住客姓名 </view>
|
||||||
<view class="right">
|
<view class="right">
|
||||||
<input
|
<input class="border-box px-4 py-2 font-size-15 color-000 line-height-20" v-model.trim="item.visitorName"
|
||||||
class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20"
|
placeholder="请输入姓名" maxlength="11" />
|
||||||
v-model.trim="item.visitorName"
|
|
||||||
placeholder="请输入姓名"
|
|
||||||
maxlength="11"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="flex flex-items-center border-box pt-12 pb-12">
|
<view class="flex flex-items-center border-box pt-12 pb-12">
|
||||||
<view class="font-size-14 font-500 color-525866 mr-12"> 联系手机 </view>
|
<view class="font-size-14 font-500 color-525866 mr-12"> 联系手机 </view>
|
||||||
<view class="right">
|
<view class="right">
|
||||||
<input
|
<input class="border-box px-4 py-2 font-size-15 color-000 line-height-20"
|
||||||
class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20"
|
v-model.trim="userFormList[0].contactPhone" placeholder="请输入联系手机" maxlength="11" />
|
||||||
v-model.trim="userFormList[0].contactPhone"
|
|
||||||
placeholder="请输入联系手机"
|
|
||||||
maxlength="11"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<text class="font-size-12 line-height-16 color-99A0AE">
|
<text class="font-size-12 line-height-16 color-99A0AE">
|
||||||
/{{ item.stockUnitLabel }}
|
/{{ item.stockUnitLabel }}
|
||||||
</text>
|
</text>
|
||||||
<text class="btn border-box rounded-10 color-white ml-16" @click.stop="handleBooking(item)">订</text>
|
<text class="btn border-box rounded-10 color-white ml-16">订</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -63,7 +63,6 @@ const navigateToPage = (commodityId, path) => {
|
|||||||
|
|
||||||
const handleClick = ({ commodityId }) => navigateToPage(commodityId, "/pages/goods/index")
|
const handleClick = ({ commodityId }) => navigateToPage(commodityId, "/pages/goods/index")
|
||||||
|
|
||||||
const handleBooking = ({ commodityId }) => navigateToPage(commodityId, "/pages-booking/index")
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -23,6 +23,15 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/webview/index",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"backgroundColor": "#FFFFFF",
|
||||||
|
"navigationBarBackgroundColor": "#FFFFFF",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
@@ -84,4 +93,4 @@
|
|||||||
"backgroundColor": "#F8F8F8"
|
"backgroundColor": "#F8F8F8"
|
||||||
},
|
},
|
||||||
"uniIdRouter": {}
|
"uniIdRouter": {}
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,9 @@
|
|||||||
<AddCarCrad v-else-if="
|
<AddCarCrad v-else-if="
|
||||||
item.toolCall.componentName === CompName.enterLicensePlateCard
|
item.toolCall.componentName === CompName.enterLicensePlateCard
|
||||||
" :toolCall="item.toolCall" />
|
" :toolCall="item.toolCall" />
|
||||||
|
<SurveyQuestionnaire v-else-if="
|
||||||
|
item.toolCall.componentName === CompName.callSurveyQuestionnaire
|
||||||
|
" :toolCall="item.toolCall" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -82,7 +85,7 @@ import {
|
|||||||
NOTICE_EVENT_LOGOUT,
|
NOTICE_EVENT_LOGOUT,
|
||||||
NOTICE_EVENT_LOGIN_SUCCESS,
|
NOTICE_EVENT_LOGIN_SUCCESS,
|
||||||
} from "@/constant/constant";
|
} from "@/constant/constant";
|
||||||
import { MessageRole, MessageType, CompName } from "@/model/ChatModel";
|
import { MessageRole, CompName } from "@/model/ChatModel";
|
||||||
import ChatTopWelcome from "../ChatTopWelcome/index.vue";
|
import ChatTopWelcome from "../ChatTopWelcome/index.vue";
|
||||||
import ChatTopNavBar from "../ChatTopNavBar/index.vue";
|
import ChatTopNavBar from "../ChatTopNavBar/index.vue";
|
||||||
import ChatCardAI from "../ChatCardAi/index.vue";
|
import ChatCardAI from "../ChatCardAi/index.vue";
|
||||||
@@ -99,6 +102,7 @@ import DetailCardCompontent from "../../module/DetailCardCompontent/index.vue";
|
|||||||
import CreateServiceOrder from "@/components/CreateServiceOrder/index.vue";
|
import CreateServiceOrder from "@/components/CreateServiceOrder/index.vue";
|
||||||
import Feedback from "@/components/Feedback/index.vue";
|
import Feedback from "@/components/Feedback/index.vue";
|
||||||
import AddCarCrad from "@/components/AddCarCrad/index.vue";
|
import AddCarCrad from "@/components/AddCarCrad/index.vue";
|
||||||
|
import SurveyQuestionnaire from "@/components/SurveyQuestionnaire/index.vue";
|
||||||
import { mainPageData } from "@/request/api/MainPageDataApi";
|
import { mainPageData } from "@/request/api/MainPageDataApi";
|
||||||
import {
|
import {
|
||||||
conversationMsgList,
|
conversationMsgList,
|
||||||
@@ -144,7 +148,7 @@ const mainPageDataModel = ref({});
|
|||||||
// 会话进行中标志
|
// 会话进行中标志
|
||||||
const isSessionActive = ref(false);
|
const isSessionActive = ref(false);
|
||||||
/// 指令
|
/// 指令
|
||||||
let commonType = "";
|
let messageCommonType = "";
|
||||||
|
|
||||||
// WebSocket 相关
|
// WebSocket 相关
|
||||||
let webSocketManager = null;
|
let webSocketManager = null;
|
||||||
@@ -234,7 +238,7 @@ const handleReplyText = (text) => {
|
|||||||
const handleReplyInstruct = async (item) => {
|
const handleReplyInstruct = async (item) => {
|
||||||
await checkToken();
|
await checkToken();
|
||||||
|
|
||||||
commonType = item.type;
|
messageCommonType = item.type;
|
||||||
// 重置消息状态,准备接收新的AI回复
|
// 重置消息状态,准备接收新的AI回复
|
||||||
resetMessageState();
|
resetMessageState();
|
||||||
sendMessage(item.title, true);
|
sendMessage(item.title, true);
|
||||||
@@ -608,10 +612,6 @@ const sendMessage = async (message, isInstruct = false) => {
|
|||||||
msgId: `msg_${chatMsgList.value.length}`,
|
msgId: `msg_${chatMsgList.value.length}`,
|
||||||
msgType: MessageRole.ME,
|
msgType: MessageRole.ME,
|
||||||
msg: message,
|
msg: message,
|
||||||
msgContent: {
|
|
||||||
type: MessageType.TEXT,
|
|
||||||
text: message,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
chatMsgList.value.push(newMsg);
|
chatMsgList.value.push(newMsg);
|
||||||
inputMessage.value = "";
|
inputMessage.value = "";
|
||||||
@@ -662,31 +662,31 @@ const sendWebSocketMessage = async (messageType, messageContent, options = {}) =
|
|||||||
try {
|
try {
|
||||||
const raw = webSocketManager.sendMessage(args);
|
const raw = webSocketManager.sendMessage(args);
|
||||||
// 兼容可能返回同步布尔或 Promise 的实现
|
// 兼容可能返回同步布尔或 Promise 的实现
|
||||||
const result = await Promise.resolve(raw);
|
const result = await Promise.resolve(raw);
|
||||||
if (result) {
|
if (result) {
|
||||||
console.log(`WebSocket消息已发送 [类型:${messageType}]:`, args);
|
console.log(`WebSocket消息已发送 [类型:${messageType}]:`, args);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 若返回 false,消息可能已经被 manager 入队并触发连接流程。
|
// 若返回 false,消息可能已经被 manager 入队并触发连接流程。
|
||||||
// 在这种情况下避免立即当作失败处理,而是等待短暂时间以观察连接是否建立并由 manager 发送队列。
|
// 在这种情况下避免立即当作失败处理,而是等待短暂时间以观察连接是否建立并由 manager 发送队列。
|
||||||
console.warn('webSocketManager.sendMessage 返回 false,等待连接或队列发送...', { attempt, args });
|
console.warn('webSocketManager.sendMessage 返回 false,等待连接或队列发送...', { attempt, args });
|
||||||
const waitForConnectMs = typeof options.waitForConnectMs === 'number' ? options.waitForConnectMs : 5000;
|
const waitForConnectMs = typeof options.waitForConnectMs === 'number' ? options.waitForConnectMs : 5000;
|
||||||
if (webSocketManager && typeof webSocketManager.isConnected === 'function' && !webSocketManager.isConnected()) {
|
if (webSocketManager && typeof webSocketManager.isConnected === 'function' && !webSocketManager.isConnected()) {
|
||||||
const startTs = Date.now();
|
const startTs = Date.now();
|
||||||
while (Date.now() - startTs < waitForConnectMs) {
|
while (Date.now() - startTs < waitForConnectMs) {
|
||||||
await sleep(200);
|
await sleep(200);
|
||||||
if (webSocketManager.isConnected()) {
|
if (webSocketManager.isConnected()) {
|
||||||
// 给 manager 一点时间处理队列并发送
|
// 给 manager 一点时间处理队列并发送
|
||||||
await sleep(150);
|
await sleep(150);
|
||||||
console.log('检测到 manager 已连接,假定队列消息已发送', args);
|
console.log('检测到 manager 已连接,假定队列消息已发送', args);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.warn('等待 manager 建连超时,进入重试逻辑', { waitForConnectMs, args });
|
|
||||||
} else {
|
|
||||||
console.warn('sendMessage 返回 false 但 manager 看起来已连接或不可用,继续重试', { args });
|
|
||||||
}
|
}
|
||||||
|
console.warn('等待 manager 建连超时,进入重试逻辑', { waitForConnectMs, args });
|
||||||
|
} else {
|
||||||
|
console.warn('sendMessage 返回 false 但 manager 看起来已连接或不可用,继续重试', { args });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送WebSocket消息异常:', error, args);
|
console.error('发送WebSocket消息异常:', error, args);
|
||||||
}
|
}
|
||||||
@@ -734,7 +734,7 @@ const sendChat = async (message, isInstruct = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messageType = isInstruct ? 1 : 0;
|
const messageType = isInstruct ? 1 : 0;
|
||||||
const messageContent = isInstruct ? commonType : message;
|
const messageContent = isInstruct ? messageCommonType : message;
|
||||||
// 生成 messageId 并保存到当前会话变量(stopRequest 可能使用)
|
// 生成 messageId 并保存到当前会话变量(stopRequest 可能使用)
|
||||||
currentSessionMessageId = IdUtils.generateMessageId();
|
currentSessionMessageId = IdUtils.generateMessageId();
|
||||||
|
|
||||||
@@ -744,10 +744,6 @@ const sendChat = async (message, isInstruct = false) => {
|
|||||||
msgType: MessageRole.AI,
|
msgType: MessageRole.AI,
|
||||||
msg: "加载中",
|
msg: "加载中",
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
msgContent: {
|
|
||||||
type: MessageType.TEXT,
|
|
||||||
url: "",
|
|
||||||
},
|
|
||||||
messageId: currentSessionMessageId,
|
messageId: currentSessionMessageId,
|
||||||
};
|
};
|
||||||
chatMsgList.value.push(aiMsg);
|
chatMsgList.value.push(aiMsg);
|
||||||
@@ -810,11 +806,11 @@ const stopRequest = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (chatMsgList.value[aiMsgIndex] &&
|
if (chatMsgList.value[aiMsgIndex] &&
|
||||||
chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI) {
|
chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI) {
|
||||||
chatMsgList.value[aiMsgIndex].isLoading = false;
|
chatMsgList.value[aiMsgIndex].isLoading = false;
|
||||||
if (chatMsgList.value[aiMsgIndex].msg &&
|
if (chatMsgList.value[aiMsgIndex].msg &&
|
||||||
chatMsgList.value[aiMsgIndex].msg.trim() &&
|
chatMsgList.value[aiMsgIndex].msg.trim() &&
|
||||||
!chatMsgList.value[aiMsgIndex].msg.startsWith("加载中")) {
|
!chatMsgList.value[aiMsgIndex].msg.startsWith("加载中")) {
|
||||||
// 保留已显示内容
|
// 保留已显示内容
|
||||||
} else {
|
} else {
|
||||||
chatMsgList.value[aiMsgIndex].msg = "请求已停止";
|
chatMsgList.value[aiMsgIndex].msg = "请求已停止";
|
||||||
|
|||||||
@@ -4,19 +4,15 @@
|
|||||||
|
|
||||||
<!-- 隐藏 -->
|
<!-- 隐藏 -->
|
||||||
<view class="flex-full h-full flex flex-items-center flex-justify-center">
|
<view class="flex-full h-full flex flex-items-center flex-justify-center">
|
||||||
<!-- ChatTopWelcome不在可视区:显示并添加动画;在可视区:隐藏 -->
|
<!-- ChatTopWelcome不在可视区:显示并添加动画;在可视区:隐藏 -->
|
||||||
<view
|
<SpriteAnimator v-show="show" class="image-animated" :src="spriteStyle.ipSmallImage"
|
||||||
v-show="show"
|
:frameWidth="spriteStyle.frameWidth" :frameHeight="spriteStyle.frameHeight"
|
||||||
:class="['w-32 h-32', { 'image-animated': show }]"
|
:totalFrames="spriteStyle.totalFrames" :columns="spriteStyle.columns" :displayWidth="spriteStyle.displayWidth"
|
||||||
:style="getStyle"
|
:fps="16" />
|
||||||
></view>
|
<text v-show="show" :class="[
|
||||||
<text
|
'font-size-14 font-500 color-171717 ml-10',
|
||||||
v-show="show"
|
{ 'text-animated': show },
|
||||||
:class="[
|
]">
|
||||||
'font-size-14 font-500 color-171717 ml-10',
|
|
||||||
{ 'text-animated': show },
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
{{ config.name }}
|
{{ config.name }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -28,25 +24,33 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineProps, computed, defineExpose } from "vue";
|
import { ref, defineProps, computed, defineExpose } from "vue";
|
||||||
import { getCurrentConfig } from "@/constant/base";
|
import { getCurrentConfig } from "@/constant/base";
|
||||||
|
import SpriteAnimator from "@/components/Sprite/SpriteAnimator.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
mainPageDataModel: {
|
mainPageDataModel: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({
|
||||||
|
initPageImages: {},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const initPageImages = computed(() => {
|
||||||
|
return props.mainPageDataModel?.initPageImages || {};
|
||||||
|
});
|
||||||
|
|
||||||
const show = ref(false);
|
const show = ref(false);
|
||||||
const config = getCurrentConfig();
|
const config = getCurrentConfig();
|
||||||
const getStyle = computed(() => {
|
|
||||||
|
const spriteStyle = computed(() => {
|
||||||
|
const images = initPageImages.value;
|
||||||
return {
|
return {
|
||||||
"--ipSmallImageStep": config.ipSmallImageStep,
|
ipSmallImage: images.ipSmallImage ?? config.ipSmallImage,
|
||||||
"--ipSmallImageHeight": config.ipSmallImageHeight,
|
frameWidth: images.ipSmallImageWidth ?? config.ipSmallImageWidth,
|
||||||
"--ipSmallTime": config.ipSmallTime,
|
frameHeight: images.ipSmallImageHeight ?? config.ipSmallImageHeight,
|
||||||
backgroundImage: `url(${config.ipSmallImage})`,
|
totalFrames: images.ipSmallTotalFrames ?? config.ipSmallTotalFrames,
|
||||||
backgroundRepeat: "no-repeat",
|
columns: images.ipSmallColumns ?? config.ipSmallColumns,
|
||||||
backgroundSize: "32px auto",
|
displayWidth: 32,
|
||||||
backgroundPosition: "0 0",
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,18 @@
|
|||||||
// 图片从0%到100%动画
|
// 图片从0%到100%动画
|
||||||
.image-animated {
|
.image-animated {
|
||||||
animation: logo-scale 0.3s ease-in-out,
|
animation: logo-scale 0.3s ease-in-out;
|
||||||
sprite-play calc(var(--ipSmallTime) * 1s) steps(var(--ipSmallImageStep))
|
|
||||||
infinite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes logo-scale {
|
@keyframes logo-scale {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sprite-play {
|
|
||||||
0% {
|
|
||||||
background-position: 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
/* 117 帧 × 每帧高度约 32px,终点应为 -(117-1)*32 = -5421px */
|
|
||||||
background-position: 0 calc(var(--ipSmallImageHeight) * -1px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文字从0%到100%动画,从左到右
|
// 文字从0%到100%动画,从左到右
|
||||||
.text-animated {
|
.text-animated {
|
||||||
animation: text-fade-in 0.3s ease-in-out;
|
animation: text-fade-in 0.3s ease-in-out;
|
||||||
@@ -35,8 +23,9 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-20px);
|
transform: translateX(-20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,11 @@ v
|
|||||||
<template>
|
<template>
|
||||||
<view class="welcome-content border-box p-12">
|
<view class="welcome-content border-box p-12">
|
||||||
<view class="wrap rounded-20">
|
<view class="wrap rounded-20">
|
||||||
<view
|
<view class="flex flex-items-center flex-justify-between border-box pl-12 pr-12">
|
||||||
class="flex flex-items-center flex-justify-between border-box pl-12 pr-12"
|
<SpriteAnimator :src="spriteStyle.ipLargeImage" :frameWidth="spriteStyle.frameWidth"
|
||||||
>
|
:frameHeight="spriteStyle.frameHeight" :totalFrames="spriteStyle.totalFrames" :columns="spriteStyle.columns"
|
||||||
<view class="ip" :style="getStyle"></view>
|
:displayWidth="spriteStyle.displayWidth" :fps="16" />
|
||||||
<view
|
<view class="welcome-text font-size-14 font-500 font-family-misans-vf color-171717 line-height-24">
|
||||||
class="welcome-text font-size-14 font-500 font-family-misans-vf color-171717 line-height-24"
|
|
||||||
>
|
|
||||||
{{ welcomeContent }}
|
{{ welcomeContent }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -22,6 +20,7 @@ v
|
|||||||
import { defineProps, computed, getCurrentInstance, defineExpose } from "vue";
|
import { defineProps, computed, getCurrentInstance, defineExpose } from "vue";
|
||||||
import { getCurrentConfig } from "@/constant/base";
|
import { getCurrentConfig } from "@/constant/base";
|
||||||
import ChatMoreTips from "../ChatMoreTips/index.vue";
|
import ChatMoreTips from "../ChatMoreTips/index.vue";
|
||||||
|
import SpriteAnimator from "@/components/Sprite/SpriteAnimator.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
mainPageDataModel: {
|
mainPageDataModel: {
|
||||||
@@ -49,19 +48,24 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const getStyle = computed(() => {
|
const initPageImages = computed(() => {
|
||||||
const config = getCurrentConfig();
|
return props.mainPageDataModel?.initPageImages || {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = getCurrentConfig();
|
||||||
|
|
||||||
|
const spriteStyle = computed(() => {
|
||||||
|
const images = initPageImages.value;
|
||||||
return {
|
return {
|
||||||
"--ipLargeImageStep": config.ipLargeImageStep,
|
ipLargeImage: images.ipLargeImage ?? config.ipLargeImage,
|
||||||
"--ipLargeImageHeight": config.ipLargeImageHeight,
|
frameWidth: images.ipLargeImageWidth ?? config.ipLargeImageWidth,
|
||||||
"--ipLargeTime": config.ipLargeTime,
|
frameHeight: images.ipLargeImageHeight ?? config.ipLargeImageHeight,
|
||||||
backgroundImage: `url(${config.ipLargeImage})`,
|
totalFrames: images.ipLargeTotalFrames ?? config.ipLargeTotalFrames,
|
||||||
backgroundRepeat: "no-repeat",
|
columns: images.ipLargeColumns ?? config.ipLargeColumns,
|
||||||
backgroundSize: "158px auto",
|
displayWidth: 158,
|
||||||
backgroundPosition: "0 0",
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const welcomeContent = computed(() => props.mainPageDataModel.welcomeContent);
|
const welcomeContent = computed(() => props.mainPageDataModel.welcomeContent);
|
||||||
const guideWords = computed(() => props.mainPageDataModel.guideWords);
|
const guideWords = computed(() => props.mainPageDataModel.guideWords);
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,3 @@
|
|||||||
.wrap {
|
.wrap {
|
||||||
background-color: rgba(255, 255, 255, 0.5);
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ip {
|
|
||||||
position: relative;
|
|
||||||
flex: 0 0 158px;
|
|
||||||
width: 158px;
|
|
||||||
height: 134px;
|
|
||||||
animation: sprite-play calc(var(--ipLargeTime) * 1s)
|
|
||||||
steps(var(--ipLargeImageStep)) infinite;
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
background-color: #f9fcfd;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes sprite-play {
|
|
||||||
0% {
|
|
||||||
background-position: 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
/* 40 帧 × 每帧高度约 139px,终点应为 -(40-1)*139 = -5421px */
|
|
||||||
background-position: 0 calc(var(--ipLargeImageHeight) * -1px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,16 +2,9 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<ModuleTitle :title="recommendTheme.themeName" />
|
<ModuleTitle :title="recommendTheme.themeName" />
|
||||||
<view class="container-scroll">
|
<view class="container-scroll">
|
||||||
<view
|
<view v-for="(item, index) in recommendTheme.recommendPostsList" :key="index">
|
||||||
v-for="(item, index) in recommendTheme.recommendPostsList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<view class="mk-card-item" @click="sendReply(item)">
|
<view class="mk-card-item" @click="sendReply(item)">
|
||||||
<image
|
<image class="card-img" :src="item.coverPhoto" mode="widthFix"></image>
|
||||||
class="card-img"
|
|
||||||
:src="item.coverPhoto"
|
|
||||||
mode="widthFix"
|
|
||||||
></image>
|
|
||||||
<text class="card-text">{{ item.topic }}</text>
|
<text class="card-text">{{ item.topic }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -20,7 +13,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
|
import { SEND_MESSAGE_CONTENT_TEXT, SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
|
||||||
import { defineProps } from "vue";
|
import { defineProps } from "vue";
|
||||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||||||
|
|
||||||
@@ -32,8 +25,12 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const sendReply = (item) => {
|
const sendReply = (item) => {
|
||||||
const topic = item.userInputContent || item.topic.replace(/^#/, "");
|
if (item.userInputContentType && item.userInputContentType === '1') {
|
||||||
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, topic);
|
const commonItem = { type: item.userInputContent, title: item.topic }
|
||||||
|
uni.$emit(SEND_MESSAGE_COMMAND_TYPE, commonItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item.userInputContent);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -3,29 +3,18 @@
|
|||||||
<ModuleTitle :title="recommendTheme.themeName" />
|
<ModuleTitle :title="recommendTheme.themeName" />
|
||||||
|
|
||||||
<view class="container-scroll font-size-0 scroll-x whitespace-nowrap">
|
<view class="container-scroll font-size-0 scroll-x whitespace-nowrap">
|
||||||
<view
|
<view class="card-item bg-white inline-block rounded-20 mr-8"
|
||||||
class="card-item bg-white inline-block rounded-20 mr-8"
|
v-for="(item, index) in recommendTheme.recommendPostsList" :key="index" @click="sendReply(item)">
|
||||||
v-for="(item, index) in recommendTheme.recommendPostsList"
|
|
||||||
:key="index"
|
|
||||||
@click="sendReply(item)"
|
|
||||||
>
|
|
||||||
<view class="m-4 relative">
|
<view class="m-4 relative">
|
||||||
<image
|
<image class="card-img rounded-16 relative z-10" :src="item.coverPhoto" mode="aspectFill" />
|
||||||
class="card-img rounded-16 relative z-10"
|
|
||||||
:src="item.coverPhoto"
|
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<view class="shadow absolute rounded-16"></view>
|
<view class="shadow absolute rounded-16"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="card-text border-box">
|
<view class="card-text border-box">
|
||||||
<view class="color-171717 font-size-14 line-height-20 ellipsis-1">
|
<view class="font-size-11 color-99A0AE ellipsis-1">
|
||||||
{{ item.topic }}
|
{{ item.topic }}
|
||||||
</view>
|
</view>
|
||||||
<view class="font-size-11 color-99A0AE">
|
|
||||||
{{ item.userInputContent }}
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -34,7 +23,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps } from "vue";
|
import { defineProps } from "vue";
|
||||||
import { SEND_MESSAGE_CONTENT_TEXT } from "@/constant/constant";
|
import { SEND_MESSAGE_CONTENT_TEXT, SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
|
||||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -45,8 +34,12 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const sendReply = (item) => {
|
const sendReply = (item) => {
|
||||||
const topic = item.userInputContent || item.topic.replace(/^#/, "");
|
if (item.userInputContentType && item.userInputContentType === '1') {
|
||||||
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, topic);
|
const commonItem = { type: item.userInputContent, title: item.topic }
|
||||||
|
uni.$emit(SEND_MESSAGE_COMMAND_TYPE, commonItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item.userInputContent);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="webview">
|
<view>
|
||||||
<!-- 使用 NavBar 组件 -->
|
<web-view :src="webviewUrl" @message="handleH5Message"></web-view>
|
||||||
<TopNavBar title="网页浏览" @back="goBack" />
|
|
||||||
|
|
||||||
<!-- WebView 内容区域 -->
|
|
||||||
<view class="webview-content">
|
|
||||||
<web-view :src="webviewUrl"></web-view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
|
||||||
|
|
||||||
const webviewUrl = ref("");
|
const webviewUrl = ref("");
|
||||||
|
|
||||||
// 返回上一页
|
|
||||||
const goBack = () => {
|
|
||||||
uni.navigateBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 获取页面参数
|
// 获取页面参数
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
@@ -33,24 +21,26 @@ onMounted(() => {
|
|||||||
webviewUrl.value = decodeURIComponent(options.url);
|
webviewUrl.value = decodeURIComponent(options.url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleH5Message = (event) => {
|
||||||
|
const messageData = event.detail.data[0];
|
||||||
|
console.log("Received message from H5:", messageData);
|
||||||
|
// 根据需要处理H5传递过来的消息
|
||||||
|
const action = messageData.action;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case "navigateBack":
|
||||||
|
uni.navigateBack();
|
||||||
|
break;
|
||||||
|
case "navigateTo":
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log("Unknown action:", action);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
.webview {
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.webview-content {
|
|
||||||
flex: 1;
|
|
||||||
margin-top: calc(44px + var(--status-bar-height));
|
|
||||||
}
|
|
||||||
|
|
||||||
.webview-content {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
13
src/request/api/GetServiceUrlApi.js
Normal file
13
src/request/api/GetServiceUrlApi.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import request from "../base/request";
|
||||||
|
import { proUrl } from "../base/baseUrl";
|
||||||
|
import { useAppStore } from "@/store";
|
||||||
|
|
||||||
|
export const getServiceUrl = async (versionValue) => {
|
||||||
|
const apiUrl = proUrl + "/hotelBiz/mainScene/getServiceUrl";
|
||||||
|
const res = await request.post(apiUrl, { versionValue: versionValue });
|
||||||
|
if (res && res.code == 0 && res.data) {
|
||||||
|
const appStore = useAppStore();
|
||||||
|
appStore.setServerConfig(res.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
import request from "../base/request";
|
|
||||||
import { isZhiNian } from "@/constant/base";
|
import { isZhiNian } from "@/constant/base";
|
||||||
import { useAppStore } from "@/store";
|
import { useAppStore } from "@/store";
|
||||||
import { devUrl, proUrl, wssDevUrl } from "../base/baseUrl";
|
import { devUrl, wssDevUrl } from "./baseUrl";
|
||||||
|
import { getServiceUrl } from "../api/GetServiceUrlApi";
|
||||||
|
|
||||||
/// 版本号, 每次发版本前增加
|
/// 版本号, 每次发版本前增加
|
||||||
const versionValue = "1.0.3";
|
const versionValue = "1.0.4";
|
||||||
|
|
||||||
|
/// 是否是测试版本, 测试版本为true, 发布版本为false
|
||||||
|
const developVersion = false;
|
||||||
|
|
||||||
// 获取服务地址
|
// 获取服务地址
|
||||||
const getEvnUrl = async () => {
|
const getEvnUrl = async () => {
|
||||||
/// 智念客户端不需要获取环境地址
|
/// 智念客户端不需要获取环境地址
|
||||||
if (isZhiNian) {
|
if (isZhiNian || developVersion) {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
appStore.setServerConfig({
|
appStore.setServerConfig({
|
||||||
baseUrl: devUrl, // 服务器基础地址
|
baseUrl: devUrl, // 服务器基础地址
|
||||||
@@ -18,12 +21,8 @@ const getEvnUrl = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiUrl = proUrl + "/hotelBiz/mainScene/getServiceUrl";
|
/// 正式环境获取服务地址
|
||||||
const res = await request.post(apiUrl, { versionValue: versionValue });
|
await getServiceUrl(versionValue);
|
||||||
if (res && res.code == 0 && res.data) {
|
|
||||||
const appStore = useAppStore();
|
|
||||||
appStore.setServerConfig(res.data);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getEvnUrl };
|
export { getEvnUrl };
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { goLogin } from "../../hooks/useGoLogin";
|
|
||||||
import { getCurrentConfig } from "@/constant/base";
|
import { getCurrentConfig } from "@/constant/base";
|
||||||
import { useAppStore } from "@/store";
|
import { useAppStore } from "@/store";
|
||||||
import { NOTICE_EVENT_LOGOUT } from "@/constant/constant";
|
import { NOTICE_EVENT_LOGOUT } from "@/constant/constant";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export function navigateTo(url, args) {
|
|||||||
// 如果有额外参数,拼接到URL后面
|
// 如果有额外参数,拼接到URL后面
|
||||||
const paramString = objectToUrlParams(args);
|
const paramString = objectToUrlParams(args);
|
||||||
if (paramString) {
|
if (paramString) {
|
||||||
if (targetUrl.contains("?")) {
|
if (typeof targetUrl === "string" && targetUrl.includes("?")) {
|
||||||
targetUrl += "&";
|
targetUrl += "&";
|
||||||
} else {
|
} else {
|
||||||
targetUrl += "?";
|
targetUrl += "?";
|
||||||
@@ -14,6 +14,7 @@ export function navigateTo(url, args) {
|
|||||||
targetUrl += paramString;
|
targetUrl += paramString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log("Navigating to URL:", targetUrl);
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: "/pages/webview/index?url=" + encodeURIComponent(targetUrl),
|
url: "/pages/webview/index?url=" + encodeURIComponent(targetUrl),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,3 +21,7 @@
|
|||||||
.h-24 {
|
.h-24 {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h72 {
|
||||||
|
height: 72px;
|
||||||
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-vw-24 {
|
||||||
|
width: calc(100vw - 24px);
|
||||||
|
}
|
||||||
|
|
||||||
.w-24 {
|
.w-24 {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
@@ -22,6 +26,12 @@
|
|||||||
width: 60px;
|
width: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.w-80 {
|
.w-80 {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-102 {
|
||||||
|
width: 102px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user