From 1d0eec6da86e3e9bcbf002d1a22142586fe023a3 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期二, 31 十二月 2024 11:34:15 +0800 Subject: [PATCH] 拆分组件 assistantMsg.vue --- src/components/chat/Chat.vue | 781 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 672 insertions(+), 109 deletions(-) diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue index ec0c7c9..ff4ec3f 100644 --- a/src/components/chat/Chat.vue +++ b/src/components/chat/Chat.vue @@ -1,98 +1,154 @@ <template> - <div class="flex flex-col h-full"> - <div class="h-full flex flex-col items-center overflow-y-auto"> - <div ref="chatListDom" class="h-full w-[100ch]"> - <div - class="group flex px-4 py-4 hover:bg-slate-100 rounded-lg" - v-for="(item, index) of messageList.filter((v) => v.role !== 'system')" - :key="index" - > - <img class="rounded-full size-12 mr-4" :src="roleImageMap[item.role]" alt="" srcset="" /> + <ChatContainer + :loading="chatListLoading" + :more-is-loading="moreIsLoading" + :is-share-page="isSharePage" + :chat-width="chatWidth" + ref="containerRef" + > + <!-- 娑堟伅鍒楄〃 --> + <template #message-list> + <template v-if="computedMessageList?.length > 0"> + <div v-for="(item, msgIndex) of computedMessageList" :key="`${item.historyId}_${item.role}`"> + <UserMsg + :msg="item" + @shareClick="shareClick" + @setCommonQuestion="setCommonQuestionClick" + v-if="item.role === RoleEnum.user" + ></UserMsg> - <div class="flex"> - <div class="relative" v-if="item.content?.values"> - <div - class="text-sm rounded-[6px] p-4 leading-relaxed max-w-[100ch] bg-white" - > - <component class="max-w-[100ch]" :is="answerTypeMapCom[item.content.type]" :data="item.content.values" /> - </div> - - <!-- <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 space-x-2 mr-2 mt-2"> - <SvgIcon class="cursor-pointer" name="ele-CopyDocument" @click="copyClick(item.content)" /> - <SvgIcon class="cursor-pointer" name="ywicon icon-dianzan" /> - <SvgIcon class="cursor-pointer" :size="12" name="ywicon icon-buzan" /> - </div> --> + <AssistantMsg + v-else + :msg="item" + :msgList="computedMessageList" + :isLast="msgIndex === computedMessageList.length - 1" + @sendChatMessage="sendChatMessage" + @shareMsg="shareClick" + :isTalking="isTalking" + /> + </div> + <div v-if="showAskMore" class="ml-4 mt-5 pb-10"> + <div class="text-gray-600 mb-5">浣犲彲浠ョ户缁棶鎴戯細</div> + <div class="space-y-2 inline-flex flex-col"> + <div + v-for="item in computedMessageList.at(-1).content.askMoreList" + :key="item.history_id" + class="bg-white p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg" + @click="askMoreClick(item)" + > + {{ item.question }} </div> - - <Loding v-else /> </div> </div> - </div> - </div> + </template> + <el-empty v-else-if="isSharePage && !chatListLoading" :image-size="200"> + <template #description> + <span class="text-[15px]">鍒嗕韩鐨勫璇濅笉瀛樺湪鎴栧凡澶辨晥</span> + </template> + </el-empty> + </template> - <div class="sticky bottom-0 w-full p-6 pb-8 bg-gray-100 flex justify-center"> - <PlayBar :isTalking="isTalking" v-model="messageContent.values" @sendClick="sendChatMessage" /> - </div> - </div> + <!-- 杈撳叆鍖哄煙 --> + <template #input-area> + <PlayBar + v-model:voicePageIsShow="voicePageIsShow" + :isTalking="isTalking" + :isHome="false" + v-model="messageContent.values" + @sendClick="sendClick" + @showUpChatClick="showUpChatClick" + @stopGenClick="stopGenClick" + @showDownChatClick="showDownChatClick" + :style="{ width: chatWidth }" + :setCommonQuestionInfo="setCommonQuestionInfo" + /> + </template> + + <!-- 鎶藉眽 --> + <template #drawer> + <CustomDrawer v-model:isShow="drawerIsShow" @updateChatInput="updateChatInput" /> + <ShareLinkDlg ref="shareLinkDlgRef" /> + </template> + </ChatContainer> </template> <script setup lang="ts"> -import { nextTick, onMounted, ref, watch } from 'vue'; -import useClipboard from 'vue-clipboard3'; -import Loding from './components/Loding.vue'; -import { RecordSet } from './model/Record'; +import type { CancelTokenSource } from 'axios'; +import axios from 'axios'; +import { orderBy } from 'lodash-es'; +import moment from 'moment'; +import { computed, onActivated, onMounted, ref } from 'vue'; +import { loadAmisSource } from '../amis/load'; +import { convertProcessItem, convertProcessToStep, formatShowTimeYear, useScrollLoad } from './hooks/useScrollLoad'; import type { ChatContent } from './model/types'; -import { AnswerType, RoleEnum, answerTypeMapCom, roleImageMap, type ChatMessage } from './model/types'; -import { QuestionAi } from '/@/api/ai/chat'; +import { AnswerState, AnswerType, RoleEnum, type ChatMessage } from './model/types'; +import { getShareChatJsonByPost, questionStreamByPost } from '/@/api/ai/chat'; import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue'; -import router from '/@/router'; -import { activeChatRoom } from '/@/stores/chatRoom'; -import { ElMessage } from 'element-plus'; +import CustomDrawer from '/@/components/drawer/CustomDrawer.vue'; +import { Logger } from '/@/model/logger/Logger'; +import { ElMessage } from 'element-plus'; +import AssistantMsg from './assistant/index.vue'; +import ChatContainer from './components/ChatContainer.vue'; +import ShareLinkDlg from './components/shareLink/index.vue'; +import UserMsg from './user/index.vue'; +import router from '/@/router'; +import { + activeChatRoom, + activeGroupType, + activeLLMId, + activeRoomId, + activeSampleId, + isSharePage, + roomConfig, +} from '/@/stores/chatRoom'; +import emitter from '/@/utils/mitt'; +import { useCompRef } from '/@/utils/types'; +import { toMyFixed } from '/@/utils/util'; +const containerRef = useCompRef(ChatContainer); +const chatListDom = computed(() => containerRef.value?.chatListDom); +const chatWidth = '75%'; +const voicePageIsShow = ref(false); let isTalking = ref(false); + let messageContent = ref<ChatContent>({ type: AnswerType.Text, values: '', }); -const chatListDom = ref<HTMLDivElement>(); +const currentRoute = router.currentRoute; +const currentRouteId = currentRoute.value.query.id as string; +activeRoomId.value = currentRouteId; const messageList = ref<ChatMessage[]>([]); - -onMounted(() => { - if (!activeChatRoom.value) { - router.replace({ - name: 'Home', - }); - return; - } - messageContent.value = { - type: AnswerType.Text, - values: activeChatRoom.value.title, - }; - sendChatMessage(); +const computedMessageList = computed(() => { + return messageList.value.filter((v) => !!v); }); -const questionAi = async (text) => { - // const res = await QuestionAi({ - // question: text, - // }); - const res = { - json_ok: true, - question: '鏄ㄦ棩浜斾竴骞垮満鍘嬪姏', - answer_type: 'recordset', - values: { - names: ['yesterday', 'max_pressure'], - values: [ - ['2024-06-28 00:00:00', 24.378], - ['2024-06-29 00:00:00', 24.276], - ], - type: 'records', - title: '鏄ㄦ棩浜斾竴骞垮満(D_GW_04)鐨勬渶澶у帇鍔涘��', - }, +const parseExtraContent = (res) => { + if (!res) return {}; + const askMoreList = orderBy(res.context_history, [(item) => Number(item.radio)], ['desc']); + const errCode = res?.err_code; + const errMsg = res?.json_msg; + const origin = res; + + return { + askMoreList, + errCode, + errMsg, + origin, }; +}; + +const parseContent = (res, reportIsShow = false, extraContent?) => { + if (!res) return null; let content: ChatContent = { type: AnswerType.Text, - values: '鍙戠敓閿欒锛�', + values: '瑙f瀽澶辫触锛�', }; + if (res.type) { + res.answer_type = res.type; + } + const curExtraContent = parseExtraContent(res); + switch (res.answer_type) { case AnswerType.RecordSet: content = { @@ -103,45 +159,285 @@ case AnswerType.Text: content = { type: AnswerType.Text, + values: res.values ?? res.answer, + }; + break; + case AnswerType.Script: + content = { + type: AnswerType.Script, + values: res, + }; + break; + + case AnswerType.Knowledge: + content = { + type: AnswerType.Knowledge, + values: res.knowledge, + }; + + break; + case AnswerType.Report: + content = { + type: AnswerType.Report, + values: (res?.reports ?? []).map((item) => ({ + content: parseContent(item, reportIsShow, { origin: item, conclusion: item.conclusion ?? [] }), + })), + }; + break; + + case AnswerType.Summary: + content = { + type: AnswerType.Summary, + values: res.summary?.map((item) => { + item.reportIsShow = reportIsShow; + return item; + }), + }; + break; + case AnswerType.Url: + content = { + type: AnswerType.Url, + values: res.url, + }; + break; + case AnswerType.Map: + content = { + type: AnswerType.Map, values: res.values, }; break; default: + content = { + type: AnswerType.Text, + values: '瑙f瀽澶辫触锛�', + }; break; } + if (!extraContent) { + content = { + ...content, + ...curExtraContent, + }; + } else { + content = { + ...content, + ...extraContent, + }; + } + return content; }; -const sendChatMessage = async (content: ChatContent = messageContent.value) => { - if (!messageContent.value?.values) return; - if (activeChatRoom.value.isInitial) { - activeChatRoom.value.title = messageContent.value.values; - activeChatRoom.value.isInitial = false; - } - try { - isTalking.value = true; - // 鍙戦�佸綋鍓� - messageList.value.push({ role: RoleEnum.user, content }); - // 娓呯┖杈撳叆妗� - clearMessageContent(); - // 鍑虹幇鍥炲锛岀疆绌哄嚭鐜扮瓑寰呭姩鐢� - messageList.value.push({ role: RoleEnum.assistant, content: null }); +let questionRes = null; +let position = null; +const preQuestion = ref(null); - let resMsgContent: ChatContent = null; - resMsgContent = await questionAi(content.values); - appendLastMessageContent(resMsgContent); - } catch (error: any) { - appendLastMessageContent({ - type: AnswerType.Text, - values: '鍙戠敓閿欒锛�', - }); - } finally { - isTalking.value = false; +let lastAxiosSource: CancelTokenSource = null; +const questionAi = async (text) => { + let judgeParams = null; + if (!preQuestion.value) { + judgeParams = {}; + } else { + judgeParams = { + prev_question: preQuestion.value, + }; } -}; -const appendLastMessageContent = (content: ChatContent) => { - messageList.value.at(-1).content = content; + const params = { + question: text, + history_group_id: currentRouteId, + raw_mode: roomConfig.value?.[currentRouteId]?.isAnswerByLLM ?? false, + ...judgeParams, + } as any; + + if (position) { + const longitude = position.coords.longitude; + const latitude = position.coords.latitude; + params.cur_pos = [longitude, latitude].join(','); + } + + if (activeGroupType.value) { + params.group_type = activeGroupType.value; + } + + if (currentSampleId) { + params.sample_id = currentSampleId; + currentSampleId = ''; + } + + let lastTimestamp = new Date().getTime(); + questionRes = {}; + let lastIsResult = false; + const resultP = new Promise((resolve, reject) => { + const currentSource = axios.CancelToken.source(); + lastAxiosSource = currentSource; + + const getResReport = () => { + const resReport = { + answer_type: AnswerType.Report, + reports: [], + }; + return resReport; + }; + const checkReportEmpty = () => { + const isEmpty = !questionRes?.reports || questionRes?.reports?.length === 0; + + return isEmpty; + }; + questionStreamByPost( + params, + (chunkRes) => { + Logger.info('chunk response锛歕n\n' + JSON.stringify(chunkRes)); + + if (chunkRes.mode === 'result') { + lastIsResult = true; + const res = chunkRes.value; + + if (checkReportEmpty()) { + const resReport = getResReport(); + resReport.reports.push(res); + questionRes = resReport; + resolve(resReport); + } else { + const lastMsg = computedMessageList.value.at(-1); + + // 宸茬粡瑙f瀽杩囦竴娆� reports + lastMsg.content.values.push({ + content: parseContent(res, true, { + origin: res, + }), + }); + } + return; + // chunkRes.value = '鍑嗗鏁版嵁鍒嗘瀽'; + } + + if (chunkRes.mode === 'summary') { + const lastMsg = computedMessageList.value.at(-1); + const extraContent = parseExtraContent(chunkRes.value); + const isReportEmpty = checkReportEmpty(); + // 娌℃湁缁忚繃 result 鎶ュ憡杩樻病鍒濆鍖� + if (isReportEmpty) { + const resReport = getResReport(); + questionRes = resReport; + } + // 姝ゅ璇濆凡缁忓姞鍏ュ埌瀵硅瘽鍒楄〃 + if (lastMsg.content?.values && extraContent) { + for (const key in extraContent) { + if (Object.prototype.hasOwnProperty.call(extraContent, key)) { + const value = extraContent[key]; + if (!lastMsg.content[key] || (Array.isArray(lastMsg.content[key]) && lastMsg.content[key].length === 0)) { + lastMsg.content[key] = value; + } + } + } + + lastMsg.historyId = chunkRes.value.history_id; + const userMsg = computedMessageList.value.at(-2); + userMsg.historyId = chunkRes.value.history_id; + userMsg.content.values = chunkRes.value.question; + } + + if (Object.keys(questionRes).length === 0) { + questionRes = chunkRes.value; + } + + // 姝ゅ璇濊繕鏈姞鍏ュ埌瀵硅瘽鍒楄〃 + if (!lastMsg.content?.values && questionRes) { + questionRes = { + ...questionRes, + ...chunkRes.value, + }; + } + + if (isReportEmpty) { + resolve(questionRes); + } + // computedMessageList.value[computedMessageList.value.length - 1] = finalMsg; + scrollToBottom(); + // chunkRes.value = '浣犲彲浠ョ户缁棶鎴�'; + return; + } + + if (chunkRes.mode === 'conclusion') { + const lastReport = computedMessageList.value.at(-1)?.content?.values?.at(-1); + if (lastReport) { + lastReport.conclusion = chunkRes.value; + chunkRes.value = '鍒嗘瀽缁撴潫'; + } + } + + if (chunkRes.mode === 'question') { + const lastGroup = computedMessageList.value.at(-1).stepGroup.at(-1); + const stepList = lastGroup?.value ?? []; + const lastStepItem = stepList.at(-1); + if (!lastStepItem.subStep) { + lastStepItem.subStep = []; + } + lastStepItem.subStep.push({ + type: chunkRes.value.type, + data: chunkRes.value, + }); + scrollToBottom(); + return; + } + // 鏆傛椂涓嶈�冭檻澶氫釜 report鎯呭喌 + + // if (lastIsResult && chunkRes.mode !== 'finish') { + // // 寮�濮嬪鍔犳柊鐨� stepGroup + // computedMessageList.value.at(-1).stepGroup.push({ + // value: [], + // isShow: true, + // }); + // lastIsResult = false; + // } + const lastGroup = computedMessageList.value.at(-1).stepGroup.at(-1); + const stepList = lastGroup?.value ?? []; + const currentTimeStamp = new Date().getTime(); + const ms = toMyFixed(currentTimeStamp - lastTimestamp, 2) + ' ms'; + if (chunkRes.mode === 'finish') { + stepList.at(-1).ms = ms; + isTalking.value = false; + + return; + } + + if (stepList?.length >= 1) { + stepList.at(-1).ms = ms; + } else { + const stepGroup = computedMessageList.value.at(-1).stepGroup; + if (stepGroup.length > 1) { + const lastStepList = stepGroup.at(-2).value; + lastStepList.at(-1).ms = ms; + } + } + lastTimestamp = currentTimeStamp; + const stepItem = convertProcessItem(chunkRes); + + stepList.push(stepItem); + // 寮哄埗瑙﹀彂鏇存柊 + + scrollToBottom(); + }, + { + cancelToken: currentSource.token, + } + ) + .catch((err) => { + throw err; + }) + .finally(() => { + isTalking.value = false; + // 鏀惰捣鎵�鏈� stepGroup + computedMessageList.value.at(-1).stepGroup.forEach((item) => { + item.isShow = false; + }); + }); + }); + + await resultP; + const content = parseContent(questionRes, true); + return content; }; const clearMessageContent = () => @@ -150,29 +446,296 @@ values: '', }); -const scrollToBottom = () => { - if (!chatListDom.value) return; - chatListDom.value.lastElementChild.scrollIntoView(); - // scrollTo(0, chatListDom.value.scrollHeight); +let currentSampleId = ''; + +let currentLLMId = null; + +const stopGenClick = () => { + lastAxiosSource?.cancel(); + isTalking.value = false; + chatListLoading.value = false; + + computedMessageList.value.at(-1).isStopMsg = true; }; -watch(messageList.value, () => nextTick(() => scrollToBottom())); +const checkCanSend = (content: ChatContent = messageContent.value) => { + if (!content?.values) { + return false; + } + if (isTalking.value || chatListLoading.value) { + ElMessage.warning('ai 姝e湪鍥炲涓紝璇风◢鍚庡皾璇曟彁闂�'); + return false; + } + return true; +}; -//#region ====================== 鑱婂ぉ鍐呭鎿嶄綔 ====================== +const addChatItem = (content: ChatContent) => { + isTalking.value = true; + const userItem: ChatMessage = { role: RoleEnum.user, content, isChecked: false } as any; + const assistantItem: ChatMessage = { + role: RoleEnum.assistant, + content: { + type: AnswerType.Report, + }, + state: AnswerState.Null, + stepGroup: [ + { + value: [], + isShow: true, + }, + ], + isStopMsg: false, + isChecked: false, + } as any; + messageList.value.push(userItem); + clearMessageContent(); -const { toClipboard } = useClipboard(); + messageList.value.push(assistantItem); + scrollToBottom(); + return [userItem, assistantItem]; +}; -const copyClick = (content) => { - ElMessage.success('澶嶅埗鎴愬姛'); - toClipboard(content); +const sendChatMessage = async (content: ChatContent = messageContent.value) => { + if (!checkCanSend(content)) { + return; + } + const isNewChat = messageList.value.length === 0; + if (isNewChat) { + if (activeSampleId.value) { + currentSampleId = activeSampleId.value; + } + + if (activeLLMId.value) { + currentLLMId = activeLLMId.value; + } + } + let resMsgContent: ChatContent = null; + + try { + const [userItem, assistantItem] = addChatItem(content); + + resMsgContent = await questionAi(content.values); + + updateLoadIndex(); + + userItem.historyId = questionRes?.history_id; + userItem.content.values = questionRes?.question ?? userItem.content.values; + assistantItem.historyId = questionRes?.history_id; + const currentTime = formatShowTimeYear(moment().format('YYYY-MM-DD HH:mm:ss')); + assistantItem.createTime = currentTime; + assistantItem.content = resMsgContent; + setTimeout(() => { + // 鏀跺埌鍥炲锛岀户缁粴 + scrollToBottom(); + }, 300); + } catch (error: any) {} +}; + +const sendClick = () => { + sendChatMessage(messageContent.value); +}; + +const { loadRangeData, onChatListScroll, moreIsLoading, updateLoadIndex } = useScrollLoad({ + container: chatListDom, + historyGroupId: currentRouteId, + messageList, + parseAnswerContent: parseContent, +}); + +const chatListLoading = ref(true); + +onActivated(() => { + emitter.emit('updateHeaderTitle', activeChatRoom.value?.title ?? ''); +}); + +const initNewChat = () => { + messageContent.value = { + type: AnswerType.Text, + values: activeChatRoom.value?.title, + }; + sendChatMessage(); +}; +const scrollToBottom = () => { + containerRef.value?.scrollToBottom(); +}; + +const initHistoryChat = () => { + // 鍒濆鐘舵�佹粴涓�涓� + scrollToBottom(); + + setTimeout(() => { + chatListDom.value.addEventListener('scroll', onChatListScroll); + }, 300); +}; + +/** + * 鍔犺浇鍒嗕韩鏁版嵁 + */ +const loadShareData = async () => { + const res = await getShareChatJsonByPost({ + share_id: router.currentRoute.value.query.id as string, + }); + + const msgValue = res?.values; + if (!msgValue) { + messageList.value = []; + return; + } + const userMsg: ChatMessage = { + historyId: msgValue.history_id, + role: RoleEnum.user, + content: { + type: AnswerType.Text, + values: msgValue.question, + }, + isChecked: false, + }; + + const assistantMsg: ChatMessage = { + historyId: msgValue.history_id, + role: RoleEnum.assistant, + content: parseContent(msgValue), + stepGroup: (msgValue?.reports ?? []).map((item) => ({ + value: convertProcessToStep(item?.exec_process), + isShow: false, + })), + isStopMsg: false, + + conclusion: msgValue.conclusion ?? [], + isChecked: false, + }; + messageList.value = [userMsg, assistantMsg]; +}; + +onMounted(async () => { + messageList.value = []; + chatListLoading.value = true; + if (isSharePage.value) { + await loadShareData().finally(() => { + chatListLoading.value = false; + }); + } else { + await loadRangeData().finally(() => { + chatListLoading.value = false; + }); + } + setTimeout(() => { + emitter.emit('updateHeaderTitle', activeChatRoom.value?.title ?? ''); + }, 300); + + if (messageList.value.length === 0) { + initNewChat(); + } else { + if (!isSharePage.value) { + setTimeout(() => { + initHistoryChat(); + }, 300); + } + } + loadAmisSource(); +}); + +//#region ====================== 鍏夋爣杈撳叆涓婁笅绠ご鏄剧ず鍘嗗彶娑堟伅 ====================== +const currentIndex = ref(null); +const history_data = computed(() => { + return computedMessageList.value.filter((item) => item.role === RoleEnum.user); +}); +//鏄剧ず涓婁竴鏉℃秷鎭� +const showUpChatClick = () => { + if (computedMessageList.value.length === 0) return; + if (currentIndex.value == 0) { + messageContent.value.values = history_data.value[currentIndex.value].content.values; + return; + } else { + currentIndex.value = (currentIndex.value + history_data.value.length - 1) % history_data.value.length; + } + messageContent.value.values = history_data.value[currentIndex.value].content.values; +}; +//鏄剧ず涓嬩竴鏉℃秷鎭� +const showDownChatClick = () => { + if (computedMessageList.value.length === 0) return; + if (currentIndex.value == history_data.value.length - 1) { + messageContent.value.values = history_data.value[currentIndex.value].content.values; + return; + } + if (currentIndex.value === null) { + currentIndex.value = 0; + } else { + currentIndex.value = (currentIndex.value + 1) % history_data.value.length; + } + messageContent.value.values = history_data.value[currentIndex.value].content.values; +}; +//#endregion +const showAskMore = computed(() => { + if (!computedMessageList.value || computedMessageList.value.length === 0) return false; + const last = computedMessageList.value.at(-1); + const isShow = last?.role === RoleEnum.assistant && last?.content?.values && last.content?.askMoreList?.length > 0; + const result = isShow && !isSharePage.value; + return result; +}); +const askMoreClick = (item) => { + if (!item.question) return; + sendChatMessage({ type: AnswerType.Text, values: item.question }); +}; + +//#region ====================== 渚ц竟鏍廳rawer ====================== +const drawerIsShow = ref(false); + +const updateChatInput = (content) => { + messageContent.value.values = content; +}; +//#endregion +//#region ====================== 鐢ㄦ埛璇㈤棶鐨勯棶棰樿缃负甯哥敤璇� ====================== +const setCommonQuestionInfo = ref({}); + +//鐢ㄦ埛闂璁剧疆涓哄父鐢ㄨ +const setCommonQuestionClick = (item) => { + setCommonQuestionInfo.value = item; +}; +//#endregion + +//#region ====================== 鍒嗕韩 ====================== + +const shareLinkDlgRef = useCompRef(ShareLinkDlg); + +const shareClick = async (item: ChatMessage) => { + shareLinkDlgRef.value.openShare(item); }; //#endregion </script> -<style scoped> +<style scoped lang="scss"> pre { font-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica, 'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB', 'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN', 'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif; } + +.more-loading { + :deep(.el-loading-spinner) { + --loading-size: 35px; + margin-top: 0; + .circular { + width: var(--loading-size); + height: var(--loading-size); + } + } +} + +:deep(.el-step__icon.is-text) { + --radius-size: 24px; + width: var(--radius-size); + height: var((--radius-size)); +} + +:deep(.el-step__icon-inner) { + font-size: 16px !important; +} +:deep(.el-step__description) { + min-height: 20px; +} + +:deep(.el-step:last-of-type .el-step__description) { + // display: none; +} </style> -- Gitblit v1.9.3