refactor: clean up codebase and add new features
Replace SCSS variable usages with explicit pixel/hex values for consistent styling across all components Fix broken template syntax including missing class spaces and incorrect closing tags Migrate constant and API imports to centralized @/constants and @/api modules Add new utility classes: IdUtils, CallbackUtils, and TimerUtils Add new chat conversation API endpoints for recent conversations and message lists Add new Discovery page components (FindTabs, QuickQuestions, CardSwiper) and their styles Update app store config to use environment variables for base API and WebSocket URLs Add new selected tab icon assets
This commit is contained in:
83
src/constants/ChatModel.ts
Normal file
83
src/constants/ChatModel.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
export const MessageRole = {
|
||||
// 智能体消息
|
||||
AI: "AI",
|
||||
// 我发送的消息
|
||||
ME: "ME",
|
||||
// 其他消息
|
||||
OTHER: "OTHER",
|
||||
};
|
||||
|
||||
/// 消息类型 0-对话 1-指令 2-中断停止 3-心跳检测 4-通知
|
||||
export const MessageType = {
|
||||
// 对话消息
|
||||
dialog: 0,
|
||||
// 指令消息
|
||||
command: 1,
|
||||
// 中断停止
|
||||
stop: 2,
|
||||
// 心跳检测
|
||||
heartbeat: 3,
|
||||
// 通知消息
|
||||
notice: 4,
|
||||
};
|
||||
|
||||
/// 跳转类型: 0商品 1提示词 2链接 3组件指令
|
||||
export const JumpType = {
|
||||
// 商品
|
||||
commodity: 0,
|
||||
// 提示词
|
||||
prompt: 1,
|
||||
// 链接
|
||||
link: 2,
|
||||
// 组件指令
|
||||
command: 3,
|
||||
};
|
||||
|
||||
/// 组件的名称
|
||||
export const CompName = {
|
||||
// 快速预定卡片
|
||||
quickBookingCard: "quickBookingCard",
|
||||
// 服务工单卡片
|
||||
callServiceCard: "callServiceCard",
|
||||
// 意见反馈卡片
|
||||
feedbackCard: "feedbackCard",
|
||||
// 探索发现卡片
|
||||
discoveryCard: "discoveryCard",
|
||||
// 图片和商品卡片
|
||||
pictureAndCommodityCard: "pictureAndCommodityCard",
|
||||
// 输入车牌卡片
|
||||
enterLicensePlateCard: "enterLicensePlateCard",
|
||||
// 调查问卷卡片
|
||||
callSurveyQuestionnaire: "callSurveyQuestionnaire",
|
||||
// 打开地图卡片
|
||||
mapCard: "mapCard",
|
||||
// 回答卡片
|
||||
longTextCard: "longTextCard",
|
||||
longTextCardSnap: "longTextCardSnap",
|
||||
longTextCardRoute: "longTextCardRoute",
|
||||
longTextCardScenicSpot: "longTextCardScenicSpot",
|
||||
// 生成合成图片
|
||||
aigcPhotoGeneratorCard: "aigcPhotoGeneratorCard",
|
||||
};
|
||||
|
||||
/// 发送的指令类型
|
||||
export const Command = {
|
||||
// 通知消息
|
||||
messageInit: "Command.init",
|
||||
// 快速预定
|
||||
quickBooking: "Command.quickBooking",
|
||||
// 探索发现
|
||||
discovery: "Command.discovery",
|
||||
// 呼叫服务
|
||||
callServiceCard: "Command.callServiceCard",
|
||||
// 更多
|
||||
more: "Command.more",
|
||||
// 我的订单
|
||||
myOrder: "Command.myOrder",
|
||||
// 我的工单
|
||||
myWorkOrder: "Command.myWorkOrder",
|
||||
// 反馈意见
|
||||
feedbackCard: "Command.feedbackCard",
|
||||
// 生成合成图片
|
||||
aigcPhotoGenerator: "Command.aigcPhotoGenerator",
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* 客户端配置管理模块
|
||||
*
|
||||
* 功能说明:
|
||||
* 所有配置从根目录的 client-configs.json 文件中读取
|
||||
*/
|
||||
|
||||
// 直接导入配置文件
|
||||
import rawConfigs from "../../client-configs.json" with { type: "json" };
|
||||
|
||||
// 所有用户端的配置 - 处理后的配置
|
||||
export const CLIENT_CONFIGS = rawConfigs;
|
||||
|
||||
// 获取当前用户端配置
|
||||
export const getCurrentConfig = () => CLIENT_CONFIGS.xiaoqi;
|
||||
export const clientId = getCurrentConfig().clientId;
|
||||
export const appId = getCurrentConfig().appId;
|
||||
|
||||
/// 客户端类型
|
||||
export const ClientType = {
|
||||
// 智念
|
||||
ZHINIAN: "ZHINIAN",
|
||||
// 小七
|
||||
XIAOQI: "XIAOQI",
|
||||
// 朵花
|
||||
DUOHUA: "DUOHUA",
|
||||
// 天沐
|
||||
TIANMU: "TIANMU",
|
||||
// 念念助手
|
||||
NIANHELPER: "NIANHELPER",
|
||||
};
|
||||
|
||||
/// 获取当前客户端类型
|
||||
export const currentClientType = () => {
|
||||
switch (getCurrentConfig().name) {
|
||||
case "念念":
|
||||
return ClientType.ZHINIAN;
|
||||
case "小七":
|
||||
return ClientType.XIAOQI;
|
||||
case "朵朵":
|
||||
return ClientType.DUOHUA;
|
||||
case "沐沐":
|
||||
return ClientType.TIANMU;
|
||||
case "念念助手":
|
||||
return ClientType.NIANHELPER;
|
||||
default:
|
||||
return ClientType.ZHINIAN;
|
||||
}
|
||||
};
|
||||
|
||||
// 环境配置 - 智念客户端使用测试环境,其他客户端使用生产环境
|
||||
export const isZhiNian = currentClientType() === ClientType.ZHINIAN;
|
||||
173
src/constants/longTextCard.ts
Normal file
173
src/constants/longTextCard.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
export const LONG_TEXT_KEYS = {
|
||||
containerType: "container_type",
|
||||
tag: "tag",
|
||||
title: "title",
|
||||
content: "content",
|
||||
contentSummary: "content_summary",
|
||||
guideConclusion: "guide_conclusion",
|
||||
keyFacts: "key_facts",
|
||||
sceneImage: "scene_image",
|
||||
checklistOrSteps: "checklist_or_steps",
|
||||
bestTimeOrPeople: "best_time_or_people",
|
||||
avoidPitfalls: "avoid_pitfalls",
|
||||
nextSuggestion: "next_suggestion",
|
||||
poiDefinition: "poi_definition",
|
||||
keyHighlights: "key_highlights",
|
||||
heroImage: "hero_image",
|
||||
backgroundStory: "background_story",
|
||||
bestTime: "best_time",
|
||||
visitSuggestion: "visit_suggestion",
|
||||
routeSummary: "route_summary",
|
||||
routeMeta: "route_meta",
|
||||
routeSteps: "route_steps",
|
||||
onsiteClues: "onsite_clues",
|
||||
realtimeNotice: "realtime_notice",
|
||||
routeWarning: "route_warning",
|
||||
arrivalNextStep: "arrival_next_step",
|
||||
photoConclusion: "photo_conclusion",
|
||||
photoSpots: "photo_spots",
|
||||
compositionTips: "composition_tips",
|
||||
phoneSettings: "phone_settings",
|
||||
lightReminder: "light_reminder",
|
||||
sampleImage: "sample_image",
|
||||
components: "components",
|
||||
checklist: "checklist",
|
||||
suggest: "suggest",
|
||||
commodity: "commodity",
|
||||
actionZone: "action_zone",
|
||||
};
|
||||
|
||||
export const LONG_TEXT_FIELD_CONFIG = [
|
||||
{ key: LONG_TEXT_KEYS.containerType },
|
||||
{ key: LONG_TEXT_KEYS.tag },
|
||||
{ key: LONG_TEXT_KEYS.title },
|
||||
{ key: LONG_TEXT_KEYS.content },
|
||||
{ key: LONG_TEXT_KEYS.contentSummary },
|
||||
{ key: LONG_TEXT_KEYS.guideConclusion },
|
||||
{ key: LONG_TEXT_KEYS.keyFacts },
|
||||
{ key: LONG_TEXT_KEYS.sceneImage },
|
||||
{ key: LONG_TEXT_KEYS.checklistOrSteps },
|
||||
{ key: LONG_TEXT_KEYS.bestTimeOrPeople },
|
||||
{ key: LONG_TEXT_KEYS.avoidPitfalls },
|
||||
{ key: LONG_TEXT_KEYS.nextSuggestion },
|
||||
{ key: LONG_TEXT_KEYS.poiDefinition },
|
||||
{ key: LONG_TEXT_KEYS.keyHighlights },
|
||||
{ key: LONG_TEXT_KEYS.heroImage },
|
||||
{ key: LONG_TEXT_KEYS.backgroundStory },
|
||||
{ key: LONG_TEXT_KEYS.bestTime },
|
||||
{ key: LONG_TEXT_KEYS.visitSuggestion },
|
||||
{ key: LONG_TEXT_KEYS.routeSummary },
|
||||
{ key: LONG_TEXT_KEYS.routeMeta },
|
||||
{ key: LONG_TEXT_KEYS.routeSteps },
|
||||
{ key: LONG_TEXT_KEYS.onsiteClues },
|
||||
{ key: LONG_TEXT_KEYS.realtimeNotice },
|
||||
{ key: LONG_TEXT_KEYS.routeWarning },
|
||||
{ key: LONG_TEXT_KEYS.arrivalNextStep },
|
||||
{ key: LONG_TEXT_KEYS.photoConclusion },
|
||||
{ key: LONG_TEXT_KEYS.photoSpots },
|
||||
{ key: LONG_TEXT_KEYS.compositionTips },
|
||||
{ key: LONG_TEXT_KEYS.phoneSettings },
|
||||
{ key: LONG_TEXT_KEYS.lightReminder },
|
||||
{ key: LONG_TEXT_KEYS.sampleImage },
|
||||
{ key: LONG_TEXT_KEYS.components },
|
||||
{ key: LONG_TEXT_KEYS.checklist },
|
||||
{ key: LONG_TEXT_KEYS.suggest },
|
||||
{ key: LONG_TEXT_KEYS.commodity },
|
||||
{ key: LONG_TEXT_KEYS.actionZone },
|
||||
];
|
||||
|
||||
export const LONG_TEXT_PREVIEW_KEYS = [
|
||||
LONG_TEXT_KEYS.contentSummary,
|
||||
LONG_TEXT_KEYS.title,
|
||||
LONG_TEXT_KEYS.tag,
|
||||
];
|
||||
|
||||
const CONFIGURED_KEYS = LONG_TEXT_FIELD_CONFIG.map((item) => item.key);
|
||||
|
||||
export const createLongTextData = () => ({
|
||||
values: {},
|
||||
parsedValues: {},
|
||||
});
|
||||
|
||||
const toText = (value) => {
|
||||
if (value === undefined || value === null) return "";
|
||||
return typeof value === "string" ? value : String(value);
|
||||
};
|
||||
|
||||
const shouldParseJSON = (raw) => {
|
||||
if (!raw || typeof raw !== "string") return false;
|
||||
return /^[\s]*[\[{]/.test(raw);
|
||||
};
|
||||
|
||||
const tryParseJSON = (raw) => {
|
||||
if (!shouldParseJSON(raw)) {
|
||||
return { ok: false, value: null };
|
||||
}
|
||||
try {
|
||||
return { ok: true, value: JSON.parse(raw) };
|
||||
} catch (e) {
|
||||
return { ok: false, value: null };
|
||||
}
|
||||
};
|
||||
|
||||
export const appendLongTextChunk = (target, chunk = {}) => {
|
||||
if (!target || !chunk.contentKey) return target;
|
||||
|
||||
const key = String(chunk.contentKey);
|
||||
const value = toText(chunk.contentValue);
|
||||
|
||||
if (!target.values) target.values = {};
|
||||
if (!target.parsedValues) target.parsedValues = {};
|
||||
|
||||
target.values[key] = (target.values[key] || "") + value;
|
||||
|
||||
const parsed = tryParseJSON(target.values[key]);
|
||||
if (parsed.ok) {
|
||||
target.parsedValues[key] = parsed.value;
|
||||
} else {
|
||||
delete target.parsedValues[key];
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
export const getLongTextValue = (data, key) => {
|
||||
if (!data || !data.values || !key) return "";
|
||||
return data.values[key] || "";
|
||||
};
|
||||
|
||||
export const getLongTextParsedValue = (data, key, fallback = undefined) => {
|
||||
if (!data || !data.parsedValues || !key) return fallback;
|
||||
return Object.prototype.hasOwnProperty.call(data.parsedValues, key)
|
||||
? data.parsedValues[key]
|
||||
: fallback;
|
||||
};
|
||||
|
||||
export const getLongTextPreviewText = (data, keys = LONG_TEXT_PREVIEW_KEYS) => {
|
||||
for (const key of keys) {
|
||||
const value = getLongTextValue(data, key);
|
||||
if (value) return value;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
export const hasLongTextExtraSections = (data, previewKeys = LONG_TEXT_PREVIEW_KEYS) => {
|
||||
if (!data || !data.values) return false;
|
||||
return Object.keys(data.values).some((key) => !previewKeys.includes(key));
|
||||
};
|
||||
|
||||
export const getLongTextSections = (data) => {
|
||||
if (!data || !data.values) return [];
|
||||
|
||||
const extraKeys = Object.keys(data.values).filter(
|
||||
(key) => !CONFIGURED_KEYS.includes(key),
|
||||
);
|
||||
|
||||
return [...CONFIGURED_KEYS, ...extraKeys]
|
||||
.filter((key) => Object.prototype.hasOwnProperty.call(data.values, key))
|
||||
.map((key) => ({
|
||||
contentKey: key,
|
||||
contentValue: getLongTextValue(data, key),
|
||||
parsedValue: getLongTextParsedValue(data, key, null),
|
||||
}));
|
||||
};
|
||||
@@ -1,35 +1,3 @@
|
||||
import { currentClientType } from "@/constant/base";
|
||||
|
||||
// 存储在本地的认证 token 键名
|
||||
const CLIENT_TYPE = currentClientType();
|
||||
const ACCESS_TOKEN = `${CLIENT_TYPE}_ACCESS_TOKEN`;
|
||||
const REFRESH_ACCESS_TOKEN = `${CLIENT_TYPE}_REFRESH_ACCESS_TOKEN`;
|
||||
|
||||
// 设置本地存储的认证 token
|
||||
export const setAccessToken = (token) => {
|
||||
return uni.setStorageSync(ACCESS_TOKEN, token);
|
||||
};
|
||||
|
||||
// 设置本地存储的刷新 token
|
||||
export const setRefreshToken = (token) => {
|
||||
return uni.setStorageSync(REFRESH_ACCESS_TOKEN, token);
|
||||
};
|
||||
|
||||
// 获取本地存储的刷新 token
|
||||
export const getRefreshToken = () => {
|
||||
return uni.getStorageSync(REFRESH_ACCESS_TOKEN);
|
||||
};
|
||||
|
||||
// 获取本地存储的认证 token
|
||||
export const getAccessToken = () => {
|
||||
return uni.getStorageSync(ACCESS_TOKEN);
|
||||
};
|
||||
|
||||
// 移除本地存储的认证 token
|
||||
export const removeAccessToken = () => {
|
||||
return uni.removeStorageSync(ACCESS_TOKEN);
|
||||
};
|
||||
|
||||
export const removeRefreshToken = () => {
|
||||
return uni.removeStorageSync(REFRESH_ACCESS_TOKEN);
|
||||
};
|
||||
export function getAccessToken() {
|
||||
return localStorage.getItem("accessToken");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user