feat: 增加腾讯AI
|
|
@ -2,7 +2,9 @@ VITE_APP_TITLE = '六纬中考通'
|
|||
VITE_APP_PORT = 9000
|
||||
|
||||
VITE_UNI_APPID = 'H57F2ACE4'
|
||||
VITE_WX_APPID = 'wx4b925e36c17dd54a'
|
||||
# VITE_WX_APPID = 'wxc48ad15d58a3e417' 六纬中考通
|
||||
# VITE_WX_APPID = 'wx4b925e36c17dd54a' 六纬裂变
|
||||
VITE_WX_APPID = 'wxc48ad15d58a3e417'
|
||||
|
||||
# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
|
||||
# https://uniapp.dcloud.net.cn/collocation/manifest.html#h5-router
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ export default defineUniPages({
|
|||
navigationBarBackgroundColor: '#FFFFFF',
|
||||
navigationBarTextStyle: 'black',
|
||||
backgroundColor: '#FFFFFF',
|
||||
// 全局注册微信原生组件(仅 mp-weixin 编译器会读取此字段)
|
||||
usingComponents: {
|
||||
'markdown-preview': '/wxcomponents/agent-ui/wd-markdown/index',
|
||||
},
|
||||
},
|
||||
easycom: {
|
||||
autoscan: true,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,292 @@
|
|||
<script lang="ts" setup>
|
||||
import type { AgentConfig, ModelConfig } from '../components/agent-config'
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
import { useAiStore } from '@/store'
|
||||
import {
|
||||
defaultAgentConfig,
|
||||
defaultModelConfig,
|
||||
generateMessageId,
|
||||
} from '../components/agent-config'
|
||||
import { fetchRecommendQuestions, streamMessage } from '../components/agent-service'
|
||||
import AgentInput from '../components/AgentInput.vue'
|
||||
import AgentMessage from '../components/AgentMessage.vue'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: 'AI 助手',
|
||||
},
|
||||
})
|
||||
|
||||
const agentConfig = reactive<AgentConfig>({ ...defaultAgentConfig })
|
||||
// 预留:model 模式下使用,当前 bot 模式不读取
|
||||
|
||||
const _modelConfig = reactive<ModelConfig>({ ...defaultModelConfig })
|
||||
|
||||
const aiStore = useAiStore()
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const messages = ref<AiMessage[]>([])
|
||||
const loading = ref(false)
|
||||
/** 当前轮回复结束后由 getRecommendQuestions 返回的追问建议 */
|
||||
const recommendQuestions = ref<string[]>([])
|
||||
|
||||
// 用于停止流:在新一轮发送时把上一轮的 controller 标记为 cancelled
|
||||
let cancelFlag = false
|
||||
|
||||
onLoad(() => {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (typeof wx !== 'undefined' && wx.cloud) {
|
||||
wx.cloud.init({
|
||||
env: agentConfig.cloudEnvId,
|
||||
traceUser: true,
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
aiStore.ensureThreadId()
|
||||
})
|
||||
|
||||
// z-paging 聊天模式:第一页直接把 store 里的历史灌给它
|
||||
// 聊天模式数据约定:数组下标 0 = 视觉最底部(最新消息),所以要倒序传入
|
||||
function queryList() {
|
||||
if (aiStore.messages.length === 0) {
|
||||
aiStore.addMessage({
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: agentConfig.welcomeMsg,
|
||||
createdAt: Date.now(),
|
||||
})
|
||||
}
|
||||
paging.value?.complete(aiStore.messages.slice().reverse())
|
||||
}
|
||||
|
||||
async function handleSend(text: string) {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
cancelFlag = false
|
||||
loading.value = true
|
||||
// 新一轮发送时收起上一轮的追问建议
|
||||
recommendQuestions.value = []
|
||||
|
||||
const userMsg: AiMessage = {
|
||||
id: generateMessageId(),
|
||||
role: 'user',
|
||||
content: text,
|
||||
createdAt: Date.now(),
|
||||
}
|
||||
const aiMsg: AiMessage = {
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
pending: true,
|
||||
// +1 防止与 userMsg 同毫秒下时间戳相等
|
||||
createdAt: Date.now() + 1,
|
||||
}
|
||||
|
||||
// 同时写入 store 与 z-paging 列表
|
||||
// 顺序与首屏 queryList 保持一致:在数组中 user 在前、ai 在后
|
||||
// z-paging 聊天模式 addChatRecordData 内部会反转 + 前插,
|
||||
// 最终 totalData = [aiMsg, userMsg, ...历史],下标 0 = 视觉最底 = aiMsg,
|
||||
// userMsg 显示在 aiMsg 上方,符合"用户问 → AI 答在下方"的正常顺序
|
||||
aiStore.addMessage(userMsg)
|
||||
aiStore.addMessage(aiMsg)
|
||||
paging.value?.addChatRecordData([userMsg, aiMsg])
|
||||
|
||||
try {
|
||||
await streamMessage({
|
||||
botId: agentConfig.botId,
|
||||
threadId: aiStore.ensureThreadId(),
|
||||
// 倒数第二条之前是历史;当前 aiMsg 是占位,不传
|
||||
history: aiStore.messages.slice(0, -1),
|
||||
prompt: text,
|
||||
onDelta: (delta) => {
|
||||
if (cancelFlag) {
|
||||
return
|
||||
}
|
||||
aiStore.appendDelta(aiMsg.id, delta)
|
||||
},
|
||||
onError: (msg) => {
|
||||
aiStore.updateMessage(aiMsg.id, {
|
||||
error: true,
|
||||
pending: false,
|
||||
content: msg,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
aiStore.updateMessage(aiMsg.id, { pending: false })
|
||||
|
||||
// 一轮对话结束后,请求大模型给追问建议
|
||||
if (!cancelFlag) {
|
||||
void loadRecommendQuestions(text)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
aiStore.updateMessage(aiMsg.id, {
|
||||
pending: false,
|
||||
error: true,
|
||||
content: aiStore.messages.find(m => m.id === aiMsg.id)?.content
|
||||
|| (err instanceof Error ? err.message : '生成失败'),
|
||||
})
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop() {
|
||||
cancelFlag = true
|
||||
loading.value = false
|
||||
// 把仍在 pending 的消息收尾
|
||||
const pending = aiStore.messages.find(m => m.pending)
|
||||
if (pending) {
|
||||
aiStore.updateMessage(pending.id, { pending: false })
|
||||
}
|
||||
}
|
||||
|
||||
function handleRetry(id: string) {
|
||||
const failedIdx = aiStore.messages.findIndex(m => m.id === id)
|
||||
if (failedIdx <= 0) {
|
||||
return
|
||||
}
|
||||
// 重试:找到这条 ai 消息对应的上一条用户消息
|
||||
const userMsg = aiStore.messages[failedIdx - 1]
|
||||
if (!userMsg || userMsg.role !== 'user') {
|
||||
return
|
||||
}
|
||||
// 移除失败的回复后重新发送
|
||||
aiStore.removeMessage(id)
|
||||
handleSend(userMsg.content)
|
||||
}
|
||||
|
||||
function handleClickQuestion(question: string) {
|
||||
recommendQuestions.value = []
|
||||
handleSend(question)
|
||||
}
|
||||
|
||||
async function loadRecommendQuestions(prompt: string) {
|
||||
// 取最近一对 user / assistant 用作上下文
|
||||
const last = aiStore.messages.slice(-2).map(m => ({
|
||||
role: m.role === 'user' ? ('user' as const) : ('assistant' as const),
|
||||
content: m.content,
|
||||
}))
|
||||
try {
|
||||
const questions = await fetchRecommendQuestions({
|
||||
botId: agentConfig.botId,
|
||||
lastPair: last,
|
||||
prompt,
|
||||
max: 3,
|
||||
onProgress: (qs) => {
|
||||
recommendQuestions.value = qs
|
||||
},
|
||||
})
|
||||
recommendQuestions.value = questions
|
||||
}
|
||||
catch (error) {
|
||||
console.error('[recommend]', error)
|
||||
recommendQuestions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
function handleClear() {
|
||||
aiStore.clear()
|
||||
recommendQuestions.value = []
|
||||
paging.value?.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="h-screen w-full flex flex-col bg-[#F4F6FA]">
|
||||
<!-- 顶部:清空按钮 -->
|
||||
<view class="flex items-center justify-between bg-white px-[24rpx] py-[20rpx] shadow-[0_2rpx_8rpx_rgba(0,0,0,0.03)]">
|
||||
<view class="text-[30rpx] text-[#1F2329] font-500">
|
||||
{{ agentConfig.botName }}
|
||||
</view>
|
||||
<view
|
||||
class="rounded-[24rpx] bg-[#F5F6F8] px-[20rpx] py-[8rpx] text-[24rpx] text-[#666] active:opacity-60"
|
||||
@click="handleClear"
|
||||
>
|
||||
清空对话
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息列表(聊天模式) -->
|
||||
<view class="min-h-0 flex-1">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="messages"
|
||||
:default-page-size="50"
|
||||
:auto-show-system-loading="false"
|
||||
:loading-more-enabled="false"
|
||||
:show-refresher-when-reload="false"
|
||||
:show-loading-more-no-more-view="false"
|
||||
use-chat-record-mode
|
||||
auto-adjust-position-when-chat
|
||||
auto-to-bottom-when-chat
|
||||
:paging-style="{ backgroundColor: '#F4F6FA' }"
|
||||
@query="queryList"
|
||||
>
|
||||
<!-- 推荐问题 -->
|
||||
<template v-if="messages.length <= 1 && agentConfig.initQuestions.length" #top>
|
||||
<view class="flex flex-col gap-[16rpx] px-[24rpx] py-[20rpx]">
|
||||
<view class="text-[24rpx] text-[#999] leading-[1.4]">
|
||||
你可以试试这样问:
|
||||
</view>
|
||||
<view class="flex flex-wrap gap-[16rpx]">
|
||||
<view
|
||||
v-for="q in agentConfig.initQuestions"
|
||||
:key="q"
|
||||
class="border-1 border-[#1580FF] rounded-[24rpx] border-solid bg-white px-[20rpx] py-[10rpx] text-[24rpx] text-[#1580FF] active:opacity-60"
|
||||
@click="handleClickQuestion(q)"
|
||||
>
|
||||
{{ q }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #default>
|
||||
<agent-message
|
||||
v-for="item in messages"
|
||||
:key="item.id"
|
||||
:message="item"
|
||||
:bot-name="agentConfig.botName"
|
||||
@retry="handleRetry"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #bottom>
|
||||
<!-- 一轮对话结束后的追问建议 -->
|
||||
<view
|
||||
v-if="recommendQuestions.length"
|
||||
class="flex flex-wrap gap-[12rpx] bg-[#F4F6FA] px-[24rpx] pb-[16rpx] pt-[8rpx]"
|
||||
>
|
||||
<view class="w-full text-[24rpx] text-[#999] leading-[1.4]">
|
||||
你可能还想问:
|
||||
</view>
|
||||
<view
|
||||
v-for="q in recommendQuestions"
|
||||
:key="q"
|
||||
class="border-1 border-[#1580FF] rounded-[24rpx] border-solid bg-white px-[20rpx] py-[10rpx] text-[24rpx] text-[#1580FF] active:opacity-60"
|
||||
@click="handleClickQuestion(q)"
|
||||
>
|
||||
{{ q }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<agent-input
|
||||
:placeholder="agentConfig.placeholder"
|
||||
:loading="loading"
|
||||
@send="handleSend"
|
||||
@stop="handleStop"
|
||||
@clear="handleClear"
|
||||
/>
|
||||
</template>
|
||||
</z-paging>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
placeholder?: string
|
||||
loading?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'send', text: string): void
|
||||
(event: 'stop'): void
|
||||
(event: 'clear'): void
|
||||
}>()
|
||||
|
||||
const inputValue = ref('')
|
||||
const showActions = ref(false)
|
||||
|
||||
function handleSend() {
|
||||
const text = inputValue.value.trim()
|
||||
if (!text || props.loading) {
|
||||
return
|
||||
}
|
||||
emit('send', text)
|
||||
inputValue.value = ''
|
||||
}
|
||||
|
||||
function toggleActions() {
|
||||
showActions.value = !showActions.value
|
||||
}
|
||||
|
||||
function handleClickClear() {
|
||||
showActions.value = false
|
||||
uni.showModal({
|
||||
title: '清空对话',
|
||||
content: '将删除所有对话记录,确认继续?',
|
||||
confirmColor: '#EB5241',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
emit('clear')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="flex flex-col bg-white pb-safe">
|
||||
<!-- 输入区 -->
|
||||
<view class="flex items-center gap-[16rpx] px-[24rpx] py-[18rpx]">
|
||||
<view class="min-h-[72rpx] flex flex-1 items-center rounded-[40rpx] bg-[#F5F6F8] px-[24rpx] py-[12rpx]">
|
||||
<textarea
|
||||
v-model="inputValue"
|
||||
class="max-h-[200rpx] w-full bg-transparent text-[28rpx] text-[#1F2329]"
|
||||
:placeholder="props.placeholder || '输入你的问题'"
|
||||
placeholder-style="color:#A6AFBD;font-size:28rpx;"
|
||||
auto-height
|
||||
:show-confirm-bar="false"
|
||||
:adjust-position="true"
|
||||
cursor-spacing="20"
|
||||
confirm-type="send"
|
||||
@confirm="handleSend"
|
||||
@focus="showActions = false"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 发送 / 停止 / 展开更多 -->
|
||||
<view
|
||||
v-if="!props.loading && !inputValue.trim()"
|
||||
class="h-[72rpx] w-[72rpx] flex items-center justify-center rounded-full bg-[#F5F6F8] text-[40rpx] text-[#666] transition active:opacity-60"
|
||||
:class="showActions ? 'rotate-45' : ''"
|
||||
@click="toggleActions"
|
||||
>
|
||||
+
|
||||
</view>
|
||||
<view
|
||||
v-else-if="!props.loading"
|
||||
class="h-[72rpx] w-[120rpx] flex items-center justify-center rounded-[36rpx] bg-[#1580FF] text-[28rpx] text-white font-500 transition active:opacity-80"
|
||||
@click="handleSend"
|
||||
>
|
||||
发送
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="h-[72rpx] w-[120rpx] flex items-center justify-center border-1 border-[#1580FF] rounded-[36rpx] border-solid bg-white text-[28rpx] text-[#1580FF] font-500 active:opacity-80"
|
||||
@click="emit('stop')"
|
||||
>
|
||||
停止
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 展开的操作面板 -->
|
||||
<view
|
||||
v-if="showActions"
|
||||
class="grid grid-cols-4 gap-[16rpx] px-[24rpx] pb-[24rpx] pt-[12rpx]"
|
||||
>
|
||||
<view
|
||||
class="flex flex-col items-center gap-[8rpx] rounded-[16rpx] bg-[#F5F6F8] py-[24rpx] active:opacity-60"
|
||||
@click="handleClickClear"
|
||||
>
|
||||
<view class="h-[64rpx] w-[64rpx] flex items-center justify-center rounded-full bg-[#FFE4E1] text-[32rpx] text-[#EB5241]">
|
||||
清
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rotate-45 {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<script lang="ts" setup>
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
|
||||
const props = defineProps<{
|
||||
message: AiMessage
|
||||
botName?: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(event: 'retry', id: string): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view
|
||||
class="cell-flip flex px-[24rpx] py-[16rpx]"
|
||||
:class="props.message.role === 'user' ? 'justify-end' : 'justify-start'"
|
||||
>
|
||||
<!-- AI 头像 -->
|
||||
<view
|
||||
v-if="props.message.role !== 'user'"
|
||||
class="mr-[16rpx] h-[64rpx] w-[64rpx] flex shrink-0 items-center justify-center rounded-full bg-[#1580FF] text-[24rpx] text-white"
|
||||
>
|
||||
AI
|
||||
</view>
|
||||
|
||||
<view class="max-w-[78%] flex flex-col gap-[8rpx]">
|
||||
<view
|
||||
class="break-all rounded-[16rpx] px-[24rpx] py-[18rpx] text-[28rpx] leading-[1.6]"
|
||||
:class="props.message.role === 'user'
|
||||
? 'bg-[#1580FF] text-white rounded-tr-[4rpx]'
|
||||
: 'rounded-tl-[4rpx] bg-white text-[#1F2329] shadow-[0_2rpx_12rpx_rgba(0,0,0,0.04)]'"
|
||||
>
|
||||
<!-- AI 回复用 markdown 渲染(仅微信小程序) -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<markdown-preview
|
||||
v-if="props.message.role !== 'user'"
|
||||
:markdown="props.message.content || (props.message.pending ? '' : '')"
|
||||
:font-size="28"
|
||||
/>
|
||||
<text v-else class="select-text">
|
||||
{{ props.message.content }}
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 其它端 fallback -->
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
<text class="select-text">
|
||||
{{ props.message.content || (props.message.pending ? '...' : '') }}
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
|
||||
<text v-if="props.message.pending" class="ml-[6rpx] animate-pulse">
|
||||
▍
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="props.message.error"
|
||||
class="self-start text-[24rpx] text-[#EB5241] leading-[1.4] active:opacity-60"
|
||||
@click="$emit('retry', props.message.id)"
|
||||
>
|
||||
生成失败,点击重试
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户头像 -->
|
||||
<view
|
||||
v-if="props.message.role === 'user'"
|
||||
class="ml-[16rpx] h-[64rpx] w-[64rpx] flex shrink-0 items-center justify-center rounded-full bg-[#FFA94D] text-[28rpx] text-white"
|
||||
>
|
||||
U
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* z-paging 聊天模式整体 scaleY(-1),cell 必须再反转一次回正 */
|
||||
.cell-flip {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
40% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// AI Agent 相关运行时配置(页面、组件共享)
|
||||
|
||||
export interface AgentConfig {
|
||||
/** 微信云开发环境 ID,用于 wx.cloud.init */
|
||||
cloudEnvId: string
|
||||
/** Agent ID,对应 wx.cloud.extend.AI.bot.sendMessage 的 botId */
|
||||
botId: string
|
||||
/** 首屏欢迎语 */
|
||||
welcomeMsg: string
|
||||
/** 输入框 placeholder */
|
||||
placeholder: string
|
||||
/** 显示在 AI 头像位置的图标 / 文字 */
|
||||
botName: string
|
||||
/** 默认推荐问题,点击后直接发送 */
|
||||
initQuestions: string[]
|
||||
}
|
||||
|
||||
export interface ModelConfig {
|
||||
/** 模型 provider,如 'cloudbase' / 'youtu' / 'hunyuan' */
|
||||
modelProvider: string
|
||||
/** 具体的模型 ID */
|
||||
quickResponseModel: string
|
||||
/** logo 图,可选 */
|
||||
logo: string
|
||||
}
|
||||
|
||||
export const defaultAgentConfig: AgentConfig = {
|
||||
cloudEnvId: 'cloud1-d3g5q6bq61a240786',
|
||||
botId: 'agent-wxai-4gl75um61026324f',
|
||||
welcomeMsg: '你好,我是 AI 助手,有什么可以帮你?',
|
||||
placeholder: '输入你的问题',
|
||||
botName: 'AI 助手',
|
||||
initQuestions: [
|
||||
'帮我介绍一下志愿填报流程',
|
||||
'中考分数线怎么查?',
|
||||
'推荐几所适合的高中',
|
||||
],
|
||||
}
|
||||
|
||||
export const defaultModelConfig: ModelConfig = {
|
||||
modelProvider: 'youtu-intent-pro',
|
||||
quickResponseModel: '',
|
||||
logo: '',
|
||||
}
|
||||
|
||||
export function generateMessageId() {
|
||||
const timestamp = Date.now().toString().slice(-8)
|
||||
const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0')
|
||||
return `${timestamp}${random}`
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
// 与 wx.cloud.extend.AI.bot 通讯的服务层
|
||||
// 把流式接收逻辑收敛到一个 streamMessage 函数,UI 只负责消费 onDelta
|
||||
|
||||
import type { AiMessage } from '@/store/ai'
|
||||
import { generateMessageId } from './agent-config'
|
||||
|
||||
interface BotEventData {
|
||||
type: string
|
||||
delta?: string
|
||||
message?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface SendMessageOptions {
|
||||
botId: string
|
||||
threadId: string
|
||||
/** 历史消息(最近若干轮),按 wx.cloud.extend.AI.bot 协议传 */
|
||||
history: AiMessage[]
|
||||
/** 当前用户输入 */
|
||||
prompt: string
|
||||
/** 流式增量回调 */
|
||||
onDelta: (delta: string) => void
|
||||
/** 错误回调,会拿到服务端返回的 message 字段 */
|
||||
onError?: (message: string) => void
|
||||
}
|
||||
|
||||
export async function streamMessage(options: SendMessageOptions): Promise<string> {
|
||||
const { botId, threadId, history, prompt, onDelta, onError } = options
|
||||
|
||||
// wx.cloud.extend.AI.bot 协议要求传入完整 messages 列表
|
||||
// 这里把 store 里的历史拼到一起,最后追加当前用户消息
|
||||
const messages = [
|
||||
...history
|
||||
.filter(m => !m.error && (m.role === 'user' || m.role === 'assistant'))
|
||||
.map(m => ({
|
||||
id: m.id,
|
||||
role: m.role,
|
||||
content: m.content,
|
||||
})),
|
||||
{
|
||||
id: generateMessageId(),
|
||||
role: 'user',
|
||||
content: prompt,
|
||||
},
|
||||
]
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// @ts-expect-error wx.cloud.extend 由微信小程序基础库注入
|
||||
const res = await wx.cloud.extend.AI.bot.sendMessage({
|
||||
data: {
|
||||
botId,
|
||||
threadId,
|
||||
runId: `run_id_${generateMessageId()}`,
|
||||
messages,
|
||||
tools: [],
|
||||
context: [],
|
||||
state: {},
|
||||
forwardedProps: {},
|
||||
},
|
||||
})
|
||||
|
||||
let response = ''
|
||||
for await (const event of res.eventStream) {
|
||||
let data: BotEventData
|
||||
try {
|
||||
data = JSON.parse(event.data) as BotEventData
|
||||
}
|
||||
catch {
|
||||
continue
|
||||
}
|
||||
switch (data.type) {
|
||||
case 'TEXT_MESSAGE_CONTENT':
|
||||
if (data.delta) {
|
||||
response += data.delta
|
||||
onDelta(data.delta)
|
||||
}
|
||||
break
|
||||
case 'RUN_ERROR':
|
||||
onError?.(data.message || '请求出错,请稍后再试')
|
||||
throw new Error(data.message || 'RUN_ERROR')
|
||||
case 'RUN_FINISHED':
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
throw new Error('AI 助手仅在微信小程序内可用')
|
||||
// #endif
|
||||
}
|
||||
|
||||
interface RecommendOptions {
|
||||
botId: string
|
||||
/** 最近一对 user/assistant 消息,用于上下文 */
|
||||
lastPair: { role: 'user' | 'assistant', content: string }[]
|
||||
/** 触发追问的用户原问题 */
|
||||
prompt: string
|
||||
/** 最多返回多少条 */
|
||||
max?: number
|
||||
/** 流式返回时增量更新(用来做"边收边渲染"),可选 */
|
||||
onProgress?: (questions: string[]) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 在一轮对话结束后,调用 getRecommendQuestions 获取追问建议。
|
||||
* 取决于 agent 后台是否开启"智能体追问"。
|
||||
*/
|
||||
export async function fetchRecommendQuestions(options: RecommendOptions): Promise<string[]> {
|
||||
const { botId, lastPair, prompt, max = 3, onProgress } = options
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// @ts-expect-error wx.cloud.extend 由微信小程序基础库注入
|
||||
const res = await wx.cloud.extend.AI.bot.getRecommendQuestions({
|
||||
data: {
|
||||
botId,
|
||||
history: lastPair.map(item => ({
|
||||
role: item.role,
|
||||
content: item.content,
|
||||
})),
|
||||
msg: prompt,
|
||||
agentSetting: '',
|
||||
introduction: '',
|
||||
name: '',
|
||||
},
|
||||
})
|
||||
|
||||
let buffer = ''
|
||||
for await (const chunk of res.textStream) {
|
||||
buffer += chunk
|
||||
const questions = buffer.split('\n').map(s => s.trim()).filter(Boolean).slice(0, max)
|
||||
onProgress?.(questions)
|
||||
}
|
||||
|
||||
return buffer.split('\n').map(s => s.trim()).filter(Boolean).slice(0, max)
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
return []
|
||||
// #endif
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { useLogin } from '@/pages-fg/hooks/useUserInfo'
|
||||
import {
|
||||
getSessionKey,
|
||||
getWxUserInfo,
|
||||
setWxInfo,
|
||||
} from '@/service/'
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
import Checkbox from '../components/check-group/Checkbox.vue'
|
||||
import CheckboxGroup from '../components/check-group/CheckboxGroup.vue'
|
||||
import { useLogin } from '@/pages-fg/hooks/useUserInfo'
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
|
||||
const checked = ref([]) // 是否同意条款
|
||||
const getPhoneInfo = ref(null)
|
||||
|
|
@ -16,8 +15,8 @@ const getPhoneInfo = ref(null)
|
|||
const tokenStore = useTokenStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const getPhoneNumber = async (e: any) => {
|
||||
if (e.detail.errMsg == 'getPhoneNumber:ok') {
|
||||
async function getPhoneNumber(e: any) {
|
||||
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||
const detail = e.detail
|
||||
const _getPhoneInfo = {
|
||||
iv: detail.iv,
|
||||
|
|
@ -26,12 +25,14 @@ const getPhoneNumber = async (e: any) => {
|
|||
}
|
||||
getPhoneInfo.value = _getPhoneInfo
|
||||
await getUserInfo(detail.code)
|
||||
} else if (e.detail.errMsg == 'getPhoneNumber:fail not login') {
|
||||
}
|
||||
else if (e.detail.errMsg === 'getPhoneNumber:fail not login') {
|
||||
uni.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none',
|
||||
})
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
uni.showToast({
|
||||
title: '获取手机号失败',
|
||||
icon: 'none',
|
||||
|
|
@ -39,7 +40,7 @@ const getPhoneNumber = async (e: any) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
function handleClick() {
|
||||
if (!checked.value) {
|
||||
uni.showToast({
|
||||
title: '您需先同意《服务条款》和《隐私条款》',
|
||||
|
|
@ -60,49 +61,46 @@ const handleClick = () => {
|
|||
}
|
||||
|
||||
// 授权完成之后返回到上一个目录去
|
||||
const handleAuthReady = () => {
|
||||
function handleAuthReady() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
|
||||
|
||||
const handleClickUserAgreement = () => {
|
||||
function handleClickUserAgreement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages-fg/login/userAgreement',
|
||||
})
|
||||
}
|
||||
|
||||
const handleClickPrivacyPolicy = () => {
|
||||
function handleClickPrivacyPolicy() {
|
||||
uni.navigateTo({
|
||||
url: '/pages-fg/login/privacyPolicy',
|
||||
})
|
||||
}
|
||||
|
||||
async function getUserInfo(_code: string) {
|
||||
const userInfo = (await useLogin()) as { code: string, errMsg: string }
|
||||
|
||||
|
||||
const getUserInfo = async (_code: string) => {
|
||||
const userInfo = (await useLogin()) as { code: string; errMsg: string }
|
||||
|
||||
if (userInfo.errMsg == 'login:ok') {
|
||||
if (userInfo.errMsg === 'login:ok') {
|
||||
const resp = await getSessionKey({ query: { JsCode: userInfo.code } })
|
||||
if(resp.code !== 200){
|
||||
uni.showModal({title:'登陆失败',content:resp.message})
|
||||
uni.navigateBack();
|
||||
if (resp.code !== 200) {
|
||||
uni.showModal({ title: '登陆失败', content: resp.message })
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
|
||||
tokenStore.setTokenInfo({ token: resp.result.accessToken, expiresIn: 7 * 24 * 60 * 60 })
|
||||
userStore.setUserOpenId(resp.result.openId)
|
||||
setWxInfo({options:{query:{code:_code, openId:resp.result.openId}}})
|
||||
getWxUserInfo().then(resp => {
|
||||
if(resp.code == 200){
|
||||
setWxInfo({ options: { query: { code: _code, openId: resp.result.openId } } })
|
||||
getWxUserInfo().then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
userStore.setUserExtend(resp.result.userExtend)
|
||||
userStore.setUserInfo({nickName:resp.result.nickName,mobile:resp.result.mobile})
|
||||
userStore.setUserInfo({ nickName: resp.result.nickName, mobile: resp.result.mobile })
|
||||
userStore.setSex(resp.result.sex)
|
||||
userStore.setUserAvatar(resp.result.avatar)
|
||||
}
|
||||
})
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
uni.showToast({
|
||||
title: '您需先授权',
|
||||
icon: 'none',
|
||||
|
|
@ -113,35 +111,36 @@ const getUserInfo = async (_code: string) => {
|
|||
|
||||
<template>
|
||||
<view class="h-screen flex flex-col bg-white">
|
||||
<view class="flex flex-col justify-center items-center flex-1 pb-safe mt-[-100px]">
|
||||
<view class="w-[424rpx] h-[424rpx]">
|
||||
<image class="w-[424rpx] h-[424rpx]" src="https://lwzk.ycymedu.com/img/home/logo.png" mode="aspectFit">
|
||||
</image>
|
||||
<view class="mt-[-100px] flex flex-1 flex-col items-center justify-center pb-safe">
|
||||
<view class="h-[424rpx] w-[424rpx]">
|
||||
<image class="h-[424rpx] w-[424rpx]" src="https://lwzk.ycymedu.com/img/home/logo.png" mode="aspectFit" />
|
||||
</view>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button
|
||||
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center "
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick"
|
||||
open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" :disabled="checked.length === 0">
|
||||
class="mb-[40rpx] flex items-center justify-center rounded-[44rpx] text-[32rpx] text-white h-[88rpx]! w-[493rpx]!"
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" open-type="getPhoneNumber"
|
||||
:disabled="checked.length === 0" @click.stop="handleClick" @getphonenumber="getPhoneNumber"
|
||||
>
|
||||
一键登录
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button
|
||||
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center "
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick">
|
||||
class="mb-[40rpx] flex items-center justify-center rounded-[44rpx] text-[32rpx] text-white h-[88rpx]! w-[493rpx]!"
|
||||
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'" @click.stop="handleClick"
|
||||
>
|
||||
一键登录
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="flex items-center flex-nowrap">
|
||||
<view class="flex flex-nowrap items-center">
|
||||
<CheckboxGroup v-model="checked" class="check-class mr-[10rpx]">
|
||||
<Checkbox name="1" cell shape="button" class="custom-checkbox"></Checkbox>
|
||||
<Checkbox name="1" cell shape="button" class="custom-checkbox" />
|
||||
</CheckboxGroup>
|
||||
|
||||
<view class="flex items-center">
|
||||
<text class="text-[24rpx] whitespace-nowrap">
|
||||
<text class="whitespace-nowrap text-[24rpx]">
|
||||
已阅读并同意
|
||||
<text class="text-[#1580FF]" @click.stop="handleClickUserAgreement">
|
||||
<text>《用户协议》</text>
|
||||
|
|
|
|||
|
|
@ -1,53 +1,50 @@
|
|||
<script lang="ts" setup>
|
||||
import { useUserStore,useTokenStore } from '@/store'
|
||||
|
||||
import { getAssistant } from '@/service'
|
||||
|
||||
import { useTokenStore, useUserStore } from '@/store'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '六纬AI小助手',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
style: {
|
||||
navigationBarTitleText: '六纬AI小助手',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
const tokenStore = useTokenStore()
|
||||
|
||||
|
||||
//chat.ycymedu.com
|
||||
//chatv2.ycymedu.com
|
||||
// chat.ycymedu.com
|
||||
// chatv2.ycymedu.com
|
||||
const url = ref(``)
|
||||
|
||||
const handleChildMessage = (event) => {
|
||||
console.log('子应用传递的消息', event)
|
||||
function handleChildMessage(event) {
|
||||
console.log('子应用传递的消息', event)
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
getAssistant().then((res) => {
|
||||
if (res.code === 200) {
|
||||
const data = res.result as unknown as string
|
||||
url.value = `${data}?userId=${userStore.userInfo.userExtend.wxId}&token=${tokenStore.validToken}×tamp=${new Date().getTime()}`
|
||||
}
|
||||
if (options.id) {
|
||||
url.value += `&reportId=${options.id}`
|
||||
}
|
||||
if (options.type) {
|
||||
url.value += `&reportType=${options.type}`
|
||||
}
|
||||
if (options.fileId) {
|
||||
url.value += `&fileId=${options.fileId}`
|
||||
}
|
||||
if (options.talentTypeId){
|
||||
url.value +=`&talentTypeId=${options.talentTypeId}`
|
||||
}
|
||||
})
|
||||
getAssistant().then((res) => {
|
||||
if (res.code === 200) {
|
||||
const data = res.result as unknown as string
|
||||
url.value = `${data}?userId=${userStore.userInfo.userExtend.wxId}&token=${tokenStore.validToken}×tamp=${new Date().getTime()}`
|
||||
}
|
||||
if (options.id) {
|
||||
url.value += `&reportId=${options.id}`
|
||||
}
|
||||
if (options.type) {
|
||||
url.value += `&reportType=${options.type}`
|
||||
}
|
||||
if (options.fileId) {
|
||||
url.value += `&fileId=${options.fileId}`
|
||||
}
|
||||
if (options.talentTypeId) {
|
||||
url.value += `&talentTypeId=${options.talentTypeId}`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<web-view :src="url" @message="handleChildMessage" :update-title="false" />
|
||||
<web-view :src="url" :update-title="false" @message="handleChildMessage" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -18,11 +18,14 @@ function navigateToVideoFn() {
|
|||
}
|
||||
|
||||
onLoad(() => {
|
||||
uni.getChannelsLiveInfo({
|
||||
uni.getChannelsLiveNoticeInfo({
|
||||
finderUserName: 'sphju9MCfZetYHP',
|
||||
success: (res) => {
|
||||
console.log('res', res)
|
||||
},
|
||||
fail: (res) => {
|
||||
console.log(res)
|
||||
},
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,47 @@
|
|||
<script lang="ts" setup>
|
||||
import { getNewsDetail } from "@/service"
|
||||
import { getNewsDetail } from '@/service'
|
||||
|
||||
const newsDetail = ref({ title: '', publishTime: "", remark: "",content:"" })
|
||||
const newsDetail = ref({ title: '', publishTime: '', remark: '', content: '' })
|
||||
|
||||
onLoad(options => {
|
||||
if (options.id) {
|
||||
getNewsDetail({ query: { id: options.id } }).then(resp => {
|
||||
if (resp.code == 200) {
|
||||
newsDetail.value = resp.result
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.showModal({ title: "没有获取到新闻ID" })
|
||||
}
|
||||
onLoad((options) => {
|
||||
if (options.id) {
|
||||
getNewsDetail({ query: { id: options.id } }).then((resp) => {
|
||||
if (resp.code === 200) {
|
||||
newsDetail.value = resp.result
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
uni.showModal({ title: '没有获取到新闻ID' })
|
||||
}
|
||||
})
|
||||
|
||||
const navigateToCustom = () => {
|
||||
uni.navigateTo({url:"/pages-sub/about/onlineCustom"})
|
||||
function navigateToCustom() {
|
||||
uni.navigateTo({ url: '/pages-sub/about/onlineCustom' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="pt-[30rpx] px-[30rpx] pb-safe">
|
||||
<view class="text-[40rpx] font-600 text-[#000]">{{ newsDetail.title }}</view>
|
||||
<view class="text-[#999] text-[28rpx] mt-[8rpx]">发布时间: {{ newsDetail.publishTime }}</view>
|
||||
<view class="border-b-[2rpx] border-b-dashed border-b-[#D8D8D8] mt-[20rpx] mb-[30rpx]"></view>
|
||||
<view class="pt-[30rpx]">
|
||||
<view v-html="newsDetail.content"></view>
|
||||
</view>
|
||||
|
||||
<view class="fixed right-[20rpx] bottom-[120rpx] w-[160rpx] h-[160rpx]" @click="navigateToCustom">
|
||||
<image src="https://lwzk.ycymedu.com/img/qt/qt_more.png" mode="scaleToFill"
|
||||
class="w-[160rpx] h-[160rpx]" />
|
||||
</view>
|
||||
<view class="px-[30rpx] pt-[30rpx] pb-safe">
|
||||
<view class="text-[40rpx] text-[#000] font-600">
|
||||
{{ newsDetail.title }}
|
||||
</view>
|
||||
<view class="mt-[8rpx] text-[28rpx] text-[#999]">
|
||||
发布时间: {{ newsDetail.publishTime }}
|
||||
</view>
|
||||
<view class="mb-[30rpx] mt-[20rpx] border-b-[2rpx] border-b-[#D8D8D8] border-b-dashed" />
|
||||
<view class="pt-[30rpx]">
|
||||
<!-- <view v-html="newsDetail.content" /> -->
|
||||
<rich-text :nodes="newsDetail.content" />
|
||||
</view>
|
||||
|
||||
<view class="fixed bottom-[120rpx] right-[20rpx] h-[160rpx] w-[160rpx]" @click="navigateToCustom">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/qt_more.png" mode="scaleToFill"
|
||||
class="h-[160rpx] w-[160rpx]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,18 @@
|
|||
<script lang="ts" setup>
|
||||
import { trackPromoterRedirect } from '@/service'
|
||||
import { useInviteStore } from '@/store/invite'
|
||||
import { getLiveLinks, trackPromoterRedirect } from '@/service'
|
||||
|
||||
const inviteStore = useInviteStore()
|
||||
let referralCode = ''
|
||||
let weChatLiveId = ''
|
||||
let douyinLiveUrl = ''
|
||||
|
||||
onLoad(() => {
|
||||
const referralCode = inviteStore.currentPromoter?.referralCode
|
||||
if (!referralCode) {
|
||||
return
|
||||
}
|
||||
onLoad((options) => {
|
||||
referralCode = options?.referralCode || ''
|
||||
|
||||
trackPromoterRedirect(referralCode).then((resp: any) => {
|
||||
weChatLiveId = resp?.liveLinks?.wechatLiveUrl || 'sphju9MCfZetYHP'
|
||||
douyinLiveUrl = resp?.liveLinks?.douyinLiveUrl || ''
|
||||
getLiveLinks().then((resp) => {
|
||||
weChatLiveId = resp?.wechatLiveUrl || ''
|
||||
douyinLiveUrl = resp?.douyinLiveUrl || ''
|
||||
}).catch((error) => {
|
||||
console.error('[redirect]', error)
|
||||
console.error('[live-links]', error)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -28,7 +24,12 @@ function navigateToVideoFn() {
|
|||
uni.openChannelsLive({
|
||||
finderUserName: weChatLiveId,
|
||||
success: () => {
|
||||
|
||||
if (!referralCode) {
|
||||
return
|
||||
}
|
||||
trackPromoterRedirect(referralCode).catch((error) => {
|
||||
console.error('[redirect]', error)
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('跳转失败:', err)
|
||||
|
|
@ -41,6 +42,12 @@ function navigateToDouyinFn() {
|
|||
uni.showToast({ title: '直播链接获取中,请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!referralCode) {
|
||||
return
|
||||
}
|
||||
trackPromoterRedirect(referralCode).catch((error) => {
|
||||
console.error('[redirect]', error)
|
||||
})
|
||||
uni.setClipboardData({
|
||||
data: douyinLiveUrl,
|
||||
success: () => {
|
||||
|
|
@ -69,7 +76,7 @@ function navigateToDouyinFn() {
|
|||
|
||||
<view class="mt-[80rpx] px-[54rpx]">
|
||||
<view class="w-full flex items-center justify-center gap-[16rpx] rounded-[210rpx] bg-[#1580FF] py-[30rpx] text-white font-500" @click="navigateToVideoFn">
|
||||
<view class="h-[39rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<view class="h-[52rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/shipin.png"
|
||||
mode="widthFix"
|
||||
|
|
@ -79,7 +86,7 @@ function navigateToDouyinFn() {
|
|||
</view>
|
||||
|
||||
<view class="mt-[48rpx] w-full flex items-center justify-center gap-[16rpx] border-1 border-[#1580FF] rounded-[210rpx] border-solid bg-white py-[30rpx] text-[#1580FF] font-500" @click="navigateToDouyinFn">
|
||||
<view class="h-[39rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<view class="h-[52rpx] w-[46rpx] rounded-[210rpx] text-[32rpx]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/douyin.png"
|
||||
mode="widthFix"
|
||||
|
|
|
|||
|
|
@ -107,11 +107,6 @@ onShareAppMessage(() => {
|
|||
imageUrl: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/zhuanshumafenxiangtu.png',
|
||||
}
|
||||
})
|
||||
onShareTimeline(() => {
|
||||
return {
|
||||
title: '六纬中考通',
|
||||
}
|
||||
})
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
return form.name.trim().length > 0 && /^1[3-9]\d{9}$/.test(form.phone)
|
||||
|
|
|
|||
|
|
@ -1,245 +1,24 @@
|
|||
<template>
|
||||
<view class="min-h-screen flex flex-col items-center bg-[#F6F8FB]">
|
||||
<canvas
|
||||
id="poster"
|
||||
canvas-id="poster"
|
||||
class="block"
|
||||
:style="{ width: `${canvasWidth}px`, height: `${canvasHeight}px` }"
|
||||
<view class="min-h-screen flex flex-col items-center bg-[#313131]">
|
||||
<image
|
||||
src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/zhuanshuyaoqing.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<view v-if="errorMessage" class="mt-[40rpx] px-[40rpx] text-center text-[26rpx] text-[#EB5241] leading-[1.5]">
|
||||
{{ errorMessage }}
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-[30rpx] mt-auto w-full gap-[20rpx] bg-[#fff] pt-[12rpx] pb-safe">
|
||||
<button
|
||||
class="ml-[30rpx] mr-0 h-[88rpx] rounded-[12rpx] border-none bg-[#F5F5F5] text-[32rpx] text-[#333]"
|
||||
@click="handleRegenerate"
|
||||
>
|
||||
重新生成
|
||||
</button>
|
||||
<button
|
||||
class="ml-0 mr-[30rpx] h-[88rpx] rounded-[12rpx] border-none bg-[#1580FF] text-[32rpx] text-[#fff]"
|
||||
@click="handleSave"
|
||||
>
|
||||
保存到手机
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import UQRCode from 'uqrcodejs'
|
||||
import { useInviteStore } from '@/store/invite'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '海报测试',
|
||||
},
|
||||
const inviteStore = useInviteStore()
|
||||
const referralCode = inviteStore.currentPromoter?.referralCode
|
||||
onShareAppMessage(() => {
|
||||
return {
|
||||
title: '六纬中考通',
|
||||
path: `/pages-sub/invite/jump?referralCode=${referralCode}`,
|
||||
imageUrl: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/yaoqingzhibotu.png',
|
||||
}
|
||||
})
|
||||
|
||||
const POSTER_IMAGE_URL = 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/erweima.png'
|
||||
const POSTER_DESIGN_HEIGHT_RPX = 1171
|
||||
|
||||
// 二维码在海报中的位置(设计稿单位 rpx)
|
||||
const QR_OFFSET_LEFT_RPX = 40
|
||||
const QR_OFFSET_TOP_RPX = 991
|
||||
const QR_WIDTH_RPX = 140
|
||||
const QR_HEIGHT_RPX = 140
|
||||
const QR_CONTENT = '你好'
|
||||
|
||||
const { windowWidth } = uni.getSystemInfoSync()
|
||||
|
||||
const canvasWidth = ref(windowWidth)
|
||||
const canvasHeight = ref(uni.upx2px(POSTER_DESIGN_HEIGHT_RPX))
|
||||
const errorMessage = ref('')
|
||||
const saving = ref(false)
|
||||
const posterReady = ref(false)
|
||||
|
||||
onReady(() => {
|
||||
renderPoster()
|
||||
})
|
||||
|
||||
async function renderPoster() {
|
||||
errorMessage.value = ''
|
||||
posterReady.value = false
|
||||
try {
|
||||
await nextTick()
|
||||
const ctx = uni.createCanvasContext('poster')
|
||||
|
||||
// 1. 背景海报
|
||||
const localPath = await getLocalImagePath(POSTER_IMAGE_URL)
|
||||
ctx.drawImage(localPath, 0, 0, canvasWidth.value, canvasHeight.value)
|
||||
|
||||
// 2. 叠加二维码
|
||||
drawQrCode(ctx, QR_CONTENT, {
|
||||
x: uni.upx2px(QR_OFFSET_LEFT_RPX),
|
||||
y: uni.upx2px(QR_OFFSET_TOP_RPX),
|
||||
width: uni.upx2px(QR_WIDTH_RPX),
|
||||
height: uni.upx2px(QR_HEIGHT_RPX),
|
||||
})
|
||||
|
||||
// 3. 一次性提交
|
||||
await new Promise<void>(resolve => ctx.draw(false, () => resolve()))
|
||||
posterReady.value = true
|
||||
}
|
||||
catch (error) {
|
||||
const message = error instanceof Error ? error.message : '海报绘制失败'
|
||||
errorMessage.value = message
|
||||
console.error('[poster]', error)
|
||||
}
|
||||
}
|
||||
|
||||
function handleRegenerate() {
|
||||
uni.showLoading({ title: '重新生成中...', mask: true })
|
||||
renderPoster().finally(() => uni.hideLoading())
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (saving.value) {
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
const tempFilePath = await canvasToTempFile('poster')
|
||||
|
||||
// #ifdef H5
|
||||
downloadFileH5(tempFilePath, 'poster.png')
|
||||
uni.showToast({ title: '已下载到本地', icon: 'success' })
|
||||
// #endif
|
||||
|
||||
// #ifndef H5
|
||||
await ensureAlbumAuth()
|
||||
await saveToAlbum(tempFilePath)
|
||||
uni.showToast({ title: '已保存到相册', icon: 'success' })
|
||||
// #endif
|
||||
}
|
||||
catch (error) {
|
||||
const message = error instanceof Error ? error.message : '保存失败,请稍后重试'
|
||||
uni.showToast({ title: message, icon: 'none' })
|
||||
console.error('[save]', error)
|
||||
}
|
||||
finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
interface QrRect {
|
||||
x: number
|
||||
y: number
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
function drawQrCode(ctx: UniApp.CanvasContext, data: string, rect: QrRect) {
|
||||
const qr = new UQRCode()
|
||||
qr.data = data
|
||||
qr.size = Math.max(rect.width, rect.height) // 仅用于内部生成,实际尺寸由 rect 控制
|
||||
qr.margin = 0
|
||||
qr.make()
|
||||
|
||||
const moduleCount = qr.moduleCount
|
||||
const cellW = rect.width / moduleCount
|
||||
const cellH = rect.height / moduleCount
|
||||
|
||||
// 白底
|
||||
ctx.setFillStyle('#FFFFFF')
|
||||
ctx.fillRect(rect.x, rect.y, rect.width, rect.height)
|
||||
|
||||
// 黑色模块(多 0.5px 重叠避免低像素下出现白色细缝)
|
||||
ctx.setFillStyle('#000000')
|
||||
for (let row = 0; row < moduleCount; row++) {
|
||||
for (let col = 0; col < moduleCount; col++) {
|
||||
if (qr.modules[row][col]?.isBlack) {
|
||||
ctx.fillRect(
|
||||
rect.x + col * cellW,
|
||||
rect.y + row * cellH,
|
||||
cellW + 0.5,
|
||||
cellH + 0.5,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLocalImagePath(src: string) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: res => resolve(res.path),
|
||||
fail: err => reject(new Error(err?.errMsg || '海报背景图加载失败')),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function canvasToTempFile(canvasId: string) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
uni.canvasToTempFilePath({
|
||||
canvasId,
|
||||
fileType: 'png',
|
||||
quality: 1,
|
||||
success: res => resolve(res.tempFilePath),
|
||||
fail: err => reject(new Error(err?.errMsg || '生成图片失败')),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function saveToAlbum(filePath: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath,
|
||||
success: () => resolve(),
|
||||
fail: err => reject(new Error(err?.errMsg || '保存到相册失败')),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 小程序场景下首次保存需用户授权
|
||||
function ensureAlbumAuth() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
uni.getSetting({
|
||||
success: (res) => {
|
||||
const authorized = res.authSetting['scope.writePhotosAlbum']
|
||||
if (authorized || authorized === undefined) {
|
||||
// 已授权 或 还没询问过(直接走 saveImageToPhotosAlbum 会触发系统弹窗)
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '需要您授权保存到相册',
|
||||
success: (modalRes) => {
|
||||
if (!modalRes.confirm) {
|
||||
reject(new Error('已取消保存'))
|
||||
return
|
||||
}
|
||||
uni.openSetting({
|
||||
success: (settingRes) => {
|
||||
if (settingRes.authSetting['scope.writePhotosAlbum']) {
|
||||
resolve()
|
||||
}
|
||||
else {
|
||||
reject(new Error('未授权保存到相册'))
|
||||
}
|
||||
},
|
||||
fail: () => reject(new Error('授权失败')),
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
fail: () => resolve(), // 拿不到设置时直接尝试保存
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
function downloadFileH5(url: string, filename: string) {
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = filename
|
||||
link.style.display = 'none'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
// #endif
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts" setup>
|
||||
import { safeAreaInsets,systemInfo } from '@/utils/systemInfo'
|
||||
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
import { useUserStore } from '@/store'
|
||||
import { useTokenStore } from '@/store/token'
|
||||
import { safeAreaInsets, systemInfo } from '@/utils/systemInfo'
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
definePage({
|
||||
|
|
@ -19,7 +19,7 @@ definePage({
|
|||
style: {
|
||||
navigationStyle: 'custom',
|
||||
transparentTitle: 'always',
|
||||
navigationBarTitleText: ''
|
||||
navigationBarTitleText: '',
|
||||
},
|
||||
excludeLoginPath: true,
|
||||
})
|
||||
|
|
@ -30,88 +30,107 @@ const tokenStore = useTokenStore()
|
|||
// 使用storeToRefs解构userInfo
|
||||
const { userInfo } = storeToRefs(userStore)
|
||||
|
||||
const topMenuList = [{ name: '我的志愿表', img: 'https://lwzk.ycymedu.com/img/qt/wd_biao.png', url: '/pages-sub/me/wishlist' }, { name: '我的测评', img: 'https://lwzk.ycymedu.com/img/qt/wd_cp.png', url: '/pages-sub/me/evaluation' }]
|
||||
const bottomMenuList = [
|
||||
{ name: '收藏院校', img: 'https://lwzk.ycymedu.com/img/qt/wd_shoucang.png', url: '/pages-sub/me/starSchool' },
|
||||
{ name: '联系客服', img: 'https://lwzk.ycymedu.com/img/qt/wd_kefu.png', url: '/pages-sub/about/onlineCustom' },
|
||||
{ name: '关于我们', img: 'https://lwzk.ycymedu.com/img/qt/wd_guanyu.png', url: '/pages-sub/about/about' },
|
||||
{ name: '直播码注册', img: 'https://lw-zk.oss-cn-hangzhou.aliyuncs.com/liebian/wd_liebian.png', url: '/pages-sub/invite/login' },
|
||||
]
|
||||
|
||||
|
||||
const topMenuList = [{ name: '我的志愿表', img: 'https://lwzk.ycymedu.com/img/qt/wd_biao.png',url:'/pages-sub/me/wishlist' }, { name: "我的测评", img: 'https://lwzk.ycymedu.com/img/qt/wd_cp.png',url:'/pages-sub/me/evaluation' }]
|
||||
const bottomMenuList = [{ name: '收藏院校', img: 'https://lwzk.ycymedu.com/img/qt/wd_shoucang.png',url:"/pages-sub/me/starSchool" }, { name: '联系客服', img: 'https://lwzk.ycymedu.com/img/qt/wd_kefu.png', url:"/pages-sub/about/onlineCustom" }, { name: '关于我们', img: 'https://lwzk.ycymedu.com/img/qt/wd_guanyu.png',url:'/pages-sub/about/about' }]
|
||||
|
||||
const navigateToUrl = (url:string) => {
|
||||
uni.navigateTo({url})
|
||||
function navigateToUrl(url: string) {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
const navigateToUserInfo = () => {
|
||||
uni.navigateTo({url:"/pages-sub/about/userInfo"})
|
||||
function navigateToUserInfo() {
|
||||
uni.navigateTo({ url: '/pages-sub/about/userInfo' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view :class="`custom-background`" :style="{height:`calc(100vh - 50px - ${safeAreaInsets.bottom}px)`}">
|
||||
<sar-navbar :fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }">
|
||||
<view class="custom-background" :style="{ height: `calc(100vh - 50px - ${safeAreaInsets.bottom}px)` }">
|
||||
<sar-navbar
|
||||
:fixed="true" fixation-style="top:unset;"
|
||||
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-height': `${systemInfo?.statusBarHeight + 44}px` }"
|
||||
>
|
||||
<template #title>
|
||||
<view :style="{ 'padding-top': `${systemInfo?.statusBarHeight}px` }" class="flex justify-center">
|
||||
我的
|
||||
</view>
|
||||
</template>
|
||||
</sar-navbar>
|
||||
<view class="flex items-center justify-between px-[50rpx] my-[50rpx]">
|
||||
<view class="my-[50rpx] flex items-center justify-between px-[50rpx]">
|
||||
<view class="flex">
|
||||
<view class="w-[132rpx] h-[132rpx]">
|
||||
<image :src="`${userInfo.avatar}`" mode="scaleToFill"
|
||||
class="w-[132rpx] h-[132rpx] rounded-full" />
|
||||
<view class="h-[132rpx] w-[132rpx]">
|
||||
<image
|
||||
:src="`${userInfo.avatar}`" mode="scaleToFill"
|
||||
class="h-[132rpx] w-[132rpx] rounded-full"
|
||||
/>
|
||||
</view>
|
||||
<view class="ml-[32rpx]">
|
||||
<view class="text-[44rpx] font-500 mb-[10rpx]">{{ userInfo.nickName }}</view>
|
||||
<view class="text-[#666] text-[32rpx]">{{ userInfo.mobile }}</view>
|
||||
<view class="mb-[10rpx] text-[44rpx] font-500">
|
||||
{{ userInfo.nickName }}
|
||||
</view>
|
||||
<view class="text-[32rpx] text-[#666]">
|
||||
{{ userInfo.mobile }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center" @click="navigateToUserInfo">
|
||||
<view class="w-[48rpx] h-[48rpx]">
|
||||
<image src="https://lwzk.ycymedu.com/img/qt/wd_bianji.png" mode="scaleToFill"
|
||||
class="w-[48rpx] h-[48rpx]" />
|
||||
<view class="h-[48rpx] w-[48rpx]">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/wd_bianji.png" mode="scaleToFill"
|
||||
class="h-[48rpx] w-[48rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#333]">
|
||||
编辑
|
||||
</view>
|
||||
<view class="text-[30rpx] text-[#333]">编辑</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-2 gap-[28rpx] items-center justify-between px-[30rpx]">
|
||||
<view class="grid grid-cols-2 items-center justify-between gap-[28rpx] px-[30rpx]">
|
||||
<view
|
||||
class="rounded-[20rpx] flex items-center px-[50rpx] py-[44rpx] bg-[#E4EEFF] border-[2rpx] border-solid border-white"
|
||||
v-for="(value, index) in topMenuList" :key="index" @click="navigateToUrl(value.url)">
|
||||
<view class="w-[48rpx] h-[48rpx] mr-[10rpx]">
|
||||
<image :src="value.img" mode="scaleToFill" class="w-[48rpx] h-[48rpx]" />
|
||||
v-for="(value, index) in topMenuList"
|
||||
:key="index" class="flex items-center border-[2rpx] border-white rounded-[20rpx] border-solid bg-[#E4EEFF] px-[50rpx] py-[44rpx]" @click="navigateToUrl(value.url)"
|
||||
>
|
||||
<view class="mr-[10rpx] h-[48rpx] w-[48rpx]">
|
||||
<image :src="value.img" mode="scaleToFill" class="h-[48rpx] w-[48rpx]" />
|
||||
</view>
|
||||
<view>{{ value.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="px-[30rpx] pt-[30rpx] mx-[30rpx] rounded-[20rpx] bg-white mt-[30rpx]">
|
||||
<view class="text-[34rpx] font-500">其他功能</view>
|
||||
<view class="flex items-center py-[34rpx] not-last:border-b-[2rpx] not-last:border-b-solid not-last:border-b-[#EDEDED]" v-for="(value,index) in bottomMenuList" :key="index" @click="navigateToUrl(value.url)">
|
||||
<view class="w-[44rpx] h-[44rpx] flex items-center">
|
||||
<view class="mx-[30rpx] mt-[30rpx] rounded-[20rpx] bg-white px-[30rpx] pt-[30rpx]">
|
||||
<view class="text-[34rpx] font-500">
|
||||
其他功能
|
||||
</view>
|
||||
<view v-for="(value, index) in bottomMenuList" :key="index" class="flex items-center py-[34rpx] not-last:border-b-[2rpx] not-last:border-b-[#EDEDED] not-last:border-b-solid" @click="navigateToUrl(value.url)">
|
||||
<view class="h-[44rpx] w-[44rpx] flex items-center">
|
||||
<image
|
||||
:src="value.img"
|
||||
mode="scaleToFill"
|
||||
class="w-[44rpx] h-[44rpx]"
|
||||
class="h-[44rpx] w-[44rpx]"
|
||||
/>
|
||||
</view>
|
||||
<view class="text-[32rpx] ml-[16rpx]">{{ value.name }}</view>
|
||||
<view class="w-[18rpx] h-[36rpx] ml-auto flex items-center">
|
||||
<view class="ml-[16rpx] text-[32rpx]">
|
||||
{{ value.name }}
|
||||
</view>
|
||||
<view class="ml-auto h-[36rpx] w-[18rpx] flex items-center">
|
||||
<image
|
||||
src="https://lwzk.ycymedu.com/img/qt/tb_jiantou.png"
|
||||
mode="scaleToFill"
|
||||
class="w-[18rpx] h-[36rpx]"
|
||||
class="h-[36rpx] w-[18rpx]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-background {
|
||||
background: linear-gradient(180deg, #C7E0FF 0%, #f8f8f8 530rpx);
|
||||
background: linear-gradient(180deg, #c7e0ff 0%, #f8f8f8 530rpx);
|
||||
background-position: 50% 50%;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
|
|
|
|||
|
|
@ -81,3 +81,36 @@ export const trackPromoterRedirect = (referralCode: string) => {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
export interface LiveLinks {
|
||||
id: string
|
||||
wechatLiveUrl: string
|
||||
douyinLiveUrl: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
const LIVE_LINKS_API_URL = 'https://liveroom.ycymedu.com/api/h5/live-links'
|
||||
|
||||
export const getLiveLinks = () => {
|
||||
return new Promise<LiveLinks>((resolve, reject) => {
|
||||
uni.request({
|
||||
url: LIVE_LINKS_API_URL,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'x-api-key': INVITE_API_KEY,
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data as LiveLinks)
|
||||
return
|
||||
}
|
||||
|
||||
reject(new Error(getInviteErrorMessage(res.data)))
|
||||
},
|
||||
fail: () => {
|
||||
reject(new Error('请求失败,请稍后重试'))
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export type AiRole = 'user' | 'assistant' | 'system'
|
||||
|
||||
export interface AiMessage {
|
||||
id: string
|
||||
role: AiRole
|
||||
content: string
|
||||
/** 是否仍在流式生成中,用于 UI 展示打字光标 */
|
||||
pending?: boolean
|
||||
/** 标记本条消息是否出错,UI 显示重试按钮 */
|
||||
error?: boolean
|
||||
createdAt: number
|
||||
}
|
||||
|
||||
export const useAiStore = defineStore(
|
||||
'ai',
|
||||
() => {
|
||||
const messages = ref<AiMessage[]>([])
|
||||
/** 一组对话共用同一个 thread,跨多轮维持上下文 */
|
||||
const threadId = ref('')
|
||||
|
||||
const messageCount = computed(() => messages.value.length)
|
||||
|
||||
function ensureThreadId() {
|
||||
if (!threadId.value) {
|
||||
threadId.value = `thread_id_${Date.now()}${Math.floor(Math.random() * 10000)}`
|
||||
}
|
||||
return threadId.value
|
||||
}
|
||||
|
||||
function addMessage(message: AiMessage) {
|
||||
messages.value.push(message)
|
||||
}
|
||||
|
||||
function updateMessage(id: string, patch: Partial<AiMessage>) {
|
||||
const target = messages.value.find(m => m.id === id)
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
Object.assign(target, patch)
|
||||
}
|
||||
|
||||
function appendDelta(id: string, delta: string) {
|
||||
const target = messages.value.find(m => m.id === id)
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
target.content += delta
|
||||
}
|
||||
|
||||
function removeMessage(id: string) {
|
||||
messages.value = messages.value.filter(m => m.id !== id)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
messages.value = []
|
||||
threadId.value = ''
|
||||
}
|
||||
|
||||
return {
|
||||
messages,
|
||||
threadId,
|
||||
messageCount,
|
||||
ensureThreadId,
|
||||
addMessage,
|
||||
updateMessage,
|
||||
appendDelta,
|
||||
removeMessage,
|
||||
clear,
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: true,
|
||||
},
|
||||
)
|
||||
|
|
@ -16,6 +16,7 @@ setActivePinia(store)
|
|||
export default store
|
||||
|
||||
// 模块统一导出
|
||||
export * from './ai'
|
||||
export * from './invite'
|
||||
export * from './token'
|
||||
export * from './user'
|
||||
|
|
|
|||
|
|
@ -158,9 +158,9 @@ export const isDoubleTokenMode = import.meta.env.VITE_AUTH_MODE === 'double'
|
|||
*/
|
||||
export const HOME_PAGE = `/${(pages as PageMetaDatum[]).find(page => page.type === 'home')?.path || (pages as PageMetaDatum[])[0].path}`
|
||||
|
||||
export const checkEmptyValues=(obj: Record<string, any>, keys: string[]): boolean=> {
|
||||
return keys.some(key => {
|
||||
const value = obj[key];
|
||||
return value === '' || value === null || value === undefined;
|
||||
});
|
||||
}
|
||||
export function checkEmptyValues(obj: Record<string, any>, keys: string[]): boolean {
|
||||
return keys.some((key) => {
|
||||
const value = obj[key]
|
||||
return value === '' || value === null || value === undefined
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,231 @@
|
|||
// components/agent-ui-new/chatFIle/chatFile.js
|
||||
import { getCloudInstance, compareVersions, commonRequest } from "../tools";
|
||||
Component({
|
||||
lifetimes: {
|
||||
attached: async function () {
|
||||
console.log("enableDel", this.data.enableDel);
|
||||
const { tempFileName, rawFileName, rawType, tempPath, fileId, botId, status } = this.data.fileData;
|
||||
const type = this.getFileType(rawFileName || tempFileName);
|
||||
console.log("type", type);
|
||||
if (!fileId) {
|
||||
this.setData({
|
||||
iconPath: "../imgs/" + type + ".svg",
|
||||
});
|
||||
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, status: "uploading" });
|
||||
}
|
||||
|
||||
if (fileId && status === "parsed") {
|
||||
this.setData({
|
||||
iconPath: "../imgs/" + type + ".svg",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const cloudInstance = await getCloudInstance();
|
||||
// console.log('file', cloudInstance)
|
||||
// 上传云存储获取 fileId
|
||||
// console.log('rawFileName tempFileName tempPath', rawFileName, tempFileName, tempPath)
|
||||
cloudInstance.uploadFile({
|
||||
cloudPath: this.generateCosUploadPath(
|
||||
botId,
|
||||
rawFileName ? rawFileName.split(".")[0] + "-" + tempFileName : tempFileName
|
||||
), // 云上文件路径
|
||||
filePath: tempPath,
|
||||
success: async (res) => {
|
||||
const appBaseInfo = wx.getAppBaseInfo();
|
||||
const fileId = res.fileID;
|
||||
console.log("当前版本", appBaseInfo.SDKVersion);
|
||||
if (botId.startsWith("ibot")) {
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parsed" });
|
||||
} else {
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, status: "parsing" });
|
||||
commonRequest({
|
||||
path: `bots/${botId}/files`,
|
||||
data: {
|
||||
fileList: [
|
||||
{
|
||||
fileName: rawFileName || tempFileName,
|
||||
fileId,
|
||||
type: rawType,
|
||||
},
|
||||
],
|
||||
}, // any
|
||||
method: "POST",
|
||||
timeout: 60000,
|
||||
success: (res) => {
|
||||
console.log("resolve agent file res", res);
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parsed" });
|
||||
},
|
||||
fail: (e) => {
|
||||
console.log("e", e);
|
||||
this.triggerEvent("changeChild", { tempId: this.data.fileData.tempId, fileId, status: "parseFailed" });
|
||||
},
|
||||
complete: () => {},
|
||||
header: {},
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error("上传失败:", err);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
observers: {
|
||||
"fileData.status": function (status) {
|
||||
this.setData({
|
||||
statusTxt: this.getFormatStatusText(status),
|
||||
});
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
enableDel: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
fileData: {
|
||||
type: Object,
|
||||
value: {
|
||||
tempId: "",
|
||||
rawType: "",
|
||||
tempFileName: "",
|
||||
rawFileName: "",
|
||||
tempPath: "",
|
||||
fileSize: 0,
|
||||
fileUrl: "",
|
||||
fileId: "",
|
||||
status: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
formatSize: "",
|
||||
iconPath: "../imgs/file.svg",
|
||||
statusTextMap: {
|
||||
uploading: "上传中",
|
||||
parsing: "解析中",
|
||||
parseFailed: "解析失败",
|
||||
},
|
||||
statusTxt: "",
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表,
|
||||
*/
|
||||
methods: {
|
||||
getFormatStatusText: function (status) {
|
||||
if (status === "parsed") {
|
||||
return this.transformSize(this.data.fileData.fileSize);
|
||||
}
|
||||
return this.data.statusTextMap[status] || "";
|
||||
},
|
||||
generateCosUploadPath: function (botId, fileName) {
|
||||
return `agent_file/${botId}/${fileName}`;
|
||||
},
|
||||
// 提取文件后缀
|
||||
getFileType: function (fileName) {
|
||||
let index = fileName.lastIndexOf(".");
|
||||
const fileExt = fileName.substring(index + 1);
|
||||
if (fileExt === "docx" || fileExt === "doc") {
|
||||
return "word";
|
||||
}
|
||||
if (fileExt === "xlsx" || fileExt === "xls" || fileExt === "csv") {
|
||||
return "excel";
|
||||
}
|
||||
if (fileExt === "png" || fileExt === "jpg" || fileExt === "jpeg" || fileExt === "svg") {
|
||||
return "image";
|
||||
}
|
||||
|
||||
if (fileExt === "ppt" || fileExt === "pptx") {
|
||||
return "ppt";
|
||||
}
|
||||
|
||||
if (fileExt === "pdf") {
|
||||
return "pdf";
|
||||
}
|
||||
return "file";
|
||||
},
|
||||
// 转换文件大小(原始单位为B)
|
||||
transformSize: function (size) {
|
||||
if (size < 1024) {
|
||||
return size + "B";
|
||||
} else if (size < 1024 * 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB";
|
||||
} else {
|
||||
return (size / 1024 / 1024).toFixed(2) + "MB";
|
||||
}
|
||||
},
|
||||
removeFileFromParents: function () {
|
||||
console.log("remove", this.data.fileData);
|
||||
this.triggerEvent("removeChild", { tempId: this.data.fileData.tempId });
|
||||
},
|
||||
openFileByWx: function (tempPath) {
|
||||
const fileExt = tempPath.split(".")[1];
|
||||
if (["doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"].includes(fileExt)) {
|
||||
wx.openDocument({
|
||||
filePath: tempPath,
|
||||
success: function (res) {
|
||||
console.log("打开文档成功");
|
||||
},
|
||||
fail: function (err) {
|
||||
console.log("打开文档失败", err);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
wx.showModal({
|
||||
content: "当前支持预览文件类型为 pdf、doc、docx、ppt、pptx、xls、xlsx",
|
||||
showCancel: false,
|
||||
confirmText: "确定",
|
||||
});
|
||||
}
|
||||
},
|
||||
previewImageByWx: function (fileId) {
|
||||
wx.previewImage({
|
||||
urls: [fileId],
|
||||
showmenu: true,
|
||||
success: function (res) {
|
||||
console.log("previewImage res", res);
|
||||
},
|
||||
fail: function (e) {
|
||||
console.log("previewImage e", e);
|
||||
},
|
||||
});
|
||||
},
|
||||
openFile: async function () {
|
||||
if (this.data.fileData.tempPath) {
|
||||
// 本地上传的文件
|
||||
if (this.data.fileData.rawType === "file") {
|
||||
this.openFileByWx(this.data.fileData.tempPath);
|
||||
} else {
|
||||
console.log("fileId", this.data.fileData.fileId);
|
||||
if (this.data.fileData.fileId) {
|
||||
this.previewImageByWx(this.data.fileData.fileId);
|
||||
}
|
||||
}
|
||||
} else if (this.data.fileData.fileId) {
|
||||
// 针对历史记录中带cloudID的处理(历史记录中附带的文件)
|
||||
const cloudInsatnce = await getCloudInstance();
|
||||
cloudInsatnce.downloadFile({
|
||||
fileID: this.data.fileData.fileId,
|
||||
success: (res) => {
|
||||
console.log("download res", res);
|
||||
if (this.data.fileData.rawType === "file") {
|
||||
this.openFileByWx(res.tempFilePath);
|
||||
} else {
|
||||
this.previewImageByWx(this.data.fileData.fileId);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("download err", err);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!--components/agent-ui-new/chatFIle/chatFile.wxml-->
|
||||
<!-- <text>components/agent-ui-new/chatFIle/chatFile.wxml</text> -->
|
||||
<view class="chat_file" bind:tap="openFile">
|
||||
<view class="chat_file__content">
|
||||
<image class="chat_file__icon" src="{{iconPath}}" />
|
||||
<view class="chat_file__info">
|
||||
<view class="chat_file__name">{{fileData.rawFileName || fileData.tempFileName}}</view>
|
||||
<view class="chat_file__size">{{statusTxt}}
|
||||
<image wx:if="{{fileData.status === 'uploading' || fileData.status === 'parsing'}}" style="width: 15px;height:15px;margin-left: 5px" src="../imgs/loading.svg" mode=""/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<image wx:if="{{enableDel}}" bind:tap="removeFileFromParents" style="width: 15px;height: 15px;position: absolute;top: -7px;right: -7px" src="../imgs/close-filled.png" mode="aspectFill"/>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/* components/agent-ui-new/chatFIle/chatFile.wxss */
|
||||
.chat_file {
|
||||
padding: 16rpx 24rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
/* box-shadow: 0 1px 8px rgba(0, 0, 0, 0.253); */
|
||||
/* margin: 0rpx 5rpx; */
|
||||
/* max-width: 110px; */
|
||||
width: 110px;
|
||||
position: relative;
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.chat_file:active {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.chat_file__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.chat_file__icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat_file__info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.chat_file__name {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 8rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.chat_file__size {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// components/agent-ui/collapsibleCard/index.js
|
||||
Component({
|
||||
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
initStatus: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
showBgColor:{
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
showExpandIcon: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
collapsedStatus: false
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.setData({ collapsedStatus: this.properties.initStatus })
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
changeCollapsedStatus: function () {
|
||||
this.setData({ collapsedStatus: !this.data.collapsedStatus })
|
||||
}
|
||||
},
|
||||
options: {
|
||||
multipleSlots: true
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<!--components/agent-ui/collapsibleCard/index.wxml-->
|
||||
<view class="collapse" style="{{collapsedStatus&&showBgColor?'background-color: #f5f5f5;':''}}">
|
||||
<view class="collapse-header" bind:tap="changeCollapsedStatus">
|
||||
<image wx:if="{{showExpandIcon}}" src="../imgs/arrow.svg" mode="aspectFill" style="width: 16px;height: 16px;transform: rotate({{collapsedStatus?360:270}}deg);" />
|
||||
<slot name="title"></slot>
|
||||
</view>
|
||||
<block wx:if="{{collapsedStatus}}">
|
||||
<slot name="content"></slot>
|
||||
</block>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* components/agent-ui/collapsibleCard/index.wxss */
|
||||
.collapse{
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.collapse-header {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background-color: #f5f5f5;
|
||||
justify-content: space-between;
|
||||
padding: 18rpx 26rpx;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Component({
|
||||
properties: {
|
||||
name: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
toolParams: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
toolData: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
},
|
||||
data: {},
|
||||
lifetimes: {},
|
||||
});
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<!--components/agent-ui-new/chatFIle/chatFile.wxml-->
|
||||
<!-- <text>components/agent-ui-new/chatFIle/chatFile.wxml</text> -->
|
||||
<!-- <block>
|
||||
<view wx:if="{{name === 'maps_geo' || name === 'maps_direction_driving'}}">
|
||||
<custom-map name="{{name}}" toolData="{{toolData}}"></custom-map>
|
||||
</view>
|
||||
<view wx:if="{{name === 'maps_weather'}}">
|
||||
<custom-weather name="{{name}}" toolData="{{toolData}}"></custom-weather>
|
||||
</view>
|
||||
<view wx:if="{{name === 'map_search_places'}}">
|
||||
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
|
||||
<custom-food-list name="{{name}}" toolData="{{toolData}}"></custom-food-list>
|
||||
</view>
|
||||
</block> -->
|
||||
|
||||
<block>
|
||||
<view class="customCard">
|
||||
<custom-map wx:if="{{name === 'geocoder' || name === 'placeSearchNearby' || 'directionDriving'}}" name="{{name}}" toolParams="{{toolParams}}" toolData="{{toolData}}"></custom-map>
|
||||
</view>
|
||||
<view class="customCard">
|
||||
<custom-weather wx:if="{{name === 'weather'}}" name="{{name}}" toolData="{{toolData}}"></custom-weather>
|
||||
</view>
|
||||
<view class="customCard" wx:if="{{name === 'placeSearchNearby'}}">
|
||||
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
|
||||
</view>
|
||||
<!-- 用户可类似添加自定义组件 -->
|
||||
</block>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
.customCard {
|
||||
margin: 15px 0px;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.0003 0.630371L14.9029 8.98093L23.7417 9.16105L16.6969 14.5021L19.2569 22.964L12.0003 17.9144L4.74363 22.964L7.30367 14.5021L0.258789 9.16105L9.09761 8.98093L12.0003 0.630371ZM12.0003 6.72181L10.5298 10.9522L6.05209 11.0434L9.62099 13.7492L8.32409 18.0359L12.0003 15.4778L15.6764 18.0359L14.3795 13.7492L17.9484 11.0434L13.4707 10.9522L12.0003 6.72181Z" fill="#f2db4a" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 473 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.0003 0.630371L14.9029 8.98093L23.7417 9.16105L16.6969 14.5021L19.2569 22.964L12.0003 17.9144L4.74363 22.964L7.30367 14.5021L0.258789 9.16105L9.09761 8.98093L12.0003 0.630371ZM12.0003 6.72181L10.5298 10.9522L6.05209 11.0434L9.62099 13.7492L8.32409 18.0359L12.0003 15.4778L15.6764 18.0359L14.3795 13.7492L17.9484 11.0434L13.4707 10.9522L12.0003 6.72181Z" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 471 B |
|
|
@ -0,0 +1,277 @@
|
|||
// pages/components/feedback/index.js
|
||||
Component({
|
||||
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
isShowFeedback: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
feedbackRecordId: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
feedbackType: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
botId: {
|
||||
type: String,
|
||||
value: ''
|
||||
},
|
||||
input: {
|
||||
type: String,
|
||||
value: ""
|
||||
},
|
||||
aiAnswer: {
|
||||
type: String,
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
upVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "准确有效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "回答全面"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "立场正确"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式规范"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "专业性强"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "富有创意"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "表达清晰"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "值得信赖"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "高效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "满意"
|
||||
}
|
||||
],
|
||||
downVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "理解错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "未识别问题"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "事实错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "推理错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容不完整"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "不专业"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "违法有害"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "乱码"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容重复"
|
||||
}
|
||||
],
|
||||
score: 5,
|
||||
message: ""
|
||||
},
|
||||
observers:{
|
||||
"feedbackType":function (value) {
|
||||
this.setData({score:value==='upvote'?5:1})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
reset: function () {
|
||||
this.setData({
|
||||
upVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "准确有效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "回答全面"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "立场正确"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式规范"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "专业性强"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "富有创意"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "表达清晰"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "值得信赖"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "高效"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "满意"
|
||||
}
|
||||
],
|
||||
downVote: [
|
||||
{
|
||||
"selected": false,
|
||||
"value": "理解错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "未识别问题"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "事实错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "推理错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容不完整"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "不专业"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "违法有害"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "格式错误"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "乱码"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"value": "内容重复"
|
||||
}
|
||||
],
|
||||
score: 5,
|
||||
message: ""
|
||||
})
|
||||
},
|
||||
onChangeScore: function (e) {
|
||||
const { score } = e.currentTarget.dataset
|
||||
this.setData({ score })
|
||||
},
|
||||
onSelect: function (e) {
|
||||
const { item } = e.currentTarget.dataset
|
||||
const newArr = [...this.data.feedbackType === 'upvote' ? this.data.upVote : this.data.downVote]
|
||||
const [selectedItem] = newArr.filter(i => i.value === item.value)
|
||||
selectedItem.selected = !selectedItem.selected
|
||||
if (this.data.feedbackType === 'upvote') {
|
||||
this.setData({ upVote: newArr })
|
||||
} else {
|
||||
this.setData({ downVote: newArr })
|
||||
}
|
||||
|
||||
},
|
||||
inputChange: function (e) {
|
||||
const value = e.detail.value
|
||||
this.setData({ message: value })
|
||||
},
|
||||
closeShowFeedback: function () {
|
||||
this.triggerEvent('close')
|
||||
},
|
||||
submitFeedback: async function () {
|
||||
const res = await wx.cloud.extend.AI.bot.sendFeedback({
|
||||
userFeedback: {
|
||||
botId: this.data.botId,
|
||||
recordId: this.data.feedbackRecordId,
|
||||
comment: this.data.message,
|
||||
rating: this.data.score,
|
||||
tags: this.data.feedbackType === 'upvote' ? this.data.upVote.filter(item => item.selected).map(item => item.value) : this.data.downVote.filter(item => item.selected).map(item => item.value),
|
||||
aiAnswer: this.data.aiAnswer,
|
||||
input: this.data.input,
|
||||
type: this.data.feedbackType === 'upvote' ? "upvote" : 'downvote',
|
||||
},
|
||||
botId: this.data.botId
|
||||
});
|
||||
if (res.status === 'success') {
|
||||
wx.showToast({
|
||||
title: "感谢反馈",
|
||||
icon: "success",
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: "反馈失败",
|
||||
icon: "fail",
|
||||
});
|
||||
}
|
||||
this.reset();
|
||||
// console.log(res)
|
||||
this.triggerEvent("close")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<view class="feedback-modal" wx:if="{{isShowFeedback}}">
|
||||
<view class="feedback">
|
||||
<view class="feedback-header">
|
||||
感谢您的宝贵反馈,我们会不断改进服务
|
||||
</view>
|
||||
<view class="feedback-body">
|
||||
<view class="item-box">
|
||||
<view class="item-title">评分</view>
|
||||
<view style="display: flex; gap: 14rpx;">
|
||||
<block wx:for="{{[1,2,3,4,5]}}" wx:key="*this">
|
||||
<image src="{{item<=score?'./imgs/star-highlight.svg':'./imgs/star.svg'}}" mode="aspectFill" class="star" bind:touchend="onChangeScore" data-score="{{item}}" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-box">
|
||||
<view class="item-title">回答内容</view>
|
||||
<view>
|
||||
<block wx:for="{{feedbackType==='upvote'?upVote:downVote}}" wx:key="value">
|
||||
<view class="{{item.selected?'vote-item-highlight':'vote-item-normal'}}" bind:tap="onSelect" data-item="{{item}}">{{item.value}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-box">
|
||||
<view class="item-title">反馈建议</view>
|
||||
<view>
|
||||
<textarea value="{{message}}" class="feedback-textarea" maxlength="140" bindinput="inputChange"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="feedback-footer">
|
||||
<view class="btn-cancel" bind:tap="closeShowFeedback">取消</view>
|
||||
<view class="btn-submit" bind:tap="submitFeedback">提交反馈</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/* pages/components/feedback/index.wxss */
|
||||
.feedback-modal {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 750rpx;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feedback {
|
||||
width: 520rpx;
|
||||
max-height: 70%;
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
}
|
||||
.feedback-header{
|
||||
font-weight: 500;
|
||||
font-size: 32rpx;
|
||||
text-align: justify;
|
||||
}
|
||||
.feedback-body{
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.item-box{
|
||||
padding: 28rpx 0px;
|
||||
}
|
||||
.item-title{
|
||||
font-size: 28rpx;
|
||||
padding-bottom: 28rpx;
|
||||
}
|
||||
.star{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.vote-item-normal{
|
||||
display: inline-block;
|
||||
background-color: rgba(243, 243, 243, 1);
|
||||
height: 48rpx;
|
||||
line-height: 48rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.vote-item-highlight{
|
||||
display: inline-block;
|
||||
background-color: rgba(0, 82, 217, 0.1);
|
||||
height: 48rpx;
|
||||
line-height: 48rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
color: rgb(0, 82, 217);
|
||||
}
|
||||
.feedback-textarea{
|
||||
width: 100%;
|
||||
height: 150rpx;
|
||||
border-radius: 16rpx;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
padding: 16rpx;
|
||||
}
|
||||
.feedback-footer{
|
||||
font-size: 28rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.btn-cancel{
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 6rpx;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
.btn-submit{
|
||||
box-sizing: border-box;
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 6rpx;
|
||||
color: #fff;
|
||||
background-color: #0052d9;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.5001 8.08575L12.0002 13.5858L6.50015 8.08576L5.08594 9.49997L12.0002 16.4142L18.9144 9.49997L17.5001 8.08575Z" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 244 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.88197 1.99988H16.118L17.618 4.99988H23V20.9999H1V4.99988H6.38197L7.88197 1.99988ZM9.11803 3.99988L7.61803 6.99988H3V18.9999H21V6.99988H16.382L14.882 3.99988H9.11803ZM12 9.49988C10.3431 9.49988 9 10.843 9 12.4999C9 14.1567 10.3431 15.4999 12 15.4999C13.6569 15.4999 15 14.1567 15 12.4999C15 10.843 13.6569 9.49988 12 9.49988ZM7 12.4999C7 9.73845 9.23858 7.49988 12 7.49988C14.7614 7.49988 17 9.73845 17 12.4999C17 15.2613 14.7614 17.4999 12 17.4999C9.23858 17.4999 7 15.2613 7 12.4999Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 630 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><rect width="2.8" height="12" x="1" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="5.8" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="10.6" y="6" fill="#e84f50"><animate id="svgSpinnersBarsScaleMiddle0" attributeName="y" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="15.4" y="6" fill="#e84f50"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="20.2" y="6" fill="#e84f50"><animate id="svgSpinnersBarsScaleMiddle1" attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 8V11H16V13H13V16H11V13H8V11H11V8H13Z" fill="#4d6bfe" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 470 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 8V11H16V13H13V16H11V13H8V11H11V8H13Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 480 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 14.3966 3.93542 16.5725 5.46305 18.1862L5.96701 18.7185L4.69951 21H12C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23H1.30049L3.51936 19.006C1.94632 17.1038 1 14.6615 1 12ZM13 5.5V11.5858L16.4142 15L15 16.4142L11 12.4142V5.5H13Z" fill="rgb(160, 160, 160)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 497 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.985 7.37845L10.3784 17.985L4.0144 11.6211L5.42862 10.2069L10.3784 15.1566L19.5708 5.96423L20.985 7.37845Z" fill="green" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 237 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 1L15 1L15 9.5L21 9.5L21 23L3 23L3 9.5L9 9.5L9 1ZM11 3L11 11.5L5 11.5V14L19 14L19 11.5H13L13 3L11 3ZM19 16L5 16L5 21H14V18L16 18V21H19V16Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 283 B |
|
After Width: | Height: | Size: 400 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.0502 5.63611L11.9999 10.5859L16.9497 5.63611L18.3639 7.05032L13.4142 12.0001L18.3639 16.9498L16.9497 18.364L11.9999 13.4143L7.0502 18.364L5.63599 16.9498L10.5857 12.0001L5.63599 7.05032L7.0502 5.63611Z" fill="red" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 333 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.0502 5.63611L11.9999 10.5859L16.9497 5.63611L18.3639 7.05032L13.4142 12.0001L18.3639 16.9498L16.9497 18.364L11.9999 13.4143L7.0502 18.364L5.63599 16.9498L10.5857 12.0001L5.63599 7.05032L7.0502 5.63611Z" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 335 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 2H15V7.5H13V4H4V13H7.5V15H2V2ZM9 9H22V22H9V9ZM11 11V20H20V11H11Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 197 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.4278 1.96289L22.0381 7.57319L7.61066 22.0007L2.00037 22.0007L2.00037 16.3904L16.4278 1.96289ZM16.4278 4.79132L13.646 7.57319L16.4278 10.3551L19.2097 7.57319L16.4278 4.79132ZM15.0136 11.7693L12.2318 8.9874L4.00037 17.2188L4.00037 20.0007H6.78224L15.0136 11.7693ZM22.2252 22.0007H12.6821V20.0007L22.2252 20.0007V22.0007Z" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 453 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.0001 3C7.02956 3 3.00012 7.02944 3.00012 12C3.00012 16.9706 7.02956 21 12.0001 21C16.9707 21 21.0001 16.9706 21.0001 12C21.0001 7.02944 16.9707 3 12.0001 3ZM1.00012 12C1.00012 5.92487 5.92499 1 12.0001 1C18.0753 1 23.0001 5.92487 23.0001 12C23.0001 18.0751 18.0753 23 12.0001 23C5.92499 23 1.00012 18.0751 1.00012 12ZM13.0001 6.5V14H11.0001V6.5H13.0001ZM11.0001 15.5H13.004V17.5039H11.0001V15.5Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 532 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><path fill="#20744a" fill-rule="evenodd" d="M28.781 4.405h-10.13V2.018L2 4.588v22.527l16.651 2.868v-3.538h10.13A1.16 1.16 0 0 0 30 25.349V5.5a1.16 1.16 0 0 0-1.219-1.095m.16 21.126H18.617l-.017-1.889h2.487v-2.2h-2.506l-.012-1.3h2.518v-2.2H18.55l-.012-1.3h2.549v-2.2H18.53v-1.3h2.557v-2.2H18.53v-1.3h2.557v-2.2H18.53v-2h10.411Z"/><path fill="#20744a" d="M22.487 7.439h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323zm0 3.501h4.323v2.2h-4.323z"/><path fill="#fff" fill-rule="evenodd" d="m6.347 10.673l2.146-.123l1.349 3.709l1.594-3.862l2.146-.123l-2.606 5.266l2.606 5.279l-2.269-.153l-1.532-4.024l-1.533 3.871l-2.085-.184l2.422-4.663z"/></svg>
|
||||
|
After Width: | Height: | Size: 773 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="20px" height="20px" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 4C4 2.89543 4.89543 2 6 2H10.5858C11.1162 2 11.6249 2.21071 12 2.58579L15.4142 6C15.7893 6.37507 16 6.88378 16 7.41421V16C16 17.1046 15.1046 18 14 18H6C4.89543 18 4 17.1046 4 16V4ZM6 10C6 9.44772 6.44772 9 7 9H13C13.5523 9 14 9.44772 14 10C14 10.5523 13.5523 11 13 11H7C6.44772 11 6 10.5523 6 10ZM7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15H13C13.5523 15 14 14.5523 14 14C14 13.4477 13.5523 13 13 13H7Z" fill="#3895FB"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 598 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 16 16"><g fill="none"><path fill="url(#fluentColorImage162)" d="M2 4.5A2.5 2.5 0 0 1 4.5 2h7A2.5 2.5 0 0 1 14 4.5v7a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 2 11.5z"/><path fill="url(#fluentColorImage160)" d="M13.586 12.879A2.5 2.5 0 0 1 11.5 14h-7a2.5 2.5 0 0 1-2.086-1.121l4.384-4.384a1.7 1.7 0 0 1 2.404 0z"/><path fill="url(#fluentColorImage161)" d="M11.5 5.502a1.002 1.002 0 1 1-2.004 0a1.002 1.002 0 0 1 2.004 0"/><defs><linearGradient id="fluentColorImage160" x1="6.286" x2="7.572" y1="7.997" y2="14.347" gradientUnits="userSpaceOnUse"><stop stop-color="#b3e0ff"/><stop offset="1" stop-color="#8cd0ff"/></linearGradient><linearGradient id="fluentColorImage161" x1="10.097" x2="10.829" y1="4.277" y2="6.913" gradientUnits="userSpaceOnUse"><stop stop-color="#fdfdfd"/><stop offset="1" stop-color="#b3e0ff"/></linearGradient><radialGradient id="fluentColorImage162" cx="0" cy="0" r="1" gradientTransform="matrix(20.57146 26.03575 -23.68122 18.71109 -2.714 -4.75)" gradientUnits="userSpaceOnUse"><stop offset=".338" stop-color="#0fafff"/><stop offset=".529" stop-color="#367af2"/></radialGradient></defs></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.00003 4V6H22V4H2.00003Z" fill="black" /><path d="M8.00003 11V13H22V11H8.00003Z" fill="black" /><path d="M2.00003 18H22V20H2.00003V18Z" fill="black" /><path d="M1.58582 11.9998L4.7678 15.1818L6.18201 13.7676L4.41424 11.9998L6.18201 10.232L4.7678 8.81783L1.58582 11.9998Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 415 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.99997 4H1.99997V6H2.99997H21H22V4H21H2.99997ZM8.99997 11H7.99997V13H8.99997H21H22V11H21H8.99997ZM1.99997 18H2.99997H21H22V20H21H2.99997H1.99997V18ZM5.80474 12.7073L6.51184 12.0002L5.80474 11.2931L4.03697 9.52532L3.32986 8.81821L1.91565 10.2324L2.62276 10.9395L3.68342 12.0002L2.62276 13.0608L1.91565 13.768L3.32986 15.1822L4.03697 14.4751L5.80474 12.7073Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 501 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.05493 11C3.45261 7.40254 5.97062 4.44413 9.33156 3.40217C8.00851 5.65483 7.1892 8.23957 7.02895 11H3.05493ZM10.9922 1.04555C5.38944 1.55442 1 6.26461 1 12C1 17.7354 5.3894 22.4455 10.9922 22.9545L11 22.9643L11.4254 22.9853C11.4932 22.9887 11.5611 22.9916 11.6292 22.9939C11.7523 22.9979 11.8759 23 12 23C12.1187 23 12.2369 22.9981 12.3546 22.9944C12.4281 22.9921 12.5015 22.989 12.5746 22.9853L13 22.9643L13.0078 22.9545C18.6106 22.4455 23 17.7354 23 12C23 6.26461 18.6106 1.55443 13.0078 1.04555L12.9999 1.03571L12.5736 1.0147C12.4767 1.00972 12.3795 1.006 12.2819 1.00354C12.1882 1.00119 12.0942 1 12 1C11.9051 1 11.8104 1.0012 11.7161 1.00359C11.6192 1.00605 11.5226 1.00976 11.4263 1.0147L11.0001 1.03571L10.9922 1.04555ZM12.0011 3C13.6972 5.25767 14.7704 8.00828 14.9672 11H9.03278C9.22955 8.00828 10.3028 5.25767 11.9989 3C11.9992 3 11.9996 3 12 3C12.0004 3 12.0008 3 12.0011 3ZM7.02894 13C7.18917 15.7604 8.00847 18.3452 9.3315 20.5978C5.97059 19.5558 3.45261 16.5974 3.05493 13H7.02894ZM11.9988 21C10.3028 18.7423 9.22953 15.9917 9.03277 13H14.9672C14.7705 15.9917 13.6972 18.7423 12.0012 21C12.0008 21 12.0004 21 12 21C11.9996 21 11.9992 21 11.9988 21ZM14.6685 20.5978C15.9915 18.3452 16.8108 15.7604 16.9711 13H20.9451C20.5474 16.5974 18.0294 19.5558 14.6685 20.5978ZM16.9711 11C16.8108 8.23957 15.9915 5.65483 14.6684 3.40217C18.0294 4.44413 20.5474 7.40254 20.9451 11H16.9711Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="rgb(77, 107, 254)" xmlns="http://www.w3.org/2000/svg"><path d="M3.05493 11C3.45261 7.40254 5.97062 4.44413 9.33156 3.40217C8.00851 5.65483 7.1892 8.23957 7.02895 11H3.05493ZM10.9922 1.04555C5.38944 1.55442 1 6.26461 1 12C1 17.7354 5.3894 22.4455 10.9922 22.9545L11 22.9643L11.4254 22.9853C11.4932 22.9887 11.5611 22.9916 11.6292 22.9939C11.7523 22.9979 11.8759 23 12 23C12.1187 23 12.2369 22.9981 12.3546 22.9944C12.4281 22.9921 12.5015 22.989 12.5746 22.9853L13 22.9643L13.0078 22.9545C18.6106 22.4455 23 17.7354 23 12C23 6.26461 18.6106 1.55443 13.0078 1.04555L12.9999 1.03571L12.5736 1.0147C12.4767 1.00972 12.3795 1.006 12.2819 1.00354C12.1882 1.00119 12.0942 1 12 1C11.9051 1 11.8104 1.0012 11.7161 1.00359C11.6192 1.00605 11.5226 1.00976 11.4263 1.0147L11.0001 1.03571L10.9922 1.04555ZM12.0011 3C13.6972 5.25767 14.7704 8.00828 14.9672 11H9.03278C9.22955 8.00828 10.3028 5.25767 11.9989 3C11.9992 3 11.9996 3 12 3C12.0004 3 12.0008 3 12.0011 3ZM7.02894 13C7.18917 15.7604 8.00847 18.3452 9.3315 20.5978C5.97059 19.5558 3.45261 16.5974 3.05493 13H7.02894ZM11.9988 21C10.3028 18.7423 9.22953 15.9917 9.03277 13H14.9672C14.7705 15.9917 13.6972 18.7423 12.0012 21C12.0008 21 12.0004 21 12 21C11.9996 21 11.9992 21 11.9988 21ZM14.6685 20.5978C15.9915 18.3452 16.8108 15.7604 16.9711 13H20.9451C20.5474 16.5974 18.0294 19.5558 14.6685 20.5978ZM16.9711 11C16.8108 8.23957 15.9915 5.65483 14.6684 3.40217C18.0294 4.44413 20.5474 7.40254 20.9451 11H16.9711Z" fill="rgb(77, 107, 254)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 3H23V21H1V3ZM3 5V19H21V5H3ZM4.99609 7.5H7V9.50391H4.99609V7.5ZM8.99609 7.5H11V9.50391H8.99609V7.5ZM12.9961 7.5H15V9.50391H12.9961V7.5ZM16.9961 7.5H19V9.50391H16.9961V7.5ZM4.99609 10.5H7V12.5039H4.99609V10.5ZM8.99609 10.5H11V12.5039H8.99609V10.5ZM12.9961 10.5H15V12.5039H12.9961V10.5ZM16.9961 10.5H19V12.5039H16.9961V10.5ZM5 15H19V17H5V15Z" fill="black" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 472 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="rgb(95, 114, 146)" d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z"><animateTransform attributeName="transform" dur="0.75s" repeatCount="indefinite" type="rotate" values="0 12 12;360 12 12"/></path></svg>
|
||||
|
After Width: | Height: | Size: 417 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM10.5 7V17H8.5V7H10.5ZM15.5 7V17H13.5V7H15.5Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 402 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 32 32"><path fill="#909090" d="m24.1 2.072l5.564 5.8v22.056H8.879V30h20.856V7.945z"/><path fill="#f4f4f4" d="M24.031 2H8.808v27.928h20.856V7.873z"/><path fill="#7a7b7c" d="M8.655 3.5h-6.39v6.827h20.1V3.5z"/><path fill="#dd2025" d="M22.472 10.211H2.395V3.379h20.077z"/><path fill="#464648" d="M9.052 4.534H7.745v4.8h1.028V7.715L9 7.728a2 2 0 0 0 .647-.117a1.4 1.4 0 0 0 .493-.291a1.2 1.2 0 0 0 .335-.454a2.1 2.1 0 0 0 .105-.908a2.2 2.2 0 0 0-.114-.644a1.17 1.17 0 0 0-.687-.65a2 2 0 0 0-.409-.104a2 2 0 0 0-.319-.026m-.189 2.294h-.089v-1.48h.193a.57.57 0 0 1 .459.181a.92.92 0 0 1 .183.558c0 .246 0 .469-.222.626a.94.94 0 0 1-.524.114m3.671-2.306c-.111 0-.219.008-.295.011L12 4.538h-.78v4.8h.918a2.7 2.7 0 0 0 1.028-.175a1.7 1.7 0 0 0 .68-.491a1.9 1.9 0 0 0 .373-.749a3.7 3.7 0 0 0 .114-.949a4.4 4.4 0 0 0-.087-1.127a1.8 1.8 0 0 0-.4-.733a1.6 1.6 0 0 0-.535-.4a2.4 2.4 0 0 0-.549-.178a1.3 1.3 0 0 0-.228-.017m-.182 3.937h-.1V5.392h.013a1.06 1.06 0 0 1 .6.107a1.2 1.2 0 0 1 .324.4a1.3 1.3 0 0 1 .142.526c.009.22 0 .4 0 .549a3 3 0 0 1-.033.513a1.8 1.8 0 0 1-.169.5a1.1 1.1 0 0 1-.363.36a.67.67 0 0 1-.416.106m5.08-3.915H15v4.8h1.028V7.434h1.3v-.892h-1.3V5.43h1.4v-.892"/><path fill="#dd2025" d="M21.781 20.255s3.188-.578 3.188.511s-1.975.646-3.188-.511m-2.357.083a7.5 7.5 0 0 0-1.473.489l.4-.9c.4-.9.815-2.127.815-2.127a14 14 0 0 0 1.658 2.252a13 13 0 0 0-1.4.288Zm-1.262-6.5c0-.949.307-1.208.546-1.208s.508.115.517.939a10.8 10.8 0 0 1-.517 2.434a4.4 4.4 0 0 1-.547-2.162Zm-4.649 10.516c-.978-.585 2.051-2.386 2.6-2.444c-.003.001-1.576 3.056-2.6 2.444M25.9 20.895c-.01-.1-.1-1.207-2.07-1.16a14 14 0 0 0-2.453.173a12.5 12.5 0 0 1-2.012-2.655a11.8 11.8 0 0 0 .623-3.1c-.029-1.2-.316-1.888-1.236-1.878s-1.054.815-.933 2.013a9.3 9.3 0 0 0 .665 2.338s-.425 1.323-.987 2.639s-.946 2.006-.946 2.006a9.6 9.6 0 0 0-2.725 1.4c-.824.767-1.159 1.356-.725 1.945c.374.508 1.683.623 2.853-.91a23 23 0 0 0 1.7-2.492s1.784-.489 2.339-.623s1.226-.24 1.226-.24s1.629 1.639 3.2 1.581s1.495-.939 1.485-1.035"/><path fill="#909090" d="M23.954 2.077V7.95h5.633z"/><path fill="#f4f4f4" d="M24.031 2v5.873h5.633z"/><path fill="#fff" d="M8.975 4.457H7.668v4.8H8.7V7.639l.228.013a2 2 0 0 0 .647-.117a1.4 1.4 0 0 0 .493-.291a1.2 1.2 0 0 0 .332-.454a2.1 2.1 0 0 0 .105-.908a2.2 2.2 0 0 0-.114-.644a1.17 1.17 0 0 0-.687-.65a2 2 0 0 0-.411-.105a2 2 0 0 0-.319-.026m-.189 2.294h-.089v-1.48h.194a.57.57 0 0 1 .459.181a.92.92 0 0 1 .183.558c0 .246 0 .469-.222.626a.94.94 0 0 1-.524.114m3.67-2.306c-.111 0-.219.008-.295.011l-.235.006h-.78v4.8h.918a2.7 2.7 0 0 0 1.028-.175a1.7 1.7 0 0 0 .68-.491a1.9 1.9 0 0 0 .373-.749a3.7 3.7 0 0 0 .114-.949a4.4 4.4 0 0 0-.087-1.127a1.8 1.8 0 0 0-.4-.733a1.6 1.6 0 0 0-.535-.4a2.4 2.4 0 0 0-.549-.178a1.3 1.3 0 0 0-.228-.017m-.182 3.937h-.1V5.315h.013a1.06 1.06 0 0 1 .6.107a1.2 1.2 0 0 1 .324.4a1.3 1.3 0 0 1 .142.526c.009.22 0 .4 0 .549a3 3 0 0 1-.033.513a1.8 1.8 0 0 1-.169.5a1.1 1.1 0 0 1-.363.36a.67.67 0 0 1-.416.106m5.077-3.915h-2.43v4.8h1.028V7.357h1.3v-.892h-1.3V5.353h1.4v-.892"/></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g opacity="0.9"> <path d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM8.5 6.37083L18.25 12L8.5 17.6292L8.5 6.37083ZM10.5 9.83494L10.5 14.1651L14.25 12L10.5 9.83494Z" fill="#8b8b8b" /></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 485 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><rect width="2.8" height="12" x="1" y="6" fill="#8b8b8b"><animate id="svgSpinnersBarsScale0" attributeName="y" begin="0;svgSpinnersBarsScale1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="0;svgSpinnersBarsScale1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="5.8" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.1s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="10.6" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="15.4" y="6" fill="#8b8b8b"><animate attributeName="y" begin="svgSpinnersBarsScale0.begin+0.3s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.3s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect><rect width="2.8" height="12" x="20.2" y="6" fill="#8b8b8b"><animate id="svgSpinnersBarsScale1" attributeName="y" begin="svgSpinnersBarsScale0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScale0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".36,.61,.3,.98;.36,.61,.3,.98" values="12;22;12"/></rect></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><path fill="#d33922" d="M18.536 2.321v2.863c3.4.019 7.357-.035 10.754.016c.642 0 .67.568.678 1.064c.054 5.942-.013 12.055.032 18c-.012.234-.006 1.1-.013 1.346c-.022.823-.434.859-1.257.884c-.132 0-.52.006-.648.012c-3.181-.016-6.362-.009-9.546-.009v3.182L2 27.134V4.873z"/><path fill="#fff" d="M18.536 6.138h10.5v19.4h-10.5V23h7.634v-1.275h-7.634v-1.59h7.634v-1.272h-7.631q.002-.936-.006-1.87a4.47 4.47 0 0 0 3.82-.375a4.35 4.35 0 0 0 1.959-3.474c-1.4-.01-2.793-.006-4.186-.006c0-1.384.016-2.767-.029-4.148c-.522.1-1.043.21-1.562.321V6.139"/><path fill="#d33922" d="M20.766 8.324a4.476 4.476 0 0 1 4.186 4.167c-1.4.016-2.793.01-4.189.01V8.324"/><path fill="#fff" d="M7.1 10.726c1.727.083 3.82-.684 5.252.611c1.371 1.664 1.008 4.724-1.024 5.719A4.7 4.7 0 0 1 9 17.348c0 1.244-.006 2.488 0 3.731q-.947-.082-1.893-.159c-.029-3.4-.035-6.8 0-10.2"/><path fill="#d33922" d="M8.993 12.446c.627-.029 1.4-.143 1.826.445a2.3 2.3 0 0 1 .041 2.087c-.363.655-1.183.592-1.816.668c-.067-1.066-.06-2.131-.051-3.2"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.0961 5.90381C12.5577 3.3654 8.44209 3.3654 5.90368 5.90381C3.36528 8.44221 3.36528 12.5578 5.90368 15.0962C8.44209 17.6346 12.5577 17.6346 15.0961 15.0962C17.6345 12.5578 17.6345 8.44221 15.0961 5.90381ZM4.48947 4.48959C7.80893 1.17014 13.1908 1.17014 16.5103 4.48959C19.5905 7.56982 19.8125 12.4259 17.1762 15.7621L22.5207 21.1066L21.1065 22.5208L15.762 17.1764C12.4258 19.8126 7.5697 19.5906 4.48947 16.5104C1.17001 13.191 1.17001 7.80905 4.48947 4.48959Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 604 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_100396_60187)"> <path d="M0.291748 1.66449L24.0026 12L0.291748 22.3355L3.93958 12L0.291748 1.66449ZM5.70755 13L3.70832 18.6645L18.9974 12L3.70832 5.33551L5.70755 11H11V13H5.70755Z" fill="#fff" /></g><defs> <clipPath id="clip0_100396_60187"> <rect width="24" height="24" fill="white" /> </clipPath></defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 458 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><rect width="2.8" height="12" x="1" y="6" fill="#68c692"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="5.8" y="6" fill="#68c692"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="10.6" y="6" fill="#68c692"><animate id="svgSpinnersBarsScaleMiddle0" attributeName="y" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="0;svgSpinnersBarsScaleMiddle1.end-0.1s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="15.4" y="6" fill="#68c692"><animate attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.2s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect><rect width="2.8" height="12" x="20.2" y="6" fill="#68c692"><animate id="svgSpinnersBarsScaleMiddle1" attributeName="y" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="6;1;6"/><animate attributeName="height" begin="svgSpinnersBarsScaleMiddle0.begin+0.4s" calcMode="spline" dur="0.6s" keySplines=".14,.73,.34,1;.65,.26,.82,.45" values="12;22;12"/></rect></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.0001 3.00488C7.02956 3.00488 3.00012 7.03432 3.00012 12.0049C3.00012 16.9754 7.02956 21.0049 12.0001 21.0049C16.9707 21.0049 21.0001 16.9754 21.0001 12.0049C21.0001 7.03432 16.9707 3.00488 12.0001 3.00488ZM1.00012 12.0049C1.00012 5.92975 5.92499 1.00488 12.0001 1.00488C18.0753 1.00488 23.0001 5.92975 23.0001 12.0049C23.0001 18.08 18.0753 23.0049 12.0001 23.0049C5.92499 23.0049 1.00012 18.08 1.00012 12.0049ZM13.0001 6.50488L13.0001 11.0049H17.5001V13.0049H13.0001L13.0001 17.5049H11.0001L11.0001 13.0049H6.50012V11.0049H11.0001L11.0001 6.50488H13.0001Z" fill="#333" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 689 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.5001 1.85059L23.5526 12L11.5001 22.1495V15.9233C7.30565 16.1238 4.4268 17.6231 2.31385 20.5813L0.519531 19.8039C1.04297 17.1867 2.10079 14.5092 3.99754 12.3415C5.75937 10.328 8.20695 8.79947 11.5001 8.15506L11.5001 1.85059ZM13.5001 6.14948L13.5001 9.86733L12.6415 9.98998C9.37204 10.4571 7.09103 11.8433 5.50269 13.6585C4.79919 14.4625 4.22297 15.3609 3.75752 16.3174C6.09576 14.6658 8.97868 13.9 12.5001 13.9H13.5001V17.8506L20.4476 12L13.5001 6.14948Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 590 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.0001 1.29053V22.71L5.73703 17.5003L1.00013 17.5003L1.00012 6.50025H5.73703L15.0001 1.29053ZM4.99894 8.50025H3.00012L3.00012 15.5003L4.99894 15.5003L4.99894 8.50025ZM6.99894 15.9154L13.0001 19.2905V4.70998L6.99894 8.08514V15.9154ZM20.9793 6.98204L21.5819 7.78005C22.5 8.99571 22.9964 10.4777 22.9959 12.001C22.9953 13.5244 22.4979 15.006 21.579 16.2211L20.9758 17.0186L19.3806 15.8122L19.9838 15.0146C20.6402 14.1468 20.9955 13.0885 20.9959 12.0004C20.9963 10.9122 20.6417 9.85368 19.9859 8.98535L19.3832 8.18734L20.9793 6.98204ZM18.1865 9.09117L18.7892 9.88918C19.2482 10.497 19.4964 11.238 19.4962 11.9997C19.4959 12.7614 19.2472 13.5022 18.7877 14.1097L18.1845 14.9073L16.5893 13.7009L17.1925 12.9033C17.3895 12.6429 17.4961 12.3254 17.4962 11.999C17.4963 11.6725 17.3899 11.355 17.1932 11.0945L16.5905 10.2965L18.1865 9.09117Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 966 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12Z" fill="#d54941" /><path d="M8 8H16V16H8V8Z" fill="#d54941" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 400 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.5266 5.69361C14.3427 6.35808 15.1567 7.09207 15.9514 7.88684C16.746 8.68139 17.4798 9.49511 18.1441 10.3111C18.7149 9.43842 19.1779 8.59599 19.5225 7.81267C19.9773 6.77901 20.2042 5.89778 20.2328 5.21464C20.2615 4.53265 20.093 4.1556 19.8875 3.95017C19.6821 3.74474 19.305 3.57623 18.6231 3.60485C17.9399 3.63353 17.0587 3.86037 16.025 4.31518C15.2417 4.65985 14.3992 5.12284 13.5266 5.69361ZM11.8389 4.41997C13.0019 3.61089 14.1454 2.95715 15.2195 2.48455C16.3866 1.97103 17.5214 1.64933 18.5392 1.60661C19.5581 1.56385 20.5669 1.80109 21.3017 2.53596C22.0366 3.27082 22.2738 4.27958 22.2311 5.29851C22.1884 6.31628 21.8667 7.45107 21.3531 8.61814C20.8806 9.69221 20.2269 10.8357 19.4178 11.9986C20.2271 13.1619 20.881 14.3056 21.3537 15.38C21.8672 16.547 22.1889 17.6818 22.2317 18.6996C22.2744 19.7185 22.0372 20.7273 21.3023 21.4621C20.5675 22.197 19.5587 22.4342 18.5398 22.3915C17.522 22.3488 16.3872 22.0271 15.2201 21.5136C14.1459 21.0409 13.0021 20.387 11.8389 19.5777C10.6758 20.387 9.53203 21.0409 8.45774 21.5136C7.29067 22.0271 6.15588 22.3488 5.13811 22.3915C4.11918 22.4342 3.11042 22.197 2.37556 21.4621C1.64069 20.7273 1.40345 19.7185 1.44621 18.6996C1.48893 17.6818 1.81063 16.547 2.32414 15.38C2.79685 14.3056 3.45076 13.1619 4.26006 11.9986C3.45103 10.8357 2.79732 9.69221 2.32473 8.61814C1.81122 7.45107 1.48952 6.31628 1.4468 5.29851C1.40403 4.27958 1.64128 3.27082 2.37614 2.53596C3.11101 1.80109 4.11976 1.56385 5.13869 1.60661C6.15647 1.64933 7.29126 1.97103 8.45833 2.48455C9.53243 2.95715 10.676 3.61089 11.8389 4.41997ZM5.53375 10.3111C6.19807 9.49511 6.93189 8.68139 7.72644 7.88684C8.5212 7.09207 9.33514 6.35808 10.1513 5.69361C9.27865 5.12284 8.43619 4.65985 7.65285 4.31518C6.6192 3.86037 5.73796 3.63353 5.05482 3.60485C4.37284 3.57623 3.99578 3.74474 3.79036 3.95017C3.58493 4.1556 3.41641 4.53265 3.44504 5.21464C3.47371 5.89778 3.70055 6.77901 4.15536 7.81267C4.50002 8.59599 4.963 9.43842 5.53375 10.3111ZM6.74564 11.9987C7.44705 12.8959 8.24907 13.8049 9.14123 14.697C10.0332 15.589 10.942 16.3908 11.8389 17.0921C12.7359 16.3908 13.6447 15.589 14.5366 14.697C15.4288 13.8049 16.2308 12.8959 16.9322 11.9987C16.231 11.1017 15.4291 10.193 14.5372 9.30105C13.6451 8.40891 12.7361 7.60691 11.8389 6.90552C10.9418 7.60691 10.0328 8.40891 9.14065 9.30105C8.24873 10.193 7.44691 11.1017 6.74564 11.9987ZM5.53368 13.6862C4.9627 14.5592 4.49954 15.4019 4.15477 16.1854C3.69997 17.2191 3.47313 18.1003 3.44445 18.7835C3.41583 19.4654 3.58434 19.8425 3.78977 20.0479C3.9952 20.2534 4.37225 20.4219 5.05424 20.3932C5.73738 20.3646 6.61861 20.1377 7.65227 19.6829C8.4358 19.3382 9.27848 18.875 10.1514 18.3041C9.33538 17.6397 8.52161 16.9059 7.72702 16.1113C6.93221 15.3165 6.19818 14.5025 5.53368 13.6862ZM13.5265 18.3041C14.3994 18.875 15.2421 19.3382 16.0256 19.6829C17.0593 20.1377 17.9405 20.3646 18.6236 20.3932C19.3056 20.4219 19.6827 20.2534 19.8881 20.0479C20.0935 19.8425 20.2621 19.4654 20.2334 18.7835C20.2048 18.1003 19.9779 17.2191 19.5231 16.1854C19.1783 15.4019 18.7152 14.5592 18.1442 13.6862C17.4797 14.5025 16.7457 15.3165 15.9509 16.1113C15.1563 16.9059 14.3425 17.6397 13.5265 18.3041ZM11.0001 11.0001H13.004V13.004H11.0001V11.0001Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.8786 21.9999L12.1576 21.7868C14.0863 21.4653 15.5 19.7965 15.5 17.8412V15.3826H20.8195C22.0554 15.3826 22.9955 14.2728 22.7923 13.0538L21.1257 3.05377C20.9649 2.08939 20.1306 1.38257 19.1529 1.38257H7V12.5804L10.8786 21.9999ZM12.1131 19.7451L9 12.1847V3.38257H19.1529L20.8195 13.3826H13.5V17.8412C13.5 18.72 12.9289 19.483 12.1131 19.7451ZM4 13.3826V1.38257H2V13.3826H4Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 507 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.8786 1.38257L12.1576 1.59573C14.0863 1.91719 15.5 3.58595 15.5 5.54131V7.99992H20.8195C22.0554 7.99992 22.9955 9.10966 22.7923 10.3287L21.1257 20.3287C20.9649 21.2931 20.1306 21.9999 19.1529 21.9999H7V10.8021L10.8786 1.38257ZM12.1131 3.63742L9 11.1977V19.9999L19.1529 19.9999L20.8195 9.99992H13.5V5.54131C13.5 4.66252 12.9289 3.89951 12.1131 3.63742ZM4 9.99992V21.9999H2V9.99992H4Z" fill="#8b8b8b" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 518 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.0001 4.5L11.0002 16.0858L6.50015 11.5858L5.08594 13L12.0002 19.9142L18.9144 13L17.5001 11.5858L13.0002 16.0858L13.0001 4.5L11.0001 4.5Z" fill="rgb(128, 128, 128)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 281 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.99988 2H21.9999V22H1.99988V2ZM3.99988 20H17.5857L8.99988 11.4142L3.99988 16.4142V20ZM19.9999 19.5858V4H3.99988V13.5858L8.99988 8.58579L19.9999 19.5858ZM15.7968 7.25C15.2445 7.25 14.7968 7.69772 14.7968 8.25C14.7968 8.80228 15.2445 9.25 15.7968 9.25C16.349 9.25 16.7968 8.80228 16.7968 8.25C16.7968 7.69772 16.349 7.25 15.7968 7.25ZM12.7968 8.25C12.7968 6.59315 14.1399 5.25 15.7968 5.25C17.4536 5.25 18.7968 6.59315 18.7968 8.25C18.7968 9.90685 17.4536 11.25 15.7968 11.25C14.1399 11.25 12.7968 9.90685 12.7968 8.25Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 662 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 48 48"><g fill="none"><path stroke="#000" stroke-linejoin="round" stroke-width="4" d="M24 44c11.046 0 20-8.954 20-20S35.046 4 24 4S4 12.954 4 24s8.954 20 20 20Z"/><path fill="#000" d="M17 25.9a2 2 0 1 0 0-4a2 2 0 0 0 0 4"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M21.95 28.85A6.98 6.98 0 0 0 24 23.9a6.98 6.98 0 0 0-2.05-4.95m4.95 14.849a13.96 13.96 0 0 0 4.1-9.9c0-3.866-1.567-7.366-4.1-9.899"/></g></svg>
|
||||
|
After Width: | Height: | Size: 531 B |
|
|
@ -0,0 +1,2 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.75 4.25C4.85689 4.25 2 6.88401 2 9.79408C2 11.3943 2.83472 12.8796 4.25197 13.9231C4.54488 14.1387 4.69759 14.4964 4.65074 14.8571L4.58136 15.3913L5.41173 14.9745C5.65098 14.8543 5.9284 14.8352 6.1819 14.9212C6.97088 15.1891 7.8375 15.3382 8.75 15.3382C9.00377 15.3382 9.254 15.3266 9.5 15.3042C9.50387 12.0935 12.1736 9.6258 15.4462 9.10286C15.0367 6.47982 12.332 4.25 8.75 4.25ZM17.4568 9.03026C21.0029 9.33461 24 11.9035 24 15.3112C24 16.9476 23.2887 18.413 22.1671 19.5096V21.4591C22.1671 21.8163 21.9765 22.1465 21.6671 22.3251C21.3577 22.5037 20.9765 22.5037 20.6671 22.3251L18.9424 21.3293C18.2488 21.5201 17.5119 21.6224 16.75 21.6224C13.6277 21.6224 10.8262 19.8749 9.85702 17.2784C9.49411 17.3179 9.12461 17.3382 8.75 17.3382C7.77222 17.3382 6.82917 17.2 5.94709 16.9436L3.79583 18.0236C3.4652 18.1896 3.06995 18.1595 2.76828 17.9454C2.46661 17.7312 2.30782 17.368 2.35547 17.0011L2.59463 15.1598C1.0185 13.8152 0 11.9258 0 9.79408C0 5.47576 4.0827 2.25 8.75 2.25C13.1377 2.25 17.0088 5.10087 17.4568 9.03026ZM5.24609 7.49609C5.24609 6.94381 5.69381 6.49609 6.24609 6.49609H6.25C6.80228 6.49609 7.25 6.94381 7.25 7.49609V7.5C7.25 8.05228 6.80228 8.5 6.25 8.5H6.24609C5.69381 8.5 5.24609 8.05228 5.24609 7.5V7.49609ZM10.25 7.50732C10.25 6.95504 10.6977 6.50732 11.25 6.50732H11.2539C11.8062 6.50732 12.2539 6.95504 12.2539 7.50732V7.51123C12.2539 8.06352 11.8062 8.51123 11.2539 8.51123H11.25C10.6977 8.51123 10.25 8.06352 10.25 7.51123V7.50732ZM16.75 11C16.6763 11 16.6029 11.0013 16.53 11.0037C13.5817 11.1038 11.5 13.1303 11.5 15.3112C11.5 15.5359 11.521 15.7559 11.5612 15.9704C11.9293 17.9298 14.0076 19.6224 16.75 19.6224C17.4593 19.6224 18.1322 19.5066 18.7446 19.2989C19.0172 19.2064 19.3165 19.2359 19.5658 19.3798L20.1671 19.727V19.0687C20.1671 18.7751 20.2962 18.4964 20.52 18.3064C21.4616 17.507 22 16.4444 22 15.3112C22 13.0766 19.8083 11 16.75 11ZM13.5561 13.656C13.5561 13.1037 14.0038 12.656 14.5561 12.656H14.56C15.1123 12.656 15.56 13.1037 15.56 13.656V13.6599C15.56 14.2122 15.1123 14.6599 14.56 14.6599H14.5561C14.0038 14.6599 13.5561 14.2122 13.5561 13.6599V13.656ZM17.9361 13.6599C17.9361 13.1076 18.3838 12.6599 18.9361 12.6599H18.94C19.4923 12.6599 19.94 13.1076 19.94 13.6599V13.6638C19.94 14.2161 19.4923 14.6638 18.94 14.6638H18.9361C18.3838 14.6638 17.9361 14.2161 17.9361 13.6638V13.6599Z" fill="rgb(95, 114, 146)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><defs><linearGradient id="vscodeIconsFileTypeWord0" x1="4.494" x2="13.832" y1="-1712.086" y2="-1695.914" gradientTransform="translate(0 1720)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2368c4"/><stop offset=".5" stop-color="#1a5dbe"/><stop offset="1" stop-color="#1146ac"/></linearGradient></defs><path fill="#41a5ee" d="M28.806 3H9.705a1.19 1.19 0 0 0-1.193 1.191V9.5l11.069 3.25L30 9.5V4.191A1.19 1.19 0 0 0 28.806 3"/><path fill="#2b7cd3" d="M30 9.5H8.512V16l11.069 1.95L30 16Z"/><path fill="#185abd" d="M8.512 16v6.5l10.418 1.3L30 22.5V16Z"/><path fill="#103f91" d="M9.705 29h19.1A1.19 1.19 0 0 0 30 27.809V22.5H8.512v5.309A1.19 1.19 0 0 0 9.705 29"/><path d="M16.434 8.2H8.512v16.25h7.922a1.2 1.2 0 0 0 1.194-1.191V9.391A1.2 1.2 0 0 0 16.434 8.2" opacity="0.1"/><path d="M15.783 8.85H8.512V25.1h7.271a1.2 1.2 0 0 0 1.194-1.191V10.041a1.2 1.2 0 0 0-1.194-1.191" opacity="0.2"/><path d="M15.783 8.85H8.512V23.8h7.271a1.2 1.2 0 0 0 1.194-1.191V10.041a1.2 1.2 0 0 0-1.194-1.191" opacity="0.2"/><path d="M15.132 8.85h-6.62V23.8h6.62a1.2 1.2 0 0 0 1.194-1.191V10.041a1.2 1.2 0 0 0-1.194-1.191" opacity="0.2"/><path fill="url(#vscodeIconsFileTypeWord0)" d="M3.194 8.85h11.938a1.193 1.193 0 0 1 1.194 1.191v11.918a1.193 1.193 0 0 1-1.194 1.191H3.194A1.19 1.19 0 0 1 2 21.959V10.041A1.19 1.19 0 0 1 3.194 8.85"/><path fill="#fff" d="M6.9 17.988q.035.276.046.481h.028q.015-.195.065-.47c.05-.275.062-.338.089-.465l1.255-5.407h1.624l1.3 5.326a8 8 0 0 1 .162 1h.022a8 8 0 0 1 .135-.975l1.039-5.358h1.477l-1.824 7.748h-1.727l-1.237-5.126q-.054-.222-.122-.578t-.084-.52h-.021q-.021.189-.084.561t-.1.552L7.78 19.871H6.024L4.19 12.127h1.5l1.131 5.418a5 5 0 0 1 .079.443"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"markdownPreview": "./wd-markdown/index",
|
||||
"FoldedCard": "./collapse/index",
|
||||
"chatFile": "./chatFile/index",
|
||||
"feedback": "./feedback/index",
|
||||
"customCard": "./customCard/index",
|
||||
"tool": "./tool/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
<!-- agent ui 组件根容器 -->
|
||||
<view class="agent-ui" bind:tap="onTapPage">
|
||||
<!-- 左侧抽屉,只在 bot 模式下展示 -->
|
||||
<view wx-if="{{chatMode==='bot'&&!isAgent}}" class="drawer-mask {{isDrawerShow ? 'show' : ''}}" bindtap="closeDrawer"></view>
|
||||
<view wx-if="{{chatMode==='bot'&&!isAgent}}" class="drawer {{isDrawerShow ? 'show' : ''}}">
|
||||
<view class="drawer-header">
|
||||
<view class="create-new-chat" bind:tap="clickCreateInDrawer">
|
||||
<image style="width: 48rpx;height: 48rpx;margin-right: 10rpx" src="./imgs/chat-add.svg" mode="aspectFill" />
|
||||
<text> 开启新对话 </text>
|
||||
</view>
|
||||
<image class="close-icon" src="./imgs/indent-left.svg" bindtap="closeDrawer" />
|
||||
</view>
|
||||
<view class="drawer-content">
|
||||
<scroll-view enhanced="{{true}}" style="height: 100%;" show-scrollbar="{{false}}" scroll-y="true"
|
||||
bindscrolltolower="scrollConToBottom">
|
||||
<block wx:if="{{ conversations.length > 0 }}">
|
||||
<view class="con-block" wx:if="{{transformConversations.todayCon.length}}">
|
||||
<text class="date-title">今天</text>
|
||||
<view class="con-container">
|
||||
<view class="con-item {{item.conversationId === conversation.conversationId ? 'selected-con' : ''}}"
|
||||
bind:tap="handleClickConversation" bind:longpress="handleLongPressConversation"
|
||||
data-conversation="{{item}}" wx:for="{{transformConversations.todayCon}}" wx:key="index">
|
||||
{{item.title}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="con-block" wx:if="{{transformConversations.curMonthCon.length}}">
|
||||
<text class="date-title">本月</text>
|
||||
<view class="con-container">
|
||||
<view class="con-item {{item.conversationId === conversation.conversationId ? 'selected-con' : ''}}"
|
||||
bind:tap="handleClickConversation" bind:longpress="handleLongPressConversation"
|
||||
data-conversation="{{item}}" wx:for="{{transformConversations.curMonthCon}}" wx:key="index">
|
||||
{{item.title}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="con-block" wx:if="{{transformConversations.earlyCon.length}}">
|
||||
<text class="date-title">更早</text>
|
||||
<view class="con-container">
|
||||
<view class="con-item" bind:tap="handleClickConversation" bind:longpress="handleLongPressConversation"
|
||||
data-conversation="{{item}}" wx:for="{{transformConversations.earlyCon}}" wx:key="index">
|
||||
{{item.title}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view
|
||||
style="width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;">
|
||||
<image src="./imgs/chat-bubble-history.svg" mode="aspectFill"
|
||||
style="width: 100rpx;height: 100rpx;transform: translateY(-50%);" />
|
||||
<text style="color: rgb(160, 160, 160)">暂无历史记录</text>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标题栏(包含会话列表展开按钮,agent 名称,开启新会话按钮),只在 bot 模式下展示 -->
|
||||
<view class="navBar {{showBotName ? 'showBotName' : 'hiddenBotName'}}" wx:if="{{chatMode === 'bot'&&!isAgent}}">
|
||||
<view class="nav-content {{showBotName ? 'showBotName' : 'hiddenBotName'}}"
|
||||
style="{{showMultiConversation ? 'justify-content: space-between;' : ''}}">
|
||||
<image wx:if="{{bot.botId && showMultiConversation}}" bind:tap="openDrawer" class="con-icon"
|
||||
src="./imgs/indent-right.svg" mode="aspectFill" />
|
||||
<text wx:if="{{showBotName}}" class="bot-name">{{bot.name}}</text>
|
||||
<image wx:if="{{bot.botId && showMultiConversation}}" class="con-icon" bind:tap="createNewConversation"
|
||||
src="./imgs/chat-bubble-add.svg" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<view style="height: 100%;overflow: auto;position: relative;">
|
||||
<!-- 聊天对话区 -->
|
||||
<scroll-view bindwheel="onWheel" enhanced="{{true}}" bindscroll="onScroll" binddragstart="handleScrollStart"
|
||||
class="main" style="height: 100%;" scroll-y="{{true}}" scroll-top="{{viewTop}}" scroll-into-view="{{ scrollTo }}"
|
||||
lower-threshold="1" bindscrolltolower="handleScrollToLower" show-scrollbar="{{false}}"
|
||||
refresher-enabled="{{showPullRefresh && (bot.multiConversationEnable ? conversation : true)}}"
|
||||
refresher-threshold="{{80}}" bindrefresherrefresh="handleRefresh" refresher-triggered="{{triggered}}"
|
||||
bounces="{{false}}">
|
||||
<view class="contentBox" style="margin-bottom: 30px;">
|
||||
<!-- 下拉刷新按钮,只在 bot 模式下展示 -->
|
||||
<view
|
||||
wx:if="{{chatMode === 'bot'&& !isAgent && bot.botId && showPullRefresh && (bot.multiConversationEnable ? conversation : true)}}"
|
||||
class="tips">
|
||||
{{refreshText}}
|
||||
</view>
|
||||
<!-- model 模式下的头像,只在 model 模式下展示 -->
|
||||
<view wx:if="{{chatMode === 'model'}}" class="nav">
|
||||
<image src="{{modelConfig.logo}}" mode="aspectFill" class="avatar" />
|
||||
<view style="line-height: 47px; font-size: 20px; font-weight: 500;">{{modelConfig.modelProvider}}</view>
|
||||
<view style="line-height: 26px;padding: 0px 16px; font-size: 32rpx;">{{modelConfig.welcomeMsg}}</view>
|
||||
</view>
|
||||
<block wx-if="{{!isAgent}}" wx:for="{{chatRecords}}" wx:key="record_id">
|
||||
<!-- 系统聊天 -->
|
||||
<view class="system" style="padding-left: {{showBotAvatar?80:0}}rpx;" wx:if="{{item.role==='assistant'}}">
|
||||
<view class="avatar-left" wx:if="{{showBotAvatar}}">
|
||||
<image src="{{chatMode==='bot'?bot.avatar:modelConfig.logo}}" mode="aspectFill"
|
||||
style="width: 56rpx;height: 56rpx; border-radius: 28rpx;" />
|
||||
</view>
|
||||
<view>
|
||||
<!-- 最后一条消息,并且是发送状态显示发送中 -->
|
||||
<block wx:if="{{(chatRecords.length-1)===index&&chatStatus===1}}">
|
||||
<view style="display: flex;align-items: center; gap: 4px; font-size: 32rpx;line-height: 1.8;">
|
||||
<image src="./imgs/loading.svg" mode="aspectFill" style="width: 14px;height: 14px;" /> 请稍等,正在卖力思考中 🤔
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<!-- 数据库检索 -->
|
||||
<view wx:if="{{item.db_len}}"
|
||||
style="border-radius: 8px;margin-bottom: 12px;background-color: #f5f5f5;padding: 18rpx 26rpx;display: inline-block;opacity: 0.7;font-size: 14px;">
|
||||
已匹配 {{item.db_len}} 张数据表
|
||||
</view>
|
||||
<!-- 联网搜索 -->
|
||||
<FoldedCard wx:if="{{item.search_info && item.search_info.search_results}}" initStatus="{{false}}"
|
||||
showBgColor="{{true}}">
|
||||
<view slot="title" style="opacity: 0.7;font-size: 14px;display: flex; align-items: center; gap: 8px;">
|
||||
<image src="./imgs/search.svg" mode="aspectFill" style="width: 36rpx;height: 36rpx;" />
|
||||
<text>已参考 {{item.search_info.search_results.length}} 个网页</text>
|
||||
</view>
|
||||
<view slot="content" class="link-box">
|
||||
<block wx:for="{{item.search_info.search_results}}" wx:key="index">
|
||||
<view bind:tap="copyUrl" data-url="{{item.url}}"
|
||||
style="margin-bottom: 3px; font-size: 14px;color: rgb(0, 82, 217); line-height: 24px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">
|
||||
{{index+1}}.{{item.title}}
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</FoldedCard>
|
||||
<!-- 知识库 -->
|
||||
<view wx:if="{{item.knowledge_base&&item.knowledge_base.length}}"
|
||||
style="border-radius: 8px;margin-bottom: 12px;background-color: #f5f5f5;padding: 18rpx 26rpx;display: inline-block;opacity: 0.7;font-size: 14px;">
|
||||
已参考 {{item.knowledge_base.length}} 处知识库内容
|
||||
</view>
|
||||
<!-- 推理过程 -->
|
||||
<FoldedCard wx:if="{{!!item.reasoning_content}}" initStatus="{{true}}" showBgColor="{{false}}">
|
||||
<view slot="title"
|
||||
style="opacity: 0.7;font-size: 14px; display: flex; align-items: center; gap: 8px;">
|
||||
<image src="./imgs/system-sum.svg" mode="aspectFill" style="width: 36rpx;height: 36rpx;" />
|
||||
<block wx:if="{{item.pauseThinking}}">
|
||||
已停止思考
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text>{{item.reasoning_content&&!item.content?"思考中...":"已深度思考(用时"+item.thinkingTime+"秒)"}}</text>
|
||||
</block>
|
||||
</view>
|
||||
<view style="padding-left: 25rpx;margin-top: 28rpx; border-left: rgba(0,0,0,0.14) solid 2px ;"
|
||||
slot="content">
|
||||
<!-- <markdownPreview markdown="{{item.reasoning_content||''}}" fontSize="{{28}}"></markdownPreview> -->
|
||||
<text user-select="{{true}}"
|
||||
style="font-size: 14px;line-height: 1.75;color: #8b8b8b">{{item.reasoning_content||''}}</text>
|
||||
</view>
|
||||
</FoldedCard>
|
||||
<!-- 工具调用 -->
|
||||
|
||||
<view wx:if="{{item.toolCallList && item.toolCallList.length > 0}}">
|
||||
<block wx:for="{{item.toolCallList}}" wx:for-item="subItem" wx:key="id">
|
||||
<markdownPreview markdown="{{subItem.content || ''}}"></markdownPreview>
|
||||
<FoldedCard showExpandIcon="{{showToolCallDetail}}" initStatus="{{false}}" showBgColor="{{false}}">
|
||||
<view slot="title"
|
||||
style="opacity: 0.7;font-size: 14px; display: flex; align-items: center; gap: 8px;">
|
||||
<block>
|
||||
调用工具 {{subItem.name}}
|
||||
<image wx:if="{{!subItem.callResult && !subItem.error}}" src="./imgs/loading.svg"
|
||||
mode="aspectFill" style="width: 14px;height: 14px;" />
|
||||
<image wx:if="{{subItem.callResult}}" mode="widthFix" src='./imgs/check.svg'
|
||||
style="width: 36rpx; height: 36rpx;vertical-align: top;" bind:tap="share" />
|
||||
<image wx:if="{{subItem.error}}" mode="widthFix" src='./imgs/close-red.svg'
|
||||
style="width: 36rpx; height: 36rpx;vertical-align: top;" bind:tap="share" />
|
||||
</block>
|
||||
<!-- <block wx:else>
|
||||
<text>{{item.reasoning_content&&!item.content?"思考中...":"已深度思考(用时"+item.thinkingTime+"秒)"}}</text>
|
||||
</block> -->
|
||||
</view>
|
||||
<view wx:if="{{showToolCallDetail}}"
|
||||
style="padding-left: 25rpx;margin-top: 28rpx; border-left: rgb(165, 164, 164) solid 2px; opacity: 0.7;"
|
||||
slot="content">
|
||||
<view>参数:</view>
|
||||
<markdownPreview markdown="{{subItem.callParams||''}}" fontSize="{{28}}"></markdownPreview>
|
||||
<view>结果:</view>
|
||||
<markdownPreview markdown="{{subItem.callResult||''}}" fontSize="{{28}}"></markdownPreview>
|
||||
</view>
|
||||
</FoldedCard>
|
||||
<customCard wx:if="{{subItem.rawResult}}" name="{{subItem.name}}" toolParams="{{subItem.rawParams}}"
|
||||
toolData="{{subItem.rawResult}}"></customCard>
|
||||
</block>
|
||||
</view>
|
||||
<!-- 正文 -->
|
||||
<markdownPreview markdown="{{item.content||''}}"></markdownPreview>
|
||||
<!-- 下面的按钮 -->
|
||||
<view style="display: flex; gap: 10px;justify-content: flex;" wx:if="{{!item.hiddenBtnGround}}">
|
||||
<image wx:if="{{item.error}}" mode="widthFix" bind:tap="showErrorMsg" src='./imgs/error-circle.svg'
|
||||
class="tool_btn" data-content="{{item.error}}" data-reqid="{{item.reqId}}" />
|
||||
<image mode="widthFix" bind:tap="copyChatRecord" src='./imgs/copy.svg' class="tool_btn"
|
||||
data-content="{{item.content}}" />
|
||||
<block wx:if="{{!item.error}}">
|
||||
<button class="share_btn" open-type="share">
|
||||
<image mode="widthFix" src='./imgs/share.svg' class="tool_btn" style="vertical-align: top;"
|
||||
bind:tap="share" />
|
||||
</button>
|
||||
<block wx:if="{{chatMode=== 'bot'}}">
|
||||
<image mode="widthFix" bind:tap="openFeedback" data-feedbackType="upvote"
|
||||
data-feedbackRecordId="{{item.record_id}}" src='./imgs/thumb-up.svg' class="tool_btn" />
|
||||
<image mode="widthFix" bind:tap="openFeedback" data-feedbackType="downvote"
|
||||
data-feedbackRecordId="{{item.record_id}}" src='./imgs/thumb-down.svg' class="tool_btn" />
|
||||
<block wx:if="{{item.record_id}}">
|
||||
<image wx:if="{{audioContext.recordId !== item.record_id || audioContext.playStatus === 0}}"
|
||||
mode="widthFix" bind:tap="handlePlayAudio" data-content="{{item.content}}"
|
||||
data-recordId="{{item.record_id}}" src='./imgs/sound.svg' class="tool_btn" />
|
||||
<image wx:elif="{{audioContext.playStatus === 1}}" mode="widthFix" src='./imgs/loading.svg'
|
||||
class="tool_btn" />
|
||||
<view wx:else class="playing_btn">
|
||||
<image style="width: 36rpx;height: 36rpx;" mode="widthFix" bind:tap="handlePauseAudio"
|
||||
data-recordId="{{item.record_id}}" src='./imgs/pause.svg' />
|
||||
<image style="width: 30rpx;height: 30rpx" src="./imgs/playing.svg" mode="widthFix" />
|
||||
<!-- 倍速切换按钮 -->
|
||||
<view class="speed-switch" bindtap="toggleSpeedList" data-recordId="{{item.record_id}}">
|
||||
|
||||
<text class="speed-label">{{audioContext.currentSpeed || '1'}}</text>X
|
||||
</view>
|
||||
<!-- 倍速弹窗 -->
|
||||
<view wx:if="{{audioContext.showSpeedList && audioContext.recordId === item.record_id}}"
|
||||
class="speed-popup">
|
||||
<view wx:for="{{speedList}}" wx:key="item" class="speed-option" bindtap="chooseSpeed"
|
||||
data-speed="{{item}}" data-recordId="{{item.record_id}}">
|
||||
<text>{{item}}X</text>
|
||||
<image wx:if="{{audioContext.currentSpeed === item}}" src="./imgs/check.svg"
|
||||
style="width: 24rpx;height: 24rpx;margin-left:8rpx;" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
<image wx:if="{{(chatRecords.length - 1) === index && (chatStatus === 2 || chatStatus === 3)}}"
|
||||
mode="widthFix" src='./imgs/loading.svg' style="width: 14px;height: 14px;" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户输入 -->
|
||||
<view class="userContent" wx:if="{{item.role==='user'}}">
|
||||
<view class="user" style="padding-left: {{showBotAvatar?80:0}}rpx;display: flex;">
|
||||
<view class="user_content" bind:longpress="handleLongPress" data-content="{{item.content}}"
|
||||
data-id="{{item.record_id}}">
|
||||
{{item.content}}
|
||||
<!-- 长按菜单 -->
|
||||
<view class="operation-menu" wx:if="{{showMenu && tapMenuRecordId === item.record_id}}">
|
||||
<view class="menu-item" bind:tap="handleCopyAll" data-content="{{item.content}}">
|
||||
<image src="./imgs/copy.svg" class="menu-icon" />
|
||||
<text>复制全文</text>
|
||||
</view>
|
||||
<view class="menu-item" bind:tap="handleEdit" data-content="{{item.content}}">
|
||||
<image src="./imgs/edit.svg" class="menu-icon" />
|
||||
<text>修改</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fileBar">
|
||||
<chatFile enableDel="{{false}}" wx:for="{{item.fileList}}" wx:for-item="innerItem" wx:key="tempPath"
|
||||
fileData="{{innerItem}}" bind:removeChild="handleRemoveChild" bind:changeChild="handleChangeChild">
|
||||
</chatFile>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- agentV2 聊天列表 -->
|
||||
<block wx:if="{{isAgent}}" wx:for="{{messages}}" wx:key="id">
|
||||
<view class="userContent" wx:if="{{item.role==='user'}}">
|
||||
<view class="user">
|
||||
<view class="user_content"> {{item.content}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="system" wx:if="{{item.role==='assistant'}}">
|
||||
<!-- 渲染 parts -->
|
||||
<block wx:for="{{item.parts}}" wx:for-item="part" wx:key="id">
|
||||
<block wx:if="{{part.type==='text'}}">
|
||||
<markdownPreview markdown="{{part.content||''}}"></markdownPreview>
|
||||
</block>
|
||||
<block wx:if="{{part.type==='tool_call'}}">
|
||||
<tool tool-name="{{part.toolCallName}}" tool-status="{{part.status}}" tool-params="{{part.arguments}}"
|
||||
toolResult="{{part.result}}">
|
||||
</tool>
|
||||
</block>
|
||||
<block wx:if="{{part.type==='error'}}">
|
||||
<view>{{part.content||''}}</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 加载图标 -->
|
||||
<view wx:if="{{isAgent&&chatStatus!=0}}">
|
||||
<image src="./imgs/loading.svg" mode="aspectFill" style="width: 14px;height: 14px; margin-left: 32rpx;" />
|
||||
</view>
|
||||
<!-- 推荐问题,只在 bot 模式下展示 -->
|
||||
<block wx-if="{{chatMode==='bot'&&!isAgent}}" wx:for="{{questions}}" wx:key="item">
|
||||
<view class="questions" style="padding-left: {{showBotAvatar?80:0}}rpx;">
|
||||
<view class="question_content" bind:tap="handleSendMessage" data-message="{{item}}">{{item}}</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view id="scroll-bottom" style="width: 100%;height: 20px;"></view>
|
||||
</scroll-view>
|
||||
<!-- 页面不在底部时候的滚动到底按钮 -->
|
||||
<image bind:tap="autoToBottom" wx:if="{{manualScroll&&!isAgent}}"
|
||||
style="width:28px;height:28px;border-radius: 50px;position: absolute;bottom:150px;right: 20px;padding: 5px;background-color: white;box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;"
|
||||
src="./imgs/toBottom.svg" mode="aspectFit" binderror="" bindload="" />
|
||||
</view>
|
||||
<!-- 底部输入区 -->
|
||||
<view class="footer">
|
||||
<view class="{{ showFileList ? 'no_feature_list' : 'feature_list'}}" wx:if="{{showFeatureList}}">
|
||||
<view bind:tap="handleClickWebSearch" class="{{'webSearchSwitch ' + (useWebSearch ? 'feature_enable' : '')}}">
|
||||
<image src="{{ useWebSearch ? './imgs/internetUse.svg' : './imgs/internet.svg'}}" mode=""
|
||||
style="width: 40rpx;height:30px;margin-right: 10rpx;" />
|
||||
<text style="color: {{useWebSearch ? 'rgb(77, 107, 254)' : 'rgb(95, 114, 146)'}}">联网搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="file_list" wx:if="{{showFileList}}">
|
||||
<chatFile enableDel="{{true}}" wx:for="{{sendFileList}}" wx:key="tempId" fileData="{{item}}"
|
||||
bind:removeChild="handleRemoveChild" bind:changeChild="handleChangeChild"></chatFile>
|
||||
</view>
|
||||
<view class="foot_function">
|
||||
<view class="input_box">
|
||||
<view class="left_btns" wx:if="{{showVoice&&!isAgent}}">
|
||||
<image wx:if="{{!useVoice}}" src="./imgs/voice.svg" class="set" mode="widthFix"
|
||||
bind:tap="handleChangeInputType" />
|
||||
<image wx:else src="./imgs/keyboard.svg" class="set" mode="widthFix" bind:tap="handleChangeInputType" />
|
||||
</view>
|
||||
<view hidden="{{useVoice}}" class="input_inner_box">
|
||||
<textarea class="input" value="{{inputValue}}" maxlength="1024" bindfocus="bindInputFocus"
|
||||
bindinput="bindKeyInput" placeholder="说点什么吧" bindconfirm="handleSendMessage" confirm-type="send"
|
||||
adjust-position cursor-spacing="40" auto-height="{{true}}" show-confirm-bar="{{false}}"
|
||||
bindlinechange="handleLineChange" />
|
||||
</view>
|
||||
<text
|
||||
style="position: absolute;top: -50%;left: 50%;transform: translateX(-50%);font-size: 12px;color: {{sendStatus === 2 ? '#e84f50;' : ''}}">{{sendStatus === 1 ? "松开发送,上滑取消" : (sendStatus === 2 ? "松开取消" : "")}}</text>
|
||||
<view hidden="{{!useVoice}}" bindtouchstart="handleTouchStart" bindtouchmove="handleTouchMove"
|
||||
bindtouchend="handleTouchEnd" class="input_inner_box"
|
||||
style="position: absolute;width: calc(100% - 136rpx);left: 50%;transform: translateX(-50%);opacity: 0;">
|
||||
</view>
|
||||
<view hidden="{{!useVoice}}" class="input_inner_box say_box"
|
||||
style="background-color: {{sendStatus === 1 ? '#e9f6ef' : (sendStatus === 2 ? '#f8ecea' : '')}};"><text
|
||||
wx:if="{{!longPressTriggered}}">{{voiceRecognizing ? '识别中' : '按住 说话'}}</text>
|
||||
<image wx:else
|
||||
src="{{ sendStatus === 1 ? './imgs/sendSaying.svg' : (sendStatus === 2 ? './imgs/cancelSaying.svg' : '')}}"
|
||||
class="set" mode="widthFix" />
|
||||
</view>
|
||||
<view class="right_btns">
|
||||
<!-- 加号 -->
|
||||
<image src="./imgs/set.svg" class="set" mode="widthFix" bind:tap="handleClickTools" />
|
||||
<!-- 发送按钮 -->
|
||||
<view wx:if="{{!!inputValue&&chatStatus===0}}" class="set"
|
||||
style="display: flex;justify-content: center;align-items: center;background-color: #436af4;border-radius: 50px;">
|
||||
<image src="./imgs/send.svg" class="send-set" mode="widthFix" bind:tap="handleSendMessage"
|
||||
style="transform-origin: 8px 8px;" />
|
||||
</view>
|
||||
<!-- 暂停按钮 -->
|
||||
<image src="./imgs/stop.svg" class="set" mode="widthFix" wx:if="{{!(chatStatus===0)}}" bind:tap="stop" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部工具栏 -->
|
||||
<view class="tool_box" wx:if="{{showTools}}">
|
||||
<view class="function" bind:tap="handleTapClear">
|
||||
<image src="./imgs/clear.svg" alt="widthFix" class="icon" />
|
||||
<text class="text_desc">清除</text>
|
||||
</view>
|
||||
<view wx:if="{{showUploadFile && chatMode === 'bot'&&!isAgent}}" class="function" bind:tap="handleUploadMessageFile">
|
||||
<image src="./imgs/wechat.svg" alt="widthFix" class="icon" />
|
||||
<text class="text_desc">微信文件</text>
|
||||
</view>
|
||||
<view wx:if="{{showUploadImg && chatMode === 'bot'&&!isAgent}}" class="function" bind:tap="handleAlbum">
|
||||
<image src="./imgs/uploadImg.svg" alt="widthFix" class="icon" />
|
||||
<text class="text_desc">图片</text>
|
||||
</view>
|
||||
<view wx:if="{{showUploadImg && chatMode === 'bot'&&!isAgent}}" class="function" bind:tap="handleCamera">
|
||||
<image src="./imgs/camera.svg" alt="widthFix" class="icon" />
|
||||
<text class="text_desc">相机</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<feedback input="{{input}}" aiAnswer="{{aiAnswer}}" isShowFeedback="{{isShowFeedback}}" bind:close="closefeedback"
|
||||
feedbackRecordId="{{feedbackRecordId}}" feedbackType="{{feedbackType}}" botId="{{bot.botId}}"></feedback>
|
||||
<!-- 底部操作菜单弹窗 -->
|
||||
<view class="action-menu-modal" wx:if="{{showActionMenu}}" bind:tap="hideActionMenu">
|
||||
<view class="action-menu" catchtap="">
|
||||
<view class="action-item" bind:tap="handleDeleteConversation" data-conversation="{{selectedConversation}}">
|
||||
删除
|
||||
</view>
|
||||
<view class="action-item cancel-item" bind:tap="hideActionMenu">
|
||||
取消
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,730 @@
|
|||
/* components/agent-ui/index.wxss */
|
||||
.agent-ui {
|
||||
width: 750rpx;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow:hidden;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
touch-action: none; /* 增强禁止滚动效果 */
|
||||
}
|
||||
|
||||
.showBotName {
|
||||
height: 62px;
|
||||
}
|
||||
|
||||
.hiddenBotName {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
width: 750rpx;
|
||||
padding: 20px 0px 0px 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navBar {
|
||||
width: 100%;
|
||||
box-shadow: 0 16px 16px #fff;
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
color: rgb(128, 128, 128);
|
||||
font-size: 12px;
|
||||
height: 32px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.tips::before,
|
||||
.tips::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
transform: scaleY(.5);
|
||||
flex-grow: 1;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.tips::before {
|
||||
background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
.tips::after {
|
||||
background-image: linear-gradient(to left, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
/* height:62px; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.bot-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.bot-name {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.main {
|
||||
background-color: #fff;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.share_btn {
|
||||
background-color: #fff;
|
||||
margin: 0px !important;
|
||||
padding: 0rpx !important;
|
||||
width: 64rpx !important;
|
||||
height: 64rpx;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 75rpx;
|
||||
}
|
||||
|
||||
.questions {
|
||||
margin: 0px 16px 10px 16px;
|
||||
}
|
||||
|
||||
.question_content {
|
||||
background-color: #f5f5f5;
|
||||
padding: 16rpx 24rpx;
|
||||
border-radius: 12px;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
min-height: 65px;
|
||||
max-height: 380px;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
padding: 0px 16rpx 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.footer .file_list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
gap: 16rpx;
|
||||
overflow-x: scroll;
|
||||
padding: 20rpx 0px;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
left: 0px;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.img-preview {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.img-preview-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.img-preview-loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-color: #eee;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.img-preview-close {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.input_box {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: row;
|
||||
gap: 10rpx;
|
||||
position: relative;
|
||||
min-height: 40px;
|
||||
padding: 0px 0px;
|
||||
background-color: white;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.set_panel_modal {
|
||||
position: fixed;
|
||||
width: 750rpx;
|
||||
height: 100vh;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.set_panel {
|
||||
background-color: #f3f3f3;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.set_panel_funtion {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 10px 16px;
|
||||
box-sizing: border-box;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.set_panel_cancel {
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
color: black;
|
||||
border-top: #cfcdcd solid 1px;
|
||||
}
|
||||
|
||||
.function {
|
||||
display: flex;
|
||||
width: 150rpx;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background-color: #f3f4f6;
|
||||
color: black;
|
||||
padding: 12px 6px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
|
||||
.text_desc {
|
||||
font-weight: 300;
|
||||
font-size: 24rpx;
|
||||
color: rgb(95, 114, 146);
|
||||
}
|
||||
|
||||
.input_inner_box {
|
||||
width: 100%;
|
||||
min-height: 54px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: #f3f3f3 solid 1px;
|
||||
border-radius: 16px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.say_box {
|
||||
font-weight: bold;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: 8px;
|
||||
color: black;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
max-height: 160px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.say_btn {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.right_btns {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.left_btns {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.set {
|
||||
width: 58rpx;
|
||||
height: 58rpx;
|
||||
}
|
||||
|
||||
.send-set {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
|
||||
.system {
|
||||
margin-left: 24rpx;
|
||||
margin-right: 24rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-top: 12px;
|
||||
padding-bottom: 16px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
.avatar-left{
|
||||
position:absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
.guide_system {
|
||||
padding-left: 32rpx;
|
||||
padding-right: 32rpx;
|
||||
border-radius: 12rpx;
|
||||
padding-bottom: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.bot_intro_system {
|
||||
padding-left: 32rpx;
|
||||
padding-right: 32rpx;
|
||||
border-radius: 12rpx;
|
||||
padding-bottom: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.userContent {
|
||||
margin-top: 12px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.userContent .fileBar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0px 16px;
|
||||
overflow-x: scroll;
|
||||
max-height: 80px;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.user .user_content {
|
||||
background-color: #f3f5fb;
|
||||
border-radius: 12rpx 0rpx 12rpx 12rpx;
|
||||
margin-left: 32rpx;
|
||||
margin-right: 32rpx;
|
||||
padding: 24rpx;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
font-size: 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.operation-menu {
|
||||
position: absolute;
|
||||
bottom: -120rpx;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 1);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
padding: 16rpx 24rpx;
|
||||
gap: 32rpx;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* 添加三角形指示器 */
|
||||
.operation-menu::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -16rpx; /* 调整三角形位置 */
|
||||
left: 30rpx; /* 调整三角形的水平位置,使其指向文本 */
|
||||
border-left: 16rpx solid transparent;
|
||||
border-right: 16rpx solid transparent;
|
||||
border-bottom: 16rpx solid rgba(0, 0, 0, 0.8);
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.menu-item text {
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.feedback_modal {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 750rpx;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal {
|
||||
background-color: #fff;
|
||||
width: 700rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal_head {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.modal_body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.modal_footer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.link-box {
|
||||
padding: 0px 16px 6px 16px;
|
||||
}
|
||||
|
||||
.tool_box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
gap: 20rpx;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: scroll;
|
||||
padding: 20rpx 0rpx 0rpx;
|
||||
}
|
||||
|
||||
.webSearchSwitch {
|
||||
width: 200rpx;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 25px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
font-size: 14px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.feature_enable {
|
||||
background-color: rgb(219, 234, 254);
|
||||
color: rgb(77, 107, 254);
|
||||
border-color: rgba(0, 122, 255, 0.15);
|
||||
}
|
||||
|
||||
.feature_list {
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
bottom: calc(100% + 20rpx);
|
||||
}
|
||||
|
||||
.no_feature_list {
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
bottom: calc(100%);
|
||||
}
|
||||
|
||||
|
||||
/* 抽屉遮罩层 */
|
||||
.drawer-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 998;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.drawer-mask.show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* 抽屉主体 */
|
||||
.drawer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: -80%;
|
||||
width: 80%;
|
||||
height: 100vh;
|
||||
background: #f9fbff;
|
||||
z-index: 999;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer.show {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
padding: 16rpx 32rpx 16rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
height: 0;
|
||||
margin-bottom: 20px;
|
||||
margin-left:32rpx;
|
||||
margin-right:32rpx;
|
||||
}
|
||||
|
||||
.con-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-left: 16rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.create-new-chat {
|
||||
border-radius: 8px;
|
||||
background: #dee9fc;
|
||||
color: #4d6bfe;
|
||||
cursor: pointer;
|
||||
padding: 16rpx 24rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date-title {
|
||||
font-size: 16px;
|
||||
color: rgb(128, 128, 128);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.con-container {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.con-block {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.con-item {
|
||||
padding: 12px 8px;
|
||||
margin-bottom: 2px;
|
||||
border-radius: 8px;
|
||||
|
||||
}
|
||||
|
||||
.con-item:active {
|
||||
transition: filter 0.4s;
|
||||
cursor: pointer;
|
||||
background-color: rgb(249, 251, 255);
|
||||
filter: brightness(0.95);
|
||||
}
|
||||
|
||||
.selected-con {
|
||||
background-color: rgb(249, 251, 255);
|
||||
filter: brightness(95%);
|
||||
transition: filter 0.4s;
|
||||
}
|
||||
|
||||
.tool_btn {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
padding: 10rpx;
|
||||
border: 1rpx solid #cfcdcd;
|
||||
border-radius: 14rpx;
|
||||
}
|
||||
|
||||
.playing_btn {
|
||||
height: 36rpx;
|
||||
padding: 10rpx;
|
||||
border: 1rpx solid #cfcdcd;
|
||||
border-radius: 14rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.speed-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 0rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 20rpx;
|
||||
/* background: #f5f5f7; */
|
||||
font-size: 26rpx;
|
||||
color: #222;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.speed-label {
|
||||
margin-left: 6rpx;
|
||||
}
|
||||
|
||||
.speed-popup {
|
||||
position: absolute;
|
||||
bottom: 48rpx;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08);
|
||||
z-index: 99;
|
||||
padding: 8rpx 0;
|
||||
min-width: 80rpx;
|
||||
}
|
||||
|
||||
.speed-option {
|
||||
padding: 16rpx 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.speed-option:active {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
/* 底部操作菜单弹窗 */
|
||||
.action-menu-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.action-menu {
|
||||
background: #ffffff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
overflow: hidden;
|
||||
animation: slideUp 0.3s ease-out;
|
||||
margin: 0 20rpx 20rpx 20rpx;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.action-item {
|
||||
padding: 32rpx 0;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
background: #ffffff;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.action-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.action-item:active {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.cancel-item {
|
||||
margin-top: 20rpx;
|
||||
border-radius: 24rpx;
|
||||
border-bottom: none;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
!function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d(function(n,t){return n<<t|n>>>32-t}(d(d(t,n),d(e,u)),o),r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function i(n,t){var r,e,o,u,c;n[t>>5]|=128<<t%32,n[14+(t+64>>>9<<4)]=t;var f=1732584193,i=-271733879,a=-1732584194,h=271733878;for(r=0;r<n.length;r+=16)i=m(i=m(i=m(i=m(i=v(i=v(i=v(i=v(i=g(i=g(i=g(i=g(i=l(i=l(i=l(i=l(o=i,a=l(u=a,h=l(c=h,f=l(e=f,i,a,h,n[r],7,-680876936),i,a,n[r+1],12,-389564586),f,i,n[r+2],17,606105819),h,f,n[r+3],22,-1044525330),a=l(a,h=l(h,f=l(f,i,a,h,n[r+4],7,-176418897),i,a,n[r+5],12,1200080426),f,i,n[r+6],17,-1473231341),h,f,n[r+7],22,-45705983),a=l(a,h=l(h,f=l(f,i,a,h,n[r+8],7,1770035416),i,a,n[r+9],12,-1958414417),f,i,n[r+10],17,-42063),h,f,n[r+11],22,-1990404162),a=l(a,h=l(h,f=l(f,i,a,h,n[r+12],7,1804603682),i,a,n[r+13],12,-40341101),f,i,n[r+14],17,-1502002290),h,f,n[r+15],22,1236535329),a=g(a,h=g(h,f=g(f,i,a,h,n[r+1],5,-165796510),i,a,n[r+6],9,-1069501632),f,i,n[r+11],14,643717713),h,f,n[r],20,-373897302),a=g(a,h=g(h,f=g(f,i,a,h,n[r+5],5,-701558691),i,a,n[r+10],9,38016083),f,i,n[r+15],14,-660478335),h,f,n[r+4],20,-405537848),a=g(a,h=g(h,f=g(f,i,a,h,n[r+9],5,568446438),i,a,n[r+14],9,-1019803690),f,i,n[r+3],14,-187363961),h,f,n[r+8],20,1163531501),a=g(a,h=g(h,f=g(f,i,a,h,n[r+13],5,-1444681467),i,a,n[r+2],9,-51403784),f,i,n[r+7],14,1735328473),h,f,n[r+12],20,-1926607734),a=v(a,h=v(h,f=v(f,i,a,h,n[r+5],4,-378558),i,a,n[r+8],11,-2022574463),f,i,n[r+11],16,1839030562),h,f,n[r+14],23,-35309556),a=v(a,h=v(h,f=v(f,i,a,h,n[r+1],4,-1530992060),i,a,n[r+4],11,1272893353),f,i,n[r+7],16,-155497632),h,f,n[r+10],23,-1094730640),a=v(a,h=v(h,f=v(f,i,a,h,n[r+13],4,681279174),i,a,n[r],11,-358537222),f,i,n[r+3],16,-722521979),h,f,n[r+6],23,76029189),a=v(a,h=v(h,f=v(f,i,a,h,n[r+9],4,-640364487),i,a,n[r+12],11,-421815835),f,i,n[r+15],16,530742520),h,f,n[r+2],23,-995338651),a=m(a,h=m(h,f=m(f,i,a,h,n[r],6,-198630844),i,a,n[r+7],10,1126891415),f,i,n[r+14],15,-1416354905),h,f,n[r+5],21,-57434055),a=m(a,h=m(h,f=m(f,i,a,h,n[r+12],6,1700485571),i,a,n[r+3],10,-1894986606),f,i,n[r+10],15,-1051523),h,f,n[r+1],21,-2054922799),a=m(a,h=m(h,f=m(f,i,a,h,n[r+8],6,1873313359),i,a,n[r+15],10,-30611744),f,i,n[r+6],15,-1560198380),h,f,n[r+13],21,1309151649),a=m(a,h=m(h,f=m(f,i,a,h,n[r+4],6,-145523070),i,a,n[r+11],10,-1120210379),f,i,n[r+2],15,718787259),h,f,n[r+9],21,-343485551),f=d(f,e),i=d(i,o),a=d(a,u),h=d(h,c);return[f,i,a,h]}function a(n){var t,r="",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function e(n){var t,r,e="0123456789abcdef",o="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>4&15)+e.charAt(15&t);return o}function r(n){return unescape(encodeURIComponent(n))}function o(n){return function(n){return a(i(h(n),8*n.length))}(r(n))}function u(n,t){return function(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,16<o.length&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}(r(n),r(t))}function t(n,t,r){return t?r?u(t,n):function(n,t){return e(u(n,t))}(t,n):r?o(n):function(n){return e(o(n))}(n)}"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:n.md5=t}(this);
|
||||
//# sourceMappingURL=md5.min.js.map
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
Component({
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
// 工具名称
|
||||
toolName: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
// 工具状态:success/failed/running
|
||||
toolStatus: {
|
||||
type: String,
|
||||
value: "success",
|
||||
},
|
||||
// 工具参数
|
||||
toolParams: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
toolResult: {
|
||||
type: String,
|
||||
value: "",
|
||||
},
|
||||
// 是否默认展开
|
||||
defaultExpanded: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
isExpanded: false,
|
||||
parsedParams: "", // 解析后的参数对象
|
||||
parsedResult: "", // 解析后的结果对象
|
||||
},
|
||||
|
||||
observers: {
|
||||
toolParams: function (toolParams) {
|
||||
if (toolParams) {
|
||||
try {
|
||||
const parsed = JSON.stringify(JSON.parse(toolParams), null, 2);
|
||||
console.log(parsed);
|
||||
this.setData({ parsedParams: parsed });
|
||||
} catch (e) {
|
||||
// 解析失败返回原字符串
|
||||
this.setData({ parsedParams: toolParams });
|
||||
}
|
||||
} else {
|
||||
this.setData({ parsedParams: "" });
|
||||
}
|
||||
},
|
||||
toolResult: function (toolResult) {
|
||||
if (toolResult) {
|
||||
try {
|
||||
const parsed = JSON.stringify(JSON.parse(toolResult), null, 2);
|
||||
console.log(parsed);
|
||||
this.setData({ parsedResult: parsed });
|
||||
} catch (e) {
|
||||
// 解析失败返回原字符串
|
||||
this.setData({ parsedResult: toolResult });
|
||||
}
|
||||
} else {
|
||||
this.setData({ parsedResult: "" });
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
// 切换展开/收起
|
||||
toggleExpand() {
|
||||
this.setData({
|
||||
isExpanded: !this.data.isExpanded,
|
||||
});
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 生命周期函数
|
||||
*/
|
||||
attached() {
|
||||
// 初始化展开状态
|
||||
this.setData({
|
||||
isExpanded: this.properties.defaultExpanded,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<view class="tool">
|
||||
<view class="header" bind:tap="toggleExpand">
|
||||
<image wx:if="{{toolStatus==='running'}}" class="icon" src="../imgs/loading.svg" mode="aspectFill" />
|
||||
<image wx:if="{{toolStatus==='success'}}" class="icon" src="../imgs/check.svg" mode="aspectFill" />
|
||||
<image wx:if="{{toolStatus==='failed'}}" class="icon" src="../imgs/close-red.svg" mode="aspectFill" />
|
||||
<view class="title">调用工具:{{toolName}}</view>
|
||||
<image class="arrow" style="transform: rotate({{isExpanded?0:-90}}deg);" src="../imgs/arrow.svg"
|
||||
mode="aspectFill" />
|
||||
</view>
|
||||
<view class="content" style='display: {{isExpanded?"block":"none"}}'>
|
||||
<view class="content-title">参数:</view>
|
||||
<view>{{parsedParams}}</view>
|
||||
<view class="divider"></view>
|
||||
<view class="content-title">调用结果:</view>
|
||||
<view>{{parsedResult}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
.tool {
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 10rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: #333333;
|
||||
padding: 20rpx;
|
||||
color: #f5f5f5;
|
||||
white-space: pre-wrap;
|
||||
font-family: monospace;
|
||||
}
|
||||
.content-title{
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.divider{
|
||||
height: 20px;
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
export const checkConfig = (chatMode, agentConfig, modelConfig) => {
|
||||
const { botId } = agentConfig || {};
|
||||
const { modelProvider, quickResponseModel, deepReasoningModel } = modelConfig || {};
|
||||
// 检测不在微信环境,提示用户
|
||||
const appBaseInfo = wx.getAppBaseInfo();
|
||||
try {
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
if (systemInfo.environment === "wxwork") {
|
||||
return [false, "请前往微信客户端扫码打开小程序"];
|
||||
}
|
||||
} catch (e) {
|
||||
if (appBaseInfo.host.env === "SDK") {
|
||||
return [false, "请前往微信客户端扫码打开小程序"];
|
||||
}
|
||||
}
|
||||
|
||||
// 检测AI能力,不存在提示用户
|
||||
if (compareVersions(appBaseInfo.SDKVersion, "3.7.7") < 0) {
|
||||
return [false, "使用AI能力需基础库为3.7.7及以上,请升级基础库版本或微信客户端"];
|
||||
}
|
||||
if (!["bot", "model"].includes(chatMode)) {
|
||||
return [false, "chatMode 不正确,值应为“bot”或“model”"];
|
||||
}
|
||||
if (chatMode === "bot" && !botId) {
|
||||
return [false, "当前chatMode值为bot,请配置botId"];
|
||||
}
|
||||
if (chatMode === "model" && (!modelProvider || !quickResponseModel)) {
|
||||
return [false, "当前chatMode值为model,请配置modelProvider和quickResponseModel"];
|
||||
}
|
||||
return [true, ""];
|
||||
};
|
||||
// 随机选取三个问题
|
||||
export function randomSelectInitquestion(question = [], num = 3) {
|
||||
if (question.length <= num) {
|
||||
return [...question];
|
||||
}
|
||||
const set = new Set();
|
||||
while (set.size < num) {
|
||||
const randomIndex = Math.floor(Math.random() * question.length);
|
||||
set.add(question[randomIndex]);
|
||||
}
|
||||
return Array.from(set);
|
||||
}
|
||||
|
||||
export const getCloudInstance = (function () {
|
||||
let cloudInstance = null;
|
||||
return async function (envShareConfig) {
|
||||
if (cloudInstance) {
|
||||
return cloudInstance;
|
||||
}
|
||||
// 如果开启了环境共享,走环境共享的ai实例
|
||||
if (envShareConfig && envShareConfig.resourceAppid && envShareConfig.resourceEnv) {
|
||||
let instance = new wx.cloud.Cloud({
|
||||
// 资源方 AppID
|
||||
resourceAppid: envShareConfig.resourceAppid,
|
||||
// 资源方环境 ID
|
||||
resourceEnv: envShareConfig.resourceEnv,
|
||||
});
|
||||
await instance.init();
|
||||
// 烦,环境共享时创建实例,没有把环境id挂在instance上,这里手动挂上去,如果你发现instance上有个env,那么这个insatnce就是环境共享的云开发实例
|
||||
instance.env = envShareConfig.resourceEnv;
|
||||
cloudInstance = instance;
|
||||
return cloudInstance;
|
||||
} else {
|
||||
cloudInstance = wx.cloud;
|
||||
return cloudInstance;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
export const compareVersions = (version1, version2) => {
|
||||
const v1Parts = version1.split(".").map(Number);
|
||||
const v2Parts = version2.split(".").map(Number);
|
||||
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
||||
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
const num1 = v1Parts[i] || 0;
|
||||
const num2 = v2Parts[i] || 0;
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
} else if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
let isDomainWarn = false;
|
||||
|
||||
export const commonRequest = async (options) => {
|
||||
const cloudInstance = await getCloudInstance();
|
||||
const self = this;
|
||||
// 判断 当前sdk 版本是否 小于 3.8.1
|
||||
const appBaseInfo = wx.getAppBaseInfo();
|
||||
const { path } = options;
|
||||
if (compareVersions(appBaseInfo.SDKVersion, "3.8.1") < 0) {
|
||||
console.log("走wx request");
|
||||
const cloudInstance = await getCloudInstance();
|
||||
const { token } = await cloudInstance.extend.AI.bot.tokenManager.getToken();
|
||||
const envId = cloudInstance.env || cloudInstance.extend.AI.bot.context.env;
|
||||
return wx.request({
|
||||
...options,
|
||||
path: undefined,
|
||||
url: `https://${envId}.api.tcloudbasegateway.com/v1/aibot/${path}`,
|
||||
header: {
|
||||
...options.header,
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
fail: (e) => {
|
||||
if (options.fail) {
|
||||
options.fail.bind(self)(e);
|
||||
if (e.errno === 600002 || e.errMsg.includes("url not in domain list")) {
|
||||
let msg = `请前往微信公众平台 request 合法域名配置中添加云开发域名 https://${envId}.api.tcloudbasegateway.com`;
|
||||
if (!isDomainWarn) {
|
||||
isDomainWarn = true;
|
||||
wx.showModal({
|
||||
title: "提示",
|
||||
content: msg,
|
||||
complete: () => {
|
||||
isDomainWarn = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const ai = cloudInstance.extend.AI;
|
||||
return ai.request(options);
|
||||
}
|
||||
};
|
||||
|
||||
export const sleep = (timeout) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, timeout);
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Component({
|
||||
options: {
|
||||
virtualHost: true,
|
||||
},
|
||||
data: {
|
||||
},
|
||||
properties: {
|
||||
dataClipboardText: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 复制到剪贴板
|
||||
copyClipBoard: function () {
|
||||
wx.setClipboardData({
|
||||
data: this.data.dataClipboardText,
|
||||
// success() {
|
||||
// wx.getClipboardData({
|
||||
// success() {},
|
||||
// });
|
||||
// },
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"component": true,
|
||||
"styleIsolation": "shared",
|
||||
"usingComponents": {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<view class="markdown-it-code-copy" bindtap="copyClipBoard">
|
||||
<image src="../../imgs/copy.svg" style="width: 32rpx !important;height: 32rpx !important" mode="aspectFill" />
|
||||
</view>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
.markdown-it-code-copy {
|
||||
position: absolute;
|
||||
top: 7.5px;
|
||||
right: 6px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
import MarkdownIt from './utils/markdown-it.min.js';
|
||||
import highlight from './utils/highlight.min.js';
|
||||
import hljsJs from './utils/hljs_javascript.min.js';
|
||||
import hljsCss from './utils/hljs_css.min.js';
|
||||
import { addCustomClassPlugin,copy } from './utils/plugin'
|
||||
Component({
|
||||
options: {
|
||||
virtualHost: true,
|
||||
},
|
||||
properties: {
|
||||
className: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
style: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
markdown: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
fontSize: {
|
||||
type: Number,
|
||||
value: 32
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
},
|
||||
data: {
|
||||
__html: '',
|
||||
mdInstance: null,
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const { options } = this.data;
|
||||
|
||||
const hljs = highlight();
|
||||
const javascript = hljsJs();
|
||||
const css = hljsCss();
|
||||
hljs.registerLanguage('javascript', javascript);
|
||||
hljs.registerLanguage('css', css);
|
||||
const md = new MarkdownIt({
|
||||
// 默认开启高亮
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return (
|
||||
'<pre class="_pre"><code class="hljs">' +
|
||||
hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
|
||||
'</code></pre>'
|
||||
);
|
||||
} catch (__) { }
|
||||
}
|
||||
return '<pre class="_pre"><code class="hljs">' + str + '</code></pre>';
|
||||
},
|
||||
...options,
|
||||
});
|
||||
// console.log(md.renderer.rules)
|
||||
md.use(copy);
|
||||
addCustomClassPlugin(md)
|
||||
this.setData({ mdInstance: md });
|
||||
this.triggerEvent('onReady', { markdownInstance: md });
|
||||
this.setData({
|
||||
__html: md.render(this.data.markdown),
|
||||
});
|
||||
},
|
||||
updateWidgetAPI() {
|
||||
this.setReadonlyAttributes &&
|
||||
this.setReadonlyAttributes({
|
||||
value: this.properties.markdown,
|
||||
markdownInstance: this.data.mdInstance,
|
||||
updateMarkdownInstance: ({ markdownInstance }) => this.setData({ mdInstance: markdownInstance }),
|
||||
});
|
||||
},
|
||||
},
|
||||
observers: {
|
||||
markdown: function () {
|
||||
const { mdInstance } = this.data;
|
||||
if (!mdInstance) return;
|
||||
const html = mdInstance.render(this.data.markdown)
|
||||
this.setData({
|
||||
__html: html,
|
||||
});
|
||||
},
|
||||
options: function () {
|
||||
this.init();
|
||||
},
|
||||
'markdown,mdInstance': function () {
|
||||
this.updateWidgetAPI();
|
||||
},
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.init();
|
||||
this.updateWidgetAPI();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"component": true,
|
||||
"styleIsolation": "shared",
|
||||
"usingComponents": {
|
||||
"mp-html":"./mp-html/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<view class="wd-markdown" style="font-size: {{fontSize}}rpx;">
|
||||
<mp-html content="{{__html}}" scroll-table="{{true}}" selectable="{{true}}"/>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
markdown 样式
|
||||
*/
|
||||
.wd-markdown {
|
||||
word-wrap: break-word;
|
||||
word-break: normal;
|
||||
text-align: justify;
|
||||
}
|
||||
.wd-markdown ._p {
|
||||
margin-bottom: 10rpx;
|
||||
line-height: 1.8;
|
||||
word-break: break-all;
|
||||
}
|
||||
.wd-markdown ._ol {
|
||||
margin-bottom: 30rpx;
|
||||
padding-left: 1.2em;
|
||||
}
|
||||
.wd-markdown ._ul {
|
||||
margin-bottom: 30rpx;
|
||||
padding-left: 1.2em;
|
||||
}
|
||||
.wd-markdown ._hr {
|
||||
border: none;
|
||||
border-top: 3px solid #eee;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.wd-markdown ._pre {
|
||||
max-width: 100%;
|
||||
padding: 32rpx;
|
||||
overflow-x: auto;
|
||||
background-color: rgb(246, 248, 250);
|
||||
border-radius: 12rpx;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
line-height: 1.14285em;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.wd-markdown ._h1 {
|
||||
border-bottom-style: double;
|
||||
border-bottom-width: 6rpx;
|
||||
font-size: 42rpx;
|
||||
padding-bottom: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.wd-markdown ._h2 {
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1rpx;
|
||||
font-size: 40rpx;
|
||||
padding-bottom: 8rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.wd-markdown ._h3 {
|
||||
font-size: 38rpx;
|
||||
padding-bottom: 6rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.wd-markdown ._h4 {
|
||||
font-size: 36rpx;
|
||||
padding-bottom: 4rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.wd-markdown ._h5 {
|
||||
font-size: 34rpx;
|
||||
padding-bottom: 2rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.wd-markdown ._h6 {
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.wd-markdown ._a {
|
||||
margin: 0 8rpx;
|
||||
border-bottom-width: 1rpx;
|
||||
border-bottom-style: solid;
|
||||
line-height: 1;
|
||||
color: #0000ee;
|
||||
}
|
||||
.wd-markdown ._blockquote {
|
||||
margin: 0 0 10px;
|
||||
padding: 15px 20px;
|
||||
background-color: #f1f2f3;
|
||||
border-left: 5px solid #ccc;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
.wd-markdown ._tableParent {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.wd-markdown ._table {
|
||||
min-width: fit-content;
|
||||
border-collapse: collapse;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wd-markdown ._table ._th,
|
||||
.wd-markdown ._table ._td {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
min-width: 70px;
|
||||
padding: 0px 5px;
|
||||
border: 1px solid #e1e6f0;
|
||||
vertical-align: top;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.wd-markdown ._table ._th {
|
||||
font-weight: bold;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.wd-markdown ._table ._td {
|
||||
background-color: white;
|
||||
}
|
||||
.wd-markdown ._table ._th > ._p,
|
||||
.wd-markdown ._table ._td > ._p {
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
.wd-markdown image {
|
||||
width: 480rpx !important;
|
||||
height: 480rpx !important;
|
||||
}
|
||||
/*!
|
||||
Theme: GitHub
|
||||
Description: Light theme as seen on github.com
|
||||
Author: github.com
|
||||
Maintainer: @Hirse
|
||||
Updated: 2021-05-15
|
||||
|
||||
Outdated base version: https://github.com/primer/github-syntax-light
|
||||
Current colors taken from GitHub's CSS
|
||||
*/
|
||||
.hljs {
|
||||
color: #24292e;
|
||||
/* background: #ffffff; */
|
||||
}
|
||||
.hljs-doctag,
|
||||
.hljs-keyword,
|
||||
.hljs-meta .hljs-keyword,
|
||||
.hljs-template-tag,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable.language_ {
|
||||
/* prettylights-syntax-keyword */
|
||||
color: #d73a49;
|
||||
}
|
||||
.hljs-title,
|
||||
.hljs-title.class_,
|
||||
.hljs-title.class_.inherited__,
|
||||
.hljs-title.function_ {
|
||||
/* prettylights-syntax-entity */
|
||||
color: #6f42c1;
|
||||
}
|
||||
.hljs-attr,
|
||||
.hljs-attribute,
|
||||
.hljs-literal,
|
||||
.hljs-meta,
|
||||
.hljs-number,
|
||||
.hljs-operator,
|
||||
.hljs-variable,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-id {
|
||||
/* prettylights-syntax-constant */
|
||||
color: #005cc5;
|
||||
}
|
||||
.hljs-regexp,
|
||||
.hljs-string,
|
||||
.hljs-meta .hljs-string {
|
||||
/* prettylights-syntax-string */
|
||||
color: #032f62;
|
||||
}
|
||||
.hljs-built_in,
|
||||
.hljs-symbol {
|
||||
/* prettylights-syntax-variable */
|
||||
color: #e36209;
|
||||
}
|
||||
.hljs-comment,
|
||||
.hljs-code,
|
||||
.hljs-formula {
|
||||
/* prettylights-syntax-comment */
|
||||
color: #6a737d;
|
||||
}
|
||||
.hljs-name,
|
||||
.hljs-quote,
|
||||
.hljs-selector-tag,
|
||||
.hljs-selector-pseudo {
|
||||
/* prettylights-syntax-entity-tag */
|
||||
color: #22863a;
|
||||
}
|
||||
.hljs-subst {
|
||||
/* prettylights-syntax-storage-modifier-import */
|
||||
color: #24292e;
|
||||
}
|
||||
.hljs-section {
|
||||
/* prettylights-syntax-markup-heading */
|
||||
color: #005cc5;
|
||||
font-weight: bold;
|
||||
}
|
||||
.hljs-bullet {
|
||||
/* prettylights-syntax-markup-list */
|
||||
color: #735c0f;
|
||||
}
|
||||
.hljs-emphasis {
|
||||
/* prettylights-syntax-markup-italic */
|
||||
color: #24292e;
|
||||
font-style: italic;
|
||||
}
|
||||
.hljs-strong {
|
||||
/* prettylights-syntax-markup-bold */
|
||||
color: #24292e;
|
||||
font-weight: bold;
|
||||
}
|
||||
.hljs-addition {
|
||||
/* prettylights-syntax-markup-inserted */
|
||||
color: #22863a;
|
||||
background-color: #f0fff4;
|
||||
}
|
||||
.hljs-deletion {
|
||||
/* prettylights-syntax-markup-deleted */
|
||||
color: #b31d28;
|
||||
background-color: #ffeef0;
|
||||
}
|
||||
.hljs-char.escape_,
|
||||
.hljs-link,
|
||||
.hljs-params,
|
||||
.hljs-property,
|
||||
.hljs-punctuation,
|
||||
.hljs-tag {
|
||||
/* purposely ignored */
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";function e(t){"@babel/helpers - typeof";return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(e,t,o){return(t=n(t))in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function n(t){var n=o(t,"string");return"symbol"==e(n)?n:n+""}function o(t,n){if("object"!=e(t)||!t)return t;var o=t[Symbol.toPrimitive];if(void 0!==o){var i=o.call(t,n||"default");if("object"!=e(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===n?String:Number)(t)}/*!
|
||||
* mp-html v2.5.0
|
||||
* https://github.com/jin-yufeng/mp-html
|
||||
*
|
||||
* Released under the MIT license
|
||||
* Author: Jin Yufeng
|
||||
*/
|
||||
var i=require("./parser"),r=[];Component({data:{nodes:[]},properties:{containerStyle:String,content:{type:String,value:"",observer:function(e){this.setContent(e)}},copyLink:{type:Boolean,value:!0},domain:String,errorImg:String,lazyLoad:Boolean,loadingImg:String,pauseVideo:{type:Boolean,value:!0},previewImg:{type:null,value:!0},scrollTable:Boolean,selectable:null,setTitle:{type:Boolean,value:!0},showImgMenu:{type:Boolean,value:!0},tagStyle:Object,useAnchor:null},created:function(){this.plugins=[];for(var e=r.length;e--;)this.plugins.push(new r[e](this))},detached:function(){this._hook("onDetached")},methods:{in:function(e,t,n){e&&t&&n&&(this._in={page:e,selector:t,scrollTop:n})},navigateTo:function(e,n){var o=this;return new Promise(function(i,r){if(!o.data.useAnchor)return void r(Error("Anchor is disabled"));var a=wx.createSelectorQuery().in(o._in?o._in.page:o).select((o._in?o._in.selector:"._root")+(e?"".concat(">>>","#").concat(e):"")).boundingClientRect();o._in?a.select(o._in.selector).scrollOffset().select(o._in.selector).boundingClientRect():a.selectViewport().scrollOffset(),a.exec(function(e){if(!e[0])return void r(Error("Label not found"));var a=e[1].scrollTop+e[0].top-(e[2]?e[2].top:0)+(n||parseInt(o.data.useAnchor)||0);o._in?o._in.page.setData(t({},o._in.scrollTop,a)):wx.pageScrollTo({scrollTop:a,duration:300}),i()})})},getText:function(e){var t="";return function e(n){for(var o=0;o<n.length;o++){var i=n[o];if("text"===i.type)t+=i.text.replace(/&/g,"&");else if("br"===i.name)t+="\n";else{var r="p"===i.name||"div"===i.name||"tr"===i.name||"li"===i.name||"h"===i.name[0]&&i.name[1]>"0"&&i.name[1]<"7";r&&t&&"\n"!==t[t.length-1]&&(t+="\n"),i.children&&e(i.children),r&&"\n"!==t[t.length-1]?t+="\n":"td"!==i.name&&"th"!==i.name||(t+="\t")}}}(e||this.data.nodes),t},getRect:function(){var e=this;return new Promise(function(t,n){wx.createSelectorQuery().in(e).select("._root").boundingClientRect().exec(function(e){return e[0]?t(e[0]):n(Error("Root label not found"))})})},pauseMedia:function(){for(var e=(this._videos||[]).length;e--;)this._videos[e].pause()},setPlaybackRate:function(e){this.playbackRate=e;for(var t=(this._videos||[]).length;t--;)this._videos[t].playbackRate(e)},setContent:function(e,t){var n=this;this.imgList&&t||(this.imgList=[]),this._videos=[];var o={},r=new i(this).parse(e);if(t)for(var a=this.data.nodes.length,s=r.length;s--;)o["nodes[".concat(a+s,"]")]=r[s];else o.nodes=r;if(this.setData(o,function(){n._hook("onLoad"),n.triggerEvent("load")}),this.data.lazyLoad||this.imgList._unloadimgs<this.imgList.length/2){var l=0,c=function(e){e&&e.height||(e={}),e.height===l?n.triggerEvent("ready",e):(l=e.height,setTimeout(function(){n.getRect().then(c).catch(c)},350))};this.getRect().then(c).catch(c)}else this.imgList._unloadimgs||this.getRect().then(function(e){n.triggerEvent("ready",e)}).catch(function(){n.triggerEvent("ready",{})})},_hook:function(e){for(var t=r.length;t--;)this.plugins[t][e]&&this.plugins[t][e]()},_add:function(e){e.detail.root=this}}});
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"component":true,"usingComponents":{"node":"./node/node"}}
|
||||