fix: 修复按钮问题
This commit is contained in:
parent
9f24fec9d6
commit
316e8101c3
BIN
AIchat.rar
BIN
AIchat.rar
Binary file not shown.
15
src/App.vue
15
src/App.vue
@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
const { statusBarHeight } = useStatus()
|
||||
import { useStatus } from '@/store/status'
|
||||
|
||||
onLaunch(() => {
|
||||
console.log('App Launch')
|
||||
@ -18,7 +20,18 @@ onHide(() => {
|
||||
button::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/*解决阅览图片关闭按钮会显示在状态栏区域的问题*/
|
||||
#u-a-p > div > div {
|
||||
margin-top: var(--statusBarHeight);
|
||||
}
|
||||
/*不显示滚动条的类*/
|
||||
.no-scroll {
|
||||
-ms-overflow-style: none; /* IE 和 Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
.no-scroll::-webkit-scrollbar {
|
||||
display: none; /* Webkit 浏览器 */
|
||||
}
|
||||
swiper,
|
||||
scroll-view {
|
||||
flex: 1;
|
||||
|
@ -8,7 +8,7 @@
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col h-screen bg-#ffffff">
|
||||
<div class="flex flex-col h-screen bg-#ffffff tops">
|
||||
<!-- Navigation Bar -->
|
||||
<div
|
||||
class="flex-none flex items-center justify-between px-5 py-3 bg-white shadow-md h-20 pt-10 z-999 fixed top-0 w-full box-border"
|
||||
@ -76,6 +76,7 @@
|
||||
msg.role === 'assistant'
|
||||
? 'bg-[#f9f8fd] text-black shadow '
|
||||
: 'bg-[#45299e] text-white ',
|
||||
msg.type === 'text' ? 'pr-0' : 'pr-3',
|
||||
]"
|
||||
>
|
||||
<wd-loading
|
||||
@ -140,6 +141,12 @@
|
||||
:key="fileIdx"
|
||||
style="flex: 0 0 6rem"
|
||||
class="relative text-xs h-12 px-2 py-2 rounded-md overflow-hidden mr-1 bg-white c-black"
|
||||
:class="{
|
||||
'w-25 h-15': msg.content.length == 1,
|
||||
'w-50 h-15': msg.content.length == 2,
|
||||
'w-30 h-15 ': msg.content.length == 3,
|
||||
'h-15 flex-grow-0 flex-shrink-0 basis-10 mr-1': msg.content.length >= 4,
|
||||
}"
|
||||
@click="previewFile(file.url)"
|
||||
>
|
||||
<view>{{ file.name }}</view>
|
||||
@ -193,11 +200,25 @@
|
||||
<div
|
||||
:class="[
|
||||
'fixed bottom-0 left-0 right-0 bg-white z-[80] overflow-hidden transition-all duration-300',
|
||||
showActions ? (uploadList.length ? 'h-60' : 'h-40') : 'h-20',
|
||||
showActions ? (uploadList.length ? 'h-40' : 'h-40') : 'h-20',
|
||||
]"
|
||||
>
|
||||
<!-- 上传列表 -->
|
||||
<div v-if="uploadList.length" class="flex px-4 py-2 overflow-x-auto space-x-3 bg-transparent">
|
||||
<div
|
||||
v-if="uploadList.length"
|
||||
:class="[
|
||||
'flex px-4 py-2 overflow-x-auto space-x-3 bg-transparent',
|
||||
showActions
|
||||
? uploadList.length
|
||||
? ' fixed bottom-40'
|
||||
: 'fixed bottom-19'
|
||||
: 'fixed bottom-19',
|
||||
]"
|
||||
:style="{
|
||||
transform: `rotate(0deg)`,
|
||||
transition: 'transform 0.3s ease',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-for="item in uploadList"
|
||||
:key="item.id"
|
||||
@ -250,8 +271,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 知识库-->
|
||||
|
||||
<!-- 知识库-->
|
||||
<div
|
||||
@click="toggleKnowledge"
|
||||
v-if="!uploadList.length"
|
||||
@ -280,6 +301,7 @@
|
||||
<view class="flex items-center px-4 py-2.5 border-t border-t-solid border-[#E7E7E7]">
|
||||
<input
|
||||
v-model="inputText"
|
||||
@focus="onFocus"
|
||||
@keyup.enter="sendText('')"
|
||||
placeholder="想对我说点什么~"
|
||||
class="flex-1 h-10 px-3 border border-gray-100 bg-[#f9f9f9] rounded-1 focus:outline-none"
|
||||
@ -308,8 +330,8 @@
|
||||
<view
|
||||
v-show="showActions"
|
||||
:class="[
|
||||
'flex justify-around items-center h-20 bg-white border-t border-t-solid border-[#E7E7E7]',
|
||||
showActions ? (uploadList.length ? 'pt-1' : 'pt-1') : 'pt-0',
|
||||
'flex justify-around items-center h-10 bg-white border-t border-t-solid border-[#E7E7E7]',
|
||||
showActions ? (uploadList.length ? 'pt-10' : 'pt-10') : 'pt-0',
|
||||
]"
|
||||
>
|
||||
<view class="flex flex-col items-center">
|
||||
@ -401,6 +423,7 @@ interface IMessage {
|
||||
timestamp: Date
|
||||
}
|
||||
const userAvatar = ref('')
|
||||
const chatMode = ref('tongyi-app')
|
||||
|
||||
const baseUrl = getEnvBaseUrl()
|
||||
const messages = reactive<IMessage[]>([])
|
||||
@ -474,7 +497,7 @@ async function goChat(listUuid: string) {
|
||||
await fetchHistoryDiets(listUuid)
|
||||
showPopup.value = false
|
||||
}
|
||||
|
||||
// qwen-vl-plus
|
||||
/** 1. 创建聊天会话 */
|
||||
const listUuid = ref('')
|
||||
|
||||
@ -484,18 +507,15 @@ async function createChatSession() {
|
||||
url: `${baseUrl}/chat/create`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
gptModel: 'gpt-4-vision-preview',
|
||||
gptModel: chatMode.value,
|
||||
},
|
||||
header: {
|
||||
Authorization: token.value,
|
||||
},
|
||||
})
|
||||
// 如果后台返回新的会话信息,可以在这里处理,比如拿到 listUuid 等
|
||||
console.log('createChatSession →', createResp)
|
||||
listUuid.value = createResp.data.data.listUuid
|
||||
} catch (err) {
|
||||
console.error('createChatSession error:', err)
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
// ------------------
|
||||
// 拉取历史记录接口(替换为你自己的 API)
|
||||
@ -532,21 +552,145 @@ async function fetchHistoryDiets(value) {
|
||||
method: 'POST',
|
||||
data: {
|
||||
listUuid: value,
|
||||
gptModel: 'gpt-4-vision-preview',
|
||||
gptModel: chatMode.value,
|
||||
},
|
||||
header: {
|
||||
Authorization: token.value,
|
||||
},
|
||||
})
|
||||
if (resp.data) {
|
||||
rawList.value = resp.data
|
||||
console.log('fetchHistoryLisssst →', rawList.value)
|
||||
console.log(resp, '/**************resp*********************/')
|
||||
if (resp && resp.data) {
|
||||
const rawList = resp.data.data // 假设后端直接返回消息数组
|
||||
const newMessages = parseBackendMessages(rawList)
|
||||
// 用解析后的消息替换当前消息列表
|
||||
messages.splice(0, messages.length, ...newMessages)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('fetchHistoryList error:', err)
|
||||
}
|
||||
}
|
||||
const token = ref<string>('')
|
||||
|
||||
function parseBackendMessages(rawList: any[]): IMessage[] {
|
||||
const messageList: IMessage[] = []
|
||||
|
||||
rawList.forEach((item) => {
|
||||
const rawContent: string = item.text ?? item.content ?? item.message ?? ''
|
||||
// 先尝试 map[...] 的老逻辑
|
||||
let parts: ParsedPart[] | null = tryParseMapFormat(rawContent)
|
||||
|
||||
// 如果没命中 map[...],再看看是不是一个标准的 JSON 数组字符串
|
||||
if (!parts && rawContent.startsWith('[') && rawContent.endsWith(']')) {
|
||||
try {
|
||||
const arr = JSON.parse(rawContent) as Array<{ text: string; type: string }>
|
||||
if (Array.isArray(arr)) {
|
||||
parts = arr.map((el) => {
|
||||
if (el.type === 'text') {
|
||||
return { type: 'text', content: el.text }
|
||||
}
|
||||
if (el.type === 'image_url' || el.type === 'image') {
|
||||
return {
|
||||
type: 'image',
|
||||
content: [{ url: el.text, uploadFileType: 'image' }],
|
||||
}
|
||||
}
|
||||
// 其他类型按需扩展
|
||||
return { type: el.type, content: el.text }
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
// 解析失败就继续下面的 fallback
|
||||
}
|
||||
}
|
||||
|
||||
if (parts) {
|
||||
// 拆分成多条消息推入
|
||||
parts.forEach((part) => {
|
||||
messageList.push({
|
||||
role: item.role,
|
||||
type: part.type as any, // 'text' 或 'image'
|
||||
content: part.content,
|
||||
timestamp: (item.CreatedAt ?? 0) * 1000,
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// 你原来的 fallback 分支(单条,直接塞 content,type 也补成 'text')
|
||||
messageList.push({
|
||||
role: item.role,
|
||||
type: 'text',
|
||||
content: rawContent,
|
||||
timestamp: (item.CreatedAt ?? 0) * 1000,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return messageList
|
||||
}
|
||||
interface ParsedPart {
|
||||
type: string
|
||||
content: string | UploadFile[]
|
||||
}
|
||||
|
||||
function tryParseMapFormat(str: string): ParsedPart[] | null {
|
||||
if (!str || !str.startsWith('[') || !str.endsWith(']') || !str.includes('map[')) {
|
||||
return null // 不符合 [map[...] ...] 格式
|
||||
}
|
||||
|
||||
const result: ParsedPart[] = []
|
||||
// 提取所有 map[...] 子串
|
||||
const pattern = /map\[([^\]]+)\]/g
|
||||
let match: RegExpExecArray | null
|
||||
while ((match = pattern.exec(str)) !== null) {
|
||||
const contentBlock = match[1] // 如 "text:这种 type:text"
|
||||
const typeIndex = contentBlock.indexOf(' type:')
|
||||
if (typeIndex === -1) {
|
||||
continue // 安全检查,正常情况下一定有 ' type:' 分隔
|
||||
}
|
||||
// 拆分内容部分和类型部分
|
||||
const contentPart = contentBlock.substring(0, typeIndex).trim() // "text:这种"
|
||||
const typeValue = contentBlock.substring(typeIndex + 6).trim() // 跳过 " type:" 得到 "text" 或 "image_url"
|
||||
// 解析内容键和值
|
||||
const colonIndex = contentPart.indexOf(':')
|
||||
if (colonIndex === -1) {
|
||||
continue
|
||||
}
|
||||
const key = contentPart.substring(0, colonIndex).trim() // 键,比如 "text" 或 "image_url"
|
||||
let value = contentPart.substring(colonIndex + 1).trim() // 值,比如 "这种" 或 "https://cdn.xx/xxx.jpg"
|
||||
// 去掉包裹在值两端的引号(如果有的话)
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.substring(1, value.length - 1)
|
||||
}
|
||||
|
||||
// 根据类型构造 ParsedPart 对象
|
||||
if (typeValue === 'text' && key === 'text') {
|
||||
result.push({
|
||||
type: 'text',
|
||||
content: value,
|
||||
})
|
||||
} else if (typeValue === 'image_url' && key === 'image_url') {
|
||||
// 将图片URL封装为 UploadFile 对象数组
|
||||
result.push({
|
||||
type: 'image', // 前端统一用 'image' 作为图片消息类型
|
||||
content: [{ url: value, uploadFileType: 'image' }],
|
||||
})
|
||||
} else {
|
||||
// 其他类型的内容,可根据需要扩展处理
|
||||
result.push({
|
||||
type: typeValue,
|
||||
content: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 如果成功解析出至少一个片段,则返回数组;否则返回 null
|
||||
return result.length > 0 ? result : null
|
||||
}
|
||||
|
||||
const token = ref<string>(
|
||||
'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941ca1430937103230a1e32a1715f569f3efdbe6f8cb8b7b8642bd679668081b9b08f693d1b5be6002d936ec51e1e3e0c4927de9e32ac99a109b326e5d2bda27ec87624bb416ec70d2a95a2e190feeba9f0d6bae8571b3dfe89c824712344759a8f2bff9d70747c52525cf6a5614f9c770bca461a9b9c247b6dca97bcf83bbaf99bb726752c4fe1e9a4aa7de5c4cf3e88a3e480801280d45cdc124f9d8221105d852945dc6ce10bc1647e4f09dff4d52ffdfc878a18b3738809e20de39acfd5430450f2bc3741057dd4ce71ccf64ea02f6a91fd001fa7bde90187008f19e848c70a002c37df28be05b4790e962f001a1361e90f1423dfc5b018ca9fac85ad2fafaef6',
|
||||
)
|
||||
const userInfo = ref<any>({})
|
||||
const refreshToken = ref<string>('')
|
||||
const statusBarHeight = ref<number>(0)
|
||||
@ -558,7 +702,7 @@ onMounted(() => {
|
||||
|
||||
const init = async () => {
|
||||
const wv = plus.webview.currentWebview()
|
||||
token.value = wv.token || uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN
|
||||
// token.value = wv.token || uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN
|
||||
userInfo.value = JSON.parse(wv.userInfo) || {}
|
||||
refreshToken.value = wv.refreshToken || uni.getStorageSync('refreshToken')
|
||||
statusBarHeight.value = wv.statusBarHeight || uni.getSystemInfoSync().statusBarHeight
|
||||
@ -568,23 +712,6 @@ onMounted(() => {
|
||||
await fetchHistoryList()
|
||||
}
|
||||
init()
|
||||
|
||||
// // 2. 如果在 Plus 环境里,等 plusready
|
||||
// if (window.plus && plus.webview) {
|
||||
// document.addEventListener('plusready', init, false)
|
||||
// // plusready 可能已经触发过,直接再调用一次以防万一
|
||||
// if (plus.webview.currentWebview()) {
|
||||
// init()
|
||||
// }
|
||||
// }
|
||||
// // 3. 普通 H5 调试,直接从 storage/SystemInfo 拿
|
||||
// else {
|
||||
// token.value = uni.getStorageSync('token') || import.meta.env.VITE_DEV_TOKEN
|
||||
// userInfo.value = uni.getStorageSync('userInfo')
|
||||
// refreshToken.value = uni.getStorageSync('refreshToken')
|
||||
// statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight
|
||||
// createChatSession().then(fetchHistoryList)
|
||||
// }
|
||||
})
|
||||
|
||||
function scrollToBottom() {
|
||||
@ -651,6 +778,7 @@ async function newChat() {
|
||||
}
|
||||
const rotation = ref(0)
|
||||
function toggleActions() {
|
||||
closeKeyboard()
|
||||
showActions.value = !showActions.value
|
||||
rotation.value += 45
|
||||
scrollToBottom()
|
||||
@ -661,6 +789,7 @@ const uploadFileTypeEm = {
|
||||
image: 'image',
|
||||
video: 'video',
|
||||
file: 'file',
|
||||
text: 'text',
|
||||
}
|
||||
|
||||
// 上传配置
|
||||
@ -914,7 +1043,11 @@ const msgLoading = ref(true)
|
||||
async function sendText(msgData) {
|
||||
msgLoading.value = true
|
||||
const text = inputText.value.trim()
|
||||
if (!text) {
|
||||
const dataBlo = toRaw(msgData)
|
||||
console.log(dataBlo)
|
||||
if (!text && dataBlo == '') {
|
||||
msgLoading.value = false
|
||||
|
||||
uni.showToast({ title: '请输入信息', icon: 'error' })
|
||||
|
||||
return
|
||||
@ -935,12 +1068,14 @@ async function sendText(msgData) {
|
||||
}
|
||||
|
||||
// 添加用户文本消息
|
||||
addMessage({
|
||||
role: 'user',
|
||||
type: 'text',
|
||||
content: text,
|
||||
timestamp: new Date(),
|
||||
})
|
||||
addMessage(
|
||||
msgData || {
|
||||
role: 'user',
|
||||
type: 'text',
|
||||
content: text,
|
||||
timestamp: new Date(),
|
||||
},
|
||||
)
|
||||
|
||||
//图片、视频、文件分开发送
|
||||
if (tempUploadList.length > 0) {
|
||||
@ -969,11 +1104,12 @@ async function sendText(msgData) {
|
||||
showImageMask.value = showMoreImgMask
|
||||
} else {
|
||||
//更新上下文消息
|
||||
historyUserMsgs.push({
|
||||
role: 'user',
|
||||
content: text,
|
||||
timestamp: new Date(),
|
||||
})
|
||||
!msgData &&
|
||||
historyUserMsgs.push({
|
||||
role: 'user',
|
||||
content: text,
|
||||
timestamp: new Date(),
|
||||
})
|
||||
}
|
||||
|
||||
inputText.value = ''
|
||||
@ -987,19 +1123,19 @@ async function sendText(msgData) {
|
||||
timestamp: new Date(),
|
||||
}
|
||||
addMessage(aiMsg)
|
||||
|
||||
//清除上传列表
|
||||
uploadList.splice(0, uploadList.length)
|
||||
// resds.value = historyUserMsgs
|
||||
|
||||
const body: IGptRequestBody = {
|
||||
model: 'gpt-4-vision-preview',
|
||||
model: chatMode.value,
|
||||
max_tokens: 1000,
|
||||
temperature: 1,
|
||||
listUuid: listUuid.value,
|
||||
top_p: 1,
|
||||
presence_penalty: 0,
|
||||
frequency_penalty: 0,
|
||||
messages: msgData || historyUserMsgs,
|
||||
messages: msgData ? [msgData] : historyUserMsgs,
|
||||
stream: true,
|
||||
}
|
||||
|
||||
@ -1011,6 +1147,7 @@ async function sendText(msgData) {
|
||||
headers: { 'Content-Type': 'application/json', Authorization: token.value },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
|
||||
const reader = resp.body!.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buffer = ''
|
||||
@ -1021,14 +1158,17 @@ async function sendText(msgData) {
|
||||
done = streamDone
|
||||
if (value) {
|
||||
buffer += decoder.decode(value, { stream: true })
|
||||
const parts = buffer.split('data: ')
|
||||
buffer = parts.pop()!
|
||||
for (const part of parts) {
|
||||
scrollToBottom()
|
||||
console.log('1', aiMsg.content)
|
||||
const chunk = part.trim()
|
||||
const lines = buffer.split(/\r?\n/)
|
||||
buffer = lines.pop()!
|
||||
|
||||
for (const line of lines) {
|
||||
// 只处理以 "data: " 开头的行
|
||||
if (!line.startsWith('data: ')) continue
|
||||
const chunk = line.slice(6).trim()
|
||||
|
||||
if (chunk === '[DONE]') {
|
||||
done = true
|
||||
console.log('sss')
|
||||
break
|
||||
}
|
||||
try {
|
||||
@ -1045,13 +1185,16 @@ async function sendText(msgData) {
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
//更新上下文消息
|
||||
done && historyUserMsgs.push(aiMsg)
|
||||
}
|
||||
}
|
||||
|
||||
//更新上下文消息
|
||||
historyUserMsgs.push(aiMsg)
|
||||
scrollToBottom()
|
||||
} catch (err) {
|
||||
aiMsg.content = '请重新发送'
|
||||
//更新messages消息
|
||||
messages[messages.length - 1] = { ...aiMsg }
|
||||
console.error(err)
|
||||
} finally {
|
||||
loading.value = false
|
||||
@ -1075,18 +1218,35 @@ function copyText(msg: IMessage) {
|
||||
}
|
||||
|
||||
function refreshText() {
|
||||
const lastUserMsg = historyUserMsgs[historyUserMsgs.length - 2]
|
||||
// resds.value = lastUserMsg
|
||||
|
||||
const lastUserMsg = historyUserMsgs[historyUserMsgs.length - 1]
|
||||
lastUserMsg.timestamp = new Date()
|
||||
sendText(lastUserMsg)
|
||||
}
|
||||
|
||||
const knowledgeOpen = ref(false)
|
||||
function toggleKnowledge() {
|
||||
console.error('44444', chatMode.value)
|
||||
if (chatMode.value == 'tongyi-app') {
|
||||
chatMode.value = 'qwen-vl-plus'
|
||||
} else {
|
||||
chatMode.value = 'tongyi-app'
|
||||
}
|
||||
knowledgeOpen.value = !knowledgeOpen.value
|
||||
showActions.value = false
|
||||
rotation.value = 0
|
||||
}
|
||||
|
||||
//收起键盘
|
||||
const closeKeyboard = () => {
|
||||
uni.hideKeyboard()
|
||||
rotation.value = 0
|
||||
}
|
||||
|
||||
//输入框聚焦事件
|
||||
const onFocus = () => {
|
||||
showActions.value = false
|
||||
rotation.value = 0
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -1191,4 +1351,8 @@ function toggleKnowledge() {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tops {
|
||||
padding-top: var(--status-bar-height);
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="flex flex-col h-screen bg-#ffffff">
|
||||
<view class="flex flex-col h-screen bg-#ffffff tops">
|
||||
<view
|
||||
class="flex-none flex items-center justify-between px-5 py-3 bg-white shadow-md h-20 pt-10 z-999 fixed top-0 w-full box-border"
|
||||
>
|
||||
@ -64,4 +64,8 @@ onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.tops {
|
||||
padding-top: var(--status-bar-height);
|
||||
}
|
||||
</style>
|
||||
|
15
src/store/status/index.js
Normal file
15
src/store/status/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
import {ref} from 'vue'
|
||||
import {createGlobalState, useStorage} from "@vueuse/core";
|
||||
import {uniStorage} from "@/utils/uniStorage";
|
||||
export const useStatus =createGlobalState(()=>{
|
||||
const currentNavbar=ref({title:'',url:''})
|
||||
const applyTabbarIndex=ref(0)
|
||||
const statusBarHeight = ref(window?.plus?.navigator?.getStatusbarHeight() ?? 0)
|
||||
const tabBarIndex = useStorage('tabBarIndex', 0, uniStorage)
|
||||
return {
|
||||
statusBarHeight,
|
||||
applyTabbarIndex,
|
||||
currentNavbar,
|
||||
tabBarIndex
|
||||
}
|
||||
})
|
11
src/utils/uniStorage.js
Normal file
11
src/utils/uniStorage.js
Normal file
@ -0,0 +1,11 @@
|
||||
export const uniStorage = {
|
||||
getItem(key) {
|
||||
return uni.getStorageSync(key) || null
|
||||
},
|
||||
setItem(key, value) {
|
||||
return uni.setStorageSync(key, value)
|
||||
},
|
||||
removeItem(key) {
|
||||
return uni.removeStorageSync(key)
|
||||
},
|
||||
}
|
Loading…
Reference in New Issue
Block a user