chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<view class="markdown-custom-process-group">
|
||||
<view class="group-header" @tap="toggleExpanded">
|
||||
<view class="header-left">
|
||||
<text class="group-title">{{ getI18nText('Mobile.ThirdParty.MpHtml.toolCall') }}</text>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<text class="process-count">{{ processCount + ' ' + getI18nText('Mobile.ThirdParty.MpHtml.itemCount') }}</text>
|
||||
<text class="iconfont icon-a-Chevrondown expand-icon" :class="{ 'is-expanded': isExpanded }"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="isExpanded" class="group-content">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { t } from '@/utils/i18n'
|
||||
|
||||
export default {
|
||||
name: 'MarkdownContainerGroup',
|
||||
props: {
|
||||
// 仅用于计算数量,不再直接渲染
|
||||
childs: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isExpanded: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
processCount() {
|
||||
// 过滤掉可能的空白节点,支持原生 container 和 PC 端 HTML 标签名,同时排除隐藏的 Event 类型
|
||||
return (this.childs || []).filter(n =>
|
||||
(n.name === 'container' || n.name === 'markdown-custom-process') &&
|
||||
n.attrs?.type !== 'Event'
|
||||
).length
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getI18nText(key, params) {
|
||||
return t(key, params)
|
||||
},
|
||||
toggleExpanded() {
|
||||
this.isExpanded = !this.isExpanded
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.markdown-custom-process-group {
|
||||
margin: 16rpx 0;
|
||||
border-radius: 12rpx;
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.08);
|
||||
background-color: #ffffff;
|
||||
overflow: hidden;
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 24rpx;
|
||||
background-color: rgba(0, 0, 0, 0.02);
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.group-title {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
|
||||
.process-count {
|
||||
font-size: 24rpx;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
font-size: 24rpx;
|
||||
color: #8c8c8c;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&.is-expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group-content {
|
||||
padding: 12rpx 24rpx;
|
||||
border-top: 1rpx solid rgba(0, 0, 0, 0.05);
|
||||
max-height: 500rpx;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,648 @@
|
||||
<template>
|
||||
<view v-if="toolCall?.type !== 'Event'" class="tool-call-status">
|
||||
<!-- Plan 类型:直接显示任务列表 -->
|
||||
<template v-if="isPlanType">
|
||||
<!-- Plan 头部信息 -->
|
||||
<view class="plan-header">
|
||||
<view class="plan-info">
|
||||
<text class="plan-name">{{
|
||||
toolCall.name || getI18nText("Mobile.ThirdParty.MpHtml.executionPlan")
|
||||
}}</text>
|
||||
<!-- <view class="plan-status-display">
|
||||
<view class="status-icon" :class="getStatusIconClass(toolCall.status)">
|
||||
<text :class="getStatusIconType(toolCall.status)" :style="{color: getStatusIconColor(toolCall.status),fontSize: '32rpx'}"></text>
|
||||
</view>
|
||||
<text class="plan-status-text">{{ getStatusText(toolCall.status) }}</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="plan-expand-icon" @tap="togglePlanExpanded">
|
||||
<text class="iconfont" :class="planExpanded ? 'icon-MinusOutlined' : 'icon-Plus'"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Plan 任务列表(直接展示) -->
|
||||
<view v-if="planExpanded && planTaskList.length > 0" class="plan-task-list">
|
||||
<view v-for="(task, index) in planTaskList" :key="index" class="plan-task-item">
|
||||
<!-- 字体图标实现的状态 -->
|
||||
<view class="task-status-icon" :class="getTaskStatusClass(task.status)">
|
||||
<text class="task-icon iconfont" :class="getTaskStatusIcon(task.status)"></text>
|
||||
</view>
|
||||
<text class="task-content">{{ task.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 非 Plan 类型:显示工具调用状态 -->
|
||||
<template v-else>
|
||||
<!-- 工具调用头部信息 -->
|
||||
<view class="tool-header" @tap="toggleExpanded">
|
||||
<view class="tool-info">
|
||||
<text class="tool-name">{{ toolNameDisplay }}</text>
|
||||
<view class="tool-status-display">
|
||||
<view class="status-icon" :class="getStatusIconClass(toolCall.status)">
|
||||
<text :class="getStatusIconType(toolCall.status)" :style="{color: getStatusIconColor(toolCall.status),fontSize: '32rpx'}"></text>
|
||||
</view>
|
||||
<text class="tool-status-text">{{ getStatusText(toolCall.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tool-actions">
|
||||
<view class="action-icon" @tap.stop.prevent="handleShowDetails(detailData)">
|
||||
<text class="iconfont icon-ProfileOutlined"></text>
|
||||
</view>
|
||||
<!-- <view class="action-icon" @tap.stop.prevent="handleCopyToClipboard">
|
||||
<text class="iconfont icon-Copy"></text>
|
||||
</view> -->
|
||||
<view v-if="isPageType(toolCall)" class="action-icon" @tap.stop.prevent="openPreviewPage(toolCall)">
|
||||
<text class="iconfont icon-eye-open"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 展开后的详细信息 调用参数/调用结果-->
|
||||
<!-- <view v-if="expanded" class="tool-details-expanded">
|
||||
<view v-if="detailData.params && Object.keys(detailData.params).length > 0" class="detail-section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">{{
|
||||
getI18nText("Mobile.ThirdParty.MpHtml.callArguments")
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="arguments-content">
|
||||
<text class="arguments-text">{{ formatArguments(detailData.params) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="detailData.response" class="detail-section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">{{
|
||||
getI18nText("Mobile.ThirdParty.MpHtml.callResult")
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="output-content">
|
||||
<text class="output-text">{{ formatResult(detailData.response) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
|
||||
import { AgentComponentTypeEnum } from '@/types/enums/agent.uts';
|
||||
import { getCurrentPageParams } from '@/utils/common';
|
||||
import { getFileProxyUrlByConversationIdAndFilePath, jumpToFilePreviewPage } from '@/utils/system.uts';
|
||||
import { t } from '@/utils/i18n';
|
||||
|
||||
export default {
|
||||
name: 'Container',
|
||||
components: {
|
||||
uniIcons,
|
||||
// toolDetailsModal
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// expanded: false,
|
||||
planExpanded: true, // Plan 类型默认展开
|
||||
toolCall: this.data
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 判断是否为 Plan 类型
|
||||
isPlanType() {
|
||||
return this.toolCall.type === AgentComponentTypeEnum.Plan || this.toolCall.type === 'Plan'
|
||||
},
|
||||
|
||||
// 格式化显示的工具名称,处理多行代码情况
|
||||
toolNameDisplay() {
|
||||
let name = this.toolCall.name || this.toolCall.type || '';
|
||||
// 还原引号实体
|
||||
name = name.replace(/"/g, '"');
|
||||
// 替换换行符为空格,防止换行符干扰单行省略号显示
|
||||
return name.replace(/\n/g, ' ').trim();
|
||||
},
|
||||
|
||||
// Plan 任务列表
|
||||
planTaskList() {
|
||||
const result = this.toolCall.result || {}
|
||||
const data = result.data
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data
|
||||
}
|
||||
|
||||
return []
|
||||
},
|
||||
|
||||
detailData() {
|
||||
const _result = this.toolCall.result || {}
|
||||
return {
|
||||
// 从结果中提取输入参数,如果没有则提供空对象
|
||||
params: _result.input || {},
|
||||
// 使用结果的 data 作为响应数据,如果没有则提供空对象
|
||||
response: _result.data || null,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler(newData) {
|
||||
this.toolCall = newData;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getI18nText(key) {
|
||||
return t(key)
|
||||
},
|
||||
|
||||
// 打开页面首页
|
||||
openPreviewPage(data) {
|
||||
uni.$emit('page_preview_executing', data);
|
||||
},
|
||||
|
||||
// 切换展开状态
|
||||
async toggleExpanded() {
|
||||
const result = this.data?.result;
|
||||
|
||||
// 打开预览页面
|
||||
if (result?.kind === 'edit') {
|
||||
const params = getCurrentPageParams();
|
||||
|
||||
const conversationId = params.conversationId;
|
||||
const file_path = result?.input?.file_path;
|
||||
|
||||
const fileProxyUrl = await getFileProxyUrlByConversationIdAndFilePath(conversationId, file_path);
|
||||
jumpToFilePreviewPage(conversationId, fileProxyUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// this.expanded = !this.expanded
|
||||
},
|
||||
|
||||
// 切换 Plan 展开状态
|
||||
togglePlanExpanded() {
|
||||
this.planExpanded = !this.planExpanded
|
||||
},
|
||||
|
||||
// 显示详情
|
||||
showDetails() {
|
||||
if (!this.toolCall.result) {
|
||||
return uni.showToast({
|
||||
icon: 'none',
|
||||
title: t('Mobile.ThirdParty.MpHtml.emptyResult'),
|
||||
})
|
||||
}
|
||||
// this.expanded = !this.expanded
|
||||
},
|
||||
|
||||
// 处理显示详情点击(阻止冒泡)
|
||||
handleShowDetails() {
|
||||
uni.$emit('page_preview_detail', this.toolCall, this.detailData);
|
||||
},
|
||||
|
||||
// 处理复制到剪贴板点击(阻止冒泡)
|
||||
handleCopyToClipboard(event) {
|
||||
event.stopPropagation()
|
||||
this.copyToClipboard()
|
||||
},
|
||||
|
||||
// 复制结果
|
||||
copyResult() {
|
||||
// 实现复制功能
|
||||
console.log('复制结果')
|
||||
},
|
||||
|
||||
// 复制到剪贴板
|
||||
copyToClipboard() {
|
||||
// 实现复制到剪贴板功能
|
||||
uni.setClipboardData({
|
||||
data: this.formatArguments(this.detailData),
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: t('Mobile.Common.copySuccess'),
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: t('Mobile.Common.copyFailed'),
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取状态图标类型
|
||||
getStatusIconType(status) {
|
||||
const iconMap = {
|
||||
'EXECUTING': 'icon-Loader', // 执行中显示加载图标
|
||||
'FINISHED': 'icon-Check', // 已完成显示对勾
|
||||
'FAILED': 'icon-waring' // 执行失败显示叉号
|
||||
}
|
||||
return ` iconfont ${iconMap[status] || 'icon-Check'}`
|
||||
},
|
||||
|
||||
// 获取状态图标样式类
|
||||
getStatusIconClass(status) {
|
||||
const statusClassMap = {
|
||||
'EXECUTING': 'status-icon-executing',
|
||||
'FINISHED': 'status-icon-finished',
|
||||
'FAILED': 'status-icon-failed'
|
||||
}
|
||||
return statusClassMap[status] || 'status-icon-default'
|
||||
},
|
||||
|
||||
// 获取状态图标颜色
|
||||
getStatusIconColor(status) {
|
||||
const statusColorMap = {
|
||||
'EXECUTING': '#1890ff',
|
||||
'FINISHED': '#52c41a',
|
||||
// 'FAILED': '#ff4d4f'
|
||||
'FAILED': '#ffcb00'
|
||||
}
|
||||
return statusColorMap[status] || '#999'
|
||||
},
|
||||
|
||||
// 获取状态文本
|
||||
getStatusText(status) {
|
||||
return '';
|
||||
// const statusTextMap = {
|
||||
// 'EXECUTING': '执行中',
|
||||
// 'FINISHED': '已完成',
|
||||
// 'FAILED': '执行失败'
|
||||
// }
|
||||
// return statusTextMap[status] || '未知状态'
|
||||
},
|
||||
|
||||
|
||||
// 获取任务状态样式类
|
||||
getTaskStatusClass(status) {
|
||||
const classMap = {
|
||||
'completed': 'task-status-completed',
|
||||
'pending': 'task-status-pending',
|
||||
'in_progress': 'task-status-in-progress',
|
||||
'failed': 'task-status-failed'
|
||||
}
|
||||
return classMap[status] || 'task-status-pending'
|
||||
},
|
||||
|
||||
// 获取任务状态图标 (使用字体图标unicode)
|
||||
getTaskStatusIcon(status) {
|
||||
const iconMap = {
|
||||
'pending': 'icon-BorderOutlined', // 待处理
|
||||
'in_progress': 'icon-HourglassOutlined', // 进行中
|
||||
'completed': 'icon-CheckSquareOutlined', // 已完成
|
||||
'failed': 'icon-CloseSquareOutlined' // 失败
|
||||
}
|
||||
return iconMap[status] || 'icon-BorderOutlined'
|
||||
},
|
||||
|
||||
// 格式化参数显示
|
||||
formatArguments(args) {
|
||||
try {
|
||||
return JSON.stringify(args, null, 2)
|
||||
} catch (error) {
|
||||
return String(args)
|
||||
}
|
||||
},
|
||||
|
||||
// 格式化结果显示
|
||||
formatResult(result) {
|
||||
if (result && typeof result === 'object') {
|
||||
try {
|
||||
return JSON.stringify(result, null, 2)
|
||||
} catch (error) {
|
||||
return String(result)
|
||||
}
|
||||
}
|
||||
return String(result)
|
||||
},
|
||||
|
||||
// 格式化执行时间
|
||||
formatExecutionTime(time) {
|
||||
if (time < 1000) {
|
||||
return `${time}ms`
|
||||
} else if (time < 60000) {
|
||||
return `${(time / 1000).toFixed(2)}s`
|
||||
} else {
|
||||
return `${(time / 60000).toFixed(2)}min`
|
||||
}
|
||||
},
|
||||
isPageType(toolCall) {
|
||||
return toolCall.type === AgentComponentTypeEnum.Page;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tool-call-status {
|
||||
width: 100%;
|
||||
margin: 16rpx 0;
|
||||
border-radius: 16rpx;
|
||||
background-color: rgba(12, 20, 102, 0.04);
|
||||
overflow: hidden;
|
||||
|
||||
.iconfont {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
// Plan 类型样式
|
||||
.plan-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
|
||||
.plan-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
gap: 16rpx;
|
||||
|
||||
.plan-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.plan-status-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 8rpx;
|
||||
|
||||
.status-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.status-icon-executing {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.plan-status-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .plan-expand-icon {
|
||||
// .iconfont {
|
||||
// font-size: 32rpx;
|
||||
// color: #333;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// Plan 任务列表
|
||||
.plan-task-list {
|
||||
padding: 0 24rpx 24rpx;
|
||||
border-top: 2rpx solid rgba(0, 0, 0, 0.06);
|
||||
margin-top: 0;
|
||||
|
||||
.plan-task-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
gap: 8rpx;
|
||||
padding: 12rpx 0;
|
||||
|
||||
.task-status-icon {
|
||||
flex-shrink: 0;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 4rpx;
|
||||
|
||||
.task-icon {
|
||||
font-family: 'iconfont';
|
||||
font-size: 32rpx;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #8c8c8c;
|
||||
}
|
||||
}
|
||||
|
||||
.task-content {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #262626;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非 Plan 类型样式(原有样式)
|
||||
.tool-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
|
||||
.tool-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
gap: 16rpx;
|
||||
|
||||
.tool-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
line-height: 40rpx;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tool-status-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 8rpx;
|
||||
|
||||
.status-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
// border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.status-icon-executing {
|
||||
animation: spin 1s linear infinite;
|
||||
|
||||
.iconfont {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-icon-finished {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-icon-failed {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.status-icon-default {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.tool-status-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 32rpx;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tool-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 16rpx;
|
||||
|
||||
.action-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6rpx;
|
||||
transition: background-color 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
.iconfont {
|
||||
// font-size: 32rpx;
|
||||
font-weight: 400;
|
||||
// color: #333;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tool-details-expanded {
|
||||
padding: 24rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-top: 2rpx solid #f0f0f0;
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.execute-id-content,
|
||||
.arguments-content,
|
||||
.output-content,
|
||||
.error-content,
|
||||
.execution-time {
|
||||
padding: 16rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid #e9ecef;
|
||||
|
||||
.execute-id-text,
|
||||
.arguments-text,
|
||||
.output-text,
|
||||
.error-text,
|
||||
.time-text {
|
||||
font-size: 24rpx;
|
||||
line-height: 36rpx;
|
||||
color: #495057;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
&.error-section {
|
||||
.error-content {
|
||||
background-color: #fff5f5;
|
||||
border-color: #ffccc7;
|
||||
|
||||
.error-text {
|
||||
color: #cf1322;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载动画
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 750rpx) {
|
||||
.tool-header {
|
||||
padding: 20rpx;
|
||||
|
||||
.tool-info {
|
||||
.tool-name {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.tool-status-display {
|
||||
.tool-status-text {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tool-details-expanded {
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @fileoverview Container 插件
|
||||
*/
|
||||
function Container(vm) {}
|
||||
|
||||
export default Container;
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 按优先级从 processingList 中获取数据
|
||||
* 优先级顺序:FINISHED -> FAILED -> EXECUTING
|
||||
* @param executeId 执行ID
|
||||
* @param processingList 处理列表
|
||||
* @returns 按优先级排序后的数据
|
||||
*/
|
||||
export const getProcessingDataByPriority = (executeId, processingList) => {
|
||||
if (!processingList || !Array.isArray(processingList)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// 过滤出匹配 executeId 的项目
|
||||
const matchedItems = processingList.filter(
|
||||
(item) => item.executeId === executeId
|
||||
);
|
||||
|
||||
if (matchedItems.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// 定义状态优先级(数字越小优先级越高)
|
||||
const statusPriority = {
|
||||
FINISHED: 1,
|
||||
FAILED: 2,
|
||||
EXECUTING: 3,
|
||||
};
|
||||
|
||||
// 按优先级排序,优先级高的在前
|
||||
const sortedItems = matchedItems.sort((a, b) => {
|
||||
const priorityA = statusPriority[a.status] || 999;
|
||||
const priorityB = statusPriority[b.status] || 999;
|
||||
return priorityA - priorityB;
|
||||
});
|
||||
|
||||
// 返回优先级最高的项目
|
||||
return sortedItems[0] || {};
|
||||
};
|
||||
Reference in New Issue
Block a user