feat: 组件的调试
This commit is contained in:
143
src/pages/ChatMain/ChatLongAnswer/ParsedValueView.vue
Normal file
143
src/pages/ChatMain/ChatLongAnswer/ParsedValueView.vue
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<view class="parsed-value">
|
||||||
|
<template v-if="isIgnoredField"></template>
|
||||||
|
<template v-else-if="isContentBody">
|
||||||
|
<template v-for="entry in renderContentBodyEntries" :key="entry.key">
|
||||||
|
<view v-if="entry.type === 'text'" class="content-body-text">
|
||||||
|
{{ entry.value }}
|
||||||
|
</view>
|
||||||
|
<view v-else-if="entry.type === 'list'" class="content-body-list-card">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in entry.value"
|
||||||
|
:key="index"
|
||||||
|
class="content-body-list-item"
|
||||||
|
>
|
||||||
|
<view class="content-body-list-text">
|
||||||
|
{{ formatLeafValue(item) }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, defineProps } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
fieldKey: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Object, Array, String, Number, Boolean],
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const CONTENT_BODY_KEY = "content_body";
|
||||||
|
const HIDDEN_CONTENT_BODY_KEYS = ["container_type"];
|
||||||
|
const IGNORED_FIELD_KEYS = ["container_type"];
|
||||||
|
|
||||||
|
const isArrayValue = (value) => Array.isArray(value);
|
||||||
|
|
||||||
|
const isObjectValue = (value) => {
|
||||||
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeValue = (value) => {
|
||||||
|
if (isArrayValue(value)) {
|
||||||
|
return value.map((item) => sanitizeValue(item));
|
||||||
|
}
|
||||||
|
if (isObjectValue(value)) {
|
||||||
|
return Object.keys(value).reduce((result, key) => {
|
||||||
|
if (HIDDEN_CONTENT_BODY_KEYS.includes(key)) return result;
|
||||||
|
result[key] = sanitizeValue(value[key]);
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatLeafValue = (value) => {
|
||||||
|
if (value === undefined || value === null) return "";
|
||||||
|
if (typeof value === "boolean") return value ? "是" : "否";
|
||||||
|
if (typeof value === "object") {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(sanitizeValue(value));
|
||||||
|
} catch (e) {
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isContentBody = computed(() => props.fieldKey === CONTENT_BODY_KEY);
|
||||||
|
const isIgnoredField = computed(() => IGNORED_FIELD_KEYS.includes(props.fieldKey));
|
||||||
|
|
||||||
|
const renderContentBodyEntries = computed(() => {
|
||||||
|
if (!isContentBody.value || !isObjectValue(props.value)) return [];
|
||||||
|
|
||||||
|
return Object.keys(props.value)
|
||||||
|
.filter((key) => !HIDDEN_CONTENT_BODY_KEYS.includes(key))
|
||||||
|
.map((key) => {
|
||||||
|
const value = props.value[key];
|
||||||
|
if (isArrayValue(value)) {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
type: "list",
|
||||||
|
value: value.filter((item) => formatLeafValue(item)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
type: "text",
|
||||||
|
value: formatLeafValue(value),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((entry) => {
|
||||||
|
if (entry.type === "list") return entry.value.length > 0;
|
||||||
|
return !!entry.value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.parsed-value {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-text {
|
||||||
|
color: #111827;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-list-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 12px;
|
||||||
|
border-left: 4px solid $theme-color-500;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba($theme-color-500, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body-list-text {
|
||||||
|
flex: 1;
|
||||||
|
color: $theme-color-800;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -9,16 +9,18 @@
|
|||||||
<scroll-view class="flex-full overflow-hidden chat-scroll" scroll-y :scroll-into-view="scrollIntoViewId" scroll-with-animation @scroll="onScroll" @touchstart="onTouchStart" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
|
<scroll-view class="flex-full overflow-hidden chat-scroll" scroll-y :scroll-into-view="scrollIntoViewId" scroll-with-animation @scroll="onScroll" @touchstart="onTouchStart" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
|
||||||
<view class="pt-12 px-12 pb-24 border-box">
|
<view class="pt-12 px-12 pb-24 border-box">
|
||||||
<template v-for="section in renderSections" :key="section.contentKey">
|
<template v-for="section in renderSections" :key="section.contentKey">
|
||||||
<view v-if="section.contentKey === 'tag'" class="long-answer-tag">
|
<view v-if="section.contentKey === LONG_TEXT_KEYS.tag" class="long-answer-tag">
|
||||||
{{ section.contentValue }}
|
{{ section.contentValue }}
|
||||||
</view>
|
</view>
|
||||||
<view v-else-if="section.contentKey === 'title'" class="long-answer-title">
|
<view v-else-if="section.contentKey === LONG_TEXT_KEYS.title" class="long-answer-title">
|
||||||
{{ section.contentValue }}
|
{{ section.contentValue }}
|
||||||
</view>
|
</view>
|
||||||
<ChatMarkdown v-else-if="section.contentKey === 'content'" :text="section.contentValue" />
|
<view v-else-if="shouldUseParsedValueView(section)" class="long-answer-block">
|
||||||
<view v-else-if="section.parsedValue !== null" class="long-answer-block">
|
<ParsedValueView :field-key="section.contentKey" :value="section.parsedValue !== null ? section.parsedValue : section.contentValue" />
|
||||||
<ChatMarkdown :text="toMarkdownText(section.parsedValue)" />
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<ChatMarkdown v-else-if="section.contentKey === LONG_TEXT_KEYS.content" :text="section.contentValue" />
|
||||||
|
|
||||||
<ChatMarkdown v-else :text="section.contentValue" />
|
<ChatMarkdown v-else :text="section.contentValue" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -32,10 +34,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||||||
import ChatMarkdown from "../ChatMarkdown/index.vue";
|
import ChatMarkdown from "../ChatMarkdown/index.vue";
|
||||||
|
import ParsedValueView from "./ParsedValueView.vue";
|
||||||
import { defineProps, ref, nextTick, computed } from "vue";
|
import { defineProps, ref, nextTick, computed } from "vue";
|
||||||
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
||||||
import StreamManager from "@/utils/StreamManager.js";
|
import StreamManager from "@/utils/StreamManager.js";
|
||||||
import {
|
import {
|
||||||
|
LONG_TEXT_KEYS,
|
||||||
getLongTextSections,
|
getLongTextSections,
|
||||||
getLongTextValue,
|
getLongTextValue,
|
||||||
} from "@/utils/longTextCard";
|
} from "@/utils/longTextCard";
|
||||||
@@ -52,20 +56,10 @@ const title = ref("");
|
|||||||
const longTextData = ref(null);
|
const longTextData = ref(null);
|
||||||
|
|
||||||
let unsubscribe = null;
|
let unsubscribe = null;
|
||||||
|
const PARSED_VALUE_VIEW_KEYS = ["container_type"];
|
||||||
|
|
||||||
const toMarkdownText = (value) => {
|
const shouldUseParsedValueView = (section) => {
|
||||||
if (value === undefined || value === null) return "";
|
return section.parsedValue !== null || PARSED_VALUE_VIEW_KEYS.includes(section.contentKey);
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return value.map((item) => toMarkdownText(item)).filter(Boolean).join("\n\n");
|
|
||||||
}
|
|
||||||
if (typeof value === "object") {
|
|
||||||
try {
|
|
||||||
return JSON.stringify(value, null, 2);
|
|
||||||
} catch (e) {
|
|
||||||
return String(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return String(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderSections = computed(() => {
|
const renderSections = computed(() => {
|
||||||
@@ -250,7 +244,6 @@ onUnload(() => {
|
|||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
.long-answer-title {
|
.long-answer-title {
|
||||||
margin-bottom: 12px;
|
|
||||||
color: #111827;
|
color: #111827;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
Reference in New Issue
Block a user