chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,340 @@
<template>
<view class="h-full flex flex-col border-b">
<!-- 顶部导航栏 -->
<custom-nav-bar :title="t('Mobile.Nav.home')" className="border-b">
<template v-slot:left>
<view class="flex flex-row items-center gap-4">
<header-menu
v-if="isLoggedIn"
:userInfo="userInfo"
ref="headerMenuRef"
/>
<view v-else class="login-btn-wrapper" @click="handleLogin">
<text class="login-btn-text">{{
t("Mobile.Common.loginRegister")
}}</text>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="icon-search-box" @click="handleSearch">
<text class="iconfont iconfont icon-Search font-48"></text>
</view>
<!-- #endif -->
</view>
</template>
<!-- #ifdef H5 || WEB -->
<template v-slot:right>
<view class="icon-search-box" @click="handleSearch">
<text class="iconfont iconfont icon-Search font-48"></text>
</view>
</template>
<!-- #endif -->
</custom-nav-bar>
<uni-notice-bar
v-if="!isLoggedIn"
single
show-close
show-icon
:text="t('Mobile.Common.noticeExperience')"
></uni-notice-bar>
<!-- 未登录时只显示智能体列表,不显示标签页 -->
<agent-list-content
v-if="!isLoggedIn"
class="h-full w-full"
ref="agentListContentRef"
:is-logged-in="isLoggedIn"
@agent-click="handleAgentClick"
/>
<!-- 登录后显示标签页:最近使用 + 会话记录 -->
<pane-tabs
v-if="isLoggedIn"
:key="currentLang"
v-model="activeTab"
:lazy-load="false"
with-bottom-padding
@change="handleTabChange"
>
<pane-tab key-value="recent" tab="Mobile.Common.recentUsed">
<agent-list-content
class="h-full w-full"
ref="agentListContentRef"
:is-logged-in="isLoggedIn"
@agent-click="handleAgentClickLast"
/>
</pane-tab>
<pane-tab
key-value="history"
tab="Mobile.Common.conversationHistory"
>
<conversation-list-content
class="h-full w-full"
ref="conversationListContentRef"
:is-logged-in="isLoggedIn"
@conversation-click="handleConversationClick"
/>
</pane-tab>
</pane-tabs>
<!-- 登录弹窗 -->
<auth-login-popup ref="loginPopupRef" />
</view>
</template>
<script setup lang="uts">
import { SUCCESS_CODE } from "@/constants/codes.constants.uts";
import { apiUserInfo } from "@/servers/account";
import type { AgentInfo } from "@/types/interfaces/agent";
import HeaderMenu from "./header-menu/header-menu.uvue";
import AgentListContent from "./agent-list-content/agent-list-content.uvue";
import ConversationListContent from "./conversation-list-content/conversation-list-content.uvue";
import type { UserInfo } from "@/types/interfaces/login";
import { apiTenantConfig } from "@/servers/account";
import { onAddToFavorites } from "@dcloudio/uni-app";
import {
getCurrentPagePath,
jumpToAgentDetailPage,
} from "@/utils/commonBusiness";
import AuthLoginPopup from "@/components/auth-login-popup/auth-login-popup.uvue";
import { useAuthInterceptor } from "@/hooks/useAuthInterceptor";
import { getCurrentPageFullPath } from "@/utils/common";
import { setCurrentPageNavigationBarTitle } from "@/utils/system";
import PaneTabs from "@/components/pane-tabs/pane-tabs.uvue";
import PaneTab from "@/components/pane-tabs/pane-tab.uvue";
import { TENANT_CONFIG_INFO } from "@/constants/home.constants";
import { useI18n, applyTabBarI18n } from "@/utils/i18n";
const { t, syncLanguageFromUser } = useI18n();
const activeTab = ref("recent");
// 分享标题
const shareTitle = ref("");
const fallbackShareTitle = computed(() => t("Mobile.Nav.home"));
const handleTabChange = (key: string) => {
if (key === "recent" && agentListContentRef.value) {
// 切换到最近使用时加载数据
agentListContentRef.value.loadData();
} else if (key === "history" && conversationListContentRef.value) {
// 切换到会话记录时加载数据
conversationListContentRef.value.loadData();
}
};
// 处理会话项点击
const handleConversationClick = (item: any) => {
// 跳转到智能体详情页面,并传递消息数据
jumpToAgentDetailPage(item.agentId, item.id);
};
// 头部菜单ref
const headerMenuRef = ref<any>(null);
// 智能体列表组件ref
const agentListContentRef = ref<any>(null);
// 会话列表组件ref
const conversationListContentRef = ref<any>(null);
// 使用登录拦截 composable
const {
loginPopupRef,
handleAgentClick: baseHandleAgentClick,
checkAuthAndShowPopup,
hasToken,
} = useAuthInterceptor();
// 包装 handleAgentClick 以适配 AgentInfo 类型
const handleAgentClick = (info: AgentInfo) => {
baseHandleAgentClick({
agentId: info.agentId,
name: info.name,
agentType: info.agentType,
icon: info.icon, // 跳转临时会话页面时使用
description: info.description, // 跳转临时会话页面时使用
});
};
// 最近使用
const handleAgentClickLast = (info: AgentInfo) => {
const { lastConversationId, agentId, name, agentType } = info || {};
if (lastConversationId) {
jumpToAgentDetailPage(agentId, lastConversationId);
} else {
baseHandleAgentClick({
agentId: agentId,
name: name,
agentType: agentType,
icon: info.icon, // 跳转临时会话页面时使用
description: info.description, // 跳转临时会话页面时使用
});
}
};
// 处理登录点击
const handleLogin = () => {
// #ifdef MP-WEIXIN
if (loginPopupRef.value) {
loginPopupRef.value.open();
}
// #endif
// #ifdef H5 || WEB
const currentUrl = getCurrentPageFullPath();
uni.navigateTo({
url:
"/subpackages/pages/login/login?redirect=" +
encodeURIComponent(currentUrl),
});
// #endif
};
// 用户信息
const userInfo = ref<UserInfo>();
// 判断是否登录
const isLoggedIn = ref<boolean>(false);
// 查询当前登录用户信息
const fetchUserInfo = async () => {
const res = await apiUserInfo();
const { code, data } = res || {};
if (code === SUCCESS_CODE) {
userInfo.value = data;
await syncLanguageFromUser(data?.lang || "");
}
};
// 设置分享标题
const setCurrentShareTitle = async () => {
// 获取本地用户配置
const tenantConfigInfoString = await uni.getStorageSync(TENANT_CONFIG_INFO);
if (tenantConfigInfoString) {
try {
const { siteName, siteDescription } = JSON.parse(
tenantConfigInfoString,
);
const titleList = [];
if (siteName) {
titleList.push(siteName);
}
if (siteDescription) {
titleList.push(siteDescription);
}
shareTitle.value = titleList.join(" ");
} catch (error) {
console.error("获取本地用户配置失败:", error);
}
}
};
onLoad((options: { cId?: string; fileProxyUrl?: string }) => {
// 检测是否为文件预览分享跳转
// #ifdef MP-WEIXIN
if (options?.cId && options?.fileProxyUrl) {
// 跳转到文件预览页面
// 注意fileProxyUrl 在分享时已经被 encodeURIComponent 编码过了
// 这里不需要再次编码,直接传递即可
uni.navigateTo({
url: `/subpackages/pages/file-preview-page/file-preview-page?cId=${options.cId}&fileProxyUrl=${encodeURIComponent(options.fileProxyUrl)}`,
});
return;
}
// #endif
// 设置当前页面导航栏标题
setCurrentPageNavigationBarTitle();
// 设置分享标题
setCurrentShareTitle();
});
onPageShow(async () => {
// 确保每次回到首页都刷新一次 TabBar 翻译,
// 解决语言切换重载后 TabBar 对象可能未就绪导致 uni.setTabBarItem 失效的问题。
applyTabBarI18n();
const loggedIn = await hasToken();
isLoggedIn.value = loggedIn || false;
// 如果是登录状态,需要等待 pane-tabs 内的组件初始化
if (isLoggedIn.value) {
await nextTick();
fetchUserInfo();
}
});
// 处理搜索
const handleSearch = () => {
// 检查登录状态,如果未登录则显示登录弹窗
if (!checkAuthAndShowPopup()) {
return;
}
const currentUrl = getCurrentPagePath();
uni.navigateTo({
url:
"/subpackages/pages/agent-search/agent-search?type=Home&backUrl=" +
encodeURIComponent(currentUrl),
});
};
// #ifdef MP-WEIXIN
// 转发给朋友
onShareAppMessage(() => {
return {
title: shareTitle.value || fallbackShareTitle.value,
path: "/pages/index/index",
};
});
// 收藏
onAddToFavorites(() => {
return {
title: shareTitle.value || fallbackShareTitle.value,
};
});
// #endif
onHide(() => {
if (headerMenuRef.value) {
headerMenuRef.value.closeDropdown();
}
});
</script>
<style lang="scss" scoped>
.h-full {
height: 100%;
}
.w-full {
width: 100%;
}
.icon-search-box {
display: flex;
align-items: center;
justify-content: center;
margin-left: 12rpx;
}
.login-btn-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 15rpx 20rpx;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 100rpx;
margin-right: 8rpx;
&:active {
background-color: rgba(0, 0, 0, 0.1);
}
.login-btn-text {
color: #333333;
font-size: 26rpx;
font-weight: 400;
}
}
</style>