feat: 实现批量任务管理页面,包含任务创建向导、任务列表、状态展示、报告日志查看器及Revit模型查看器,并新增CAD数据存储。
This commit is contained in:
parent
a837baef95
commit
b53f9d37e5
@ -10,6 +10,24 @@
|
||||
- **Base URL**: `http://localhost:12345`
|
||||
- **端口**: `12345`
|
||||
|
||||
### 1.0. 插件可用性探活 API (Health Check)
|
||||
- **接口路径**: `/api/health` (或 `/api/status`)
|
||||
- **请求方式**: `GET`
|
||||
- **基础描述**: 用于队列执行前快速判活,检测 Creo 插件是否正常启动并可以接收任务,减少无效重试。
|
||||
- **接入说明**:
|
||||
- **请求参数**: 无
|
||||
- **响应格式**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Creo 插件在线就绪",
|
||||
"data": {
|
||||
"isBusy": false // 是否正忙于处理其他任务
|
||||
}
|
||||
}
|
||||
```
|
||||
- **异常响应**: 如插件未启动、断联或崩溃,通常表现为连接超时或 HTTP 50x 错误。
|
||||
|
||||
### 1.1. 打开模型 API
|
||||
- **接口路径**: `/api/model/open`
|
||||
- **请求方式**: `POST`
|
||||
@ -81,6 +99,24 @@
|
||||
- **Base URL**: `http://localhost:9000`
|
||||
- **端口**: `9000`
|
||||
|
||||
### 2.0. 插件可用性探活 API (Health Check)
|
||||
- **接口路径**: `/api/health` (或 `/api/status`)
|
||||
- **请求方式**: `GET`
|
||||
- **基础描述**: 用于队列执行前快速判活,检测 Revit 插件是否正常启动并可以接收任务,减少无效重试。
|
||||
- **接入说明**:
|
||||
- **请求参数**: 无
|
||||
- **响应格式**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Revit 插件在线就绪",
|
||||
"data": {
|
||||
"isBusy": false
|
||||
}
|
||||
}
|
||||
```
|
||||
- **异常响应**: 如插件未启动、断联或崩溃,通常表现为连接超时或 HTTP 50x 错误。
|
||||
|
||||
### 2.1. 打开模型 API
|
||||
- **接口路径**: `/api/open`
|
||||
- **请求方式**: `POST`
|
||||
@ -131,6 +167,24 @@
|
||||
- **Base URL**: `http://localhost:9001`
|
||||
- **端口**: `9001`
|
||||
|
||||
### 3.0. 插件可用性探活 API (Health Check)
|
||||
- **接口路径**: `/api/health` (或 `/api/status`)
|
||||
- **请求方式**: `GET`
|
||||
- **基础描述**: 用于队列执行前快速判活,检测 PDMS 插件是否正常启动并可以接收任务,减少无效重试。
|
||||
- **接入说明**:
|
||||
- **请求参数**: 无
|
||||
- **响应格式**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "PDMS 插件在线就绪",
|
||||
"data": {
|
||||
"isBusy": false
|
||||
}
|
||||
}
|
||||
```
|
||||
- **异常响应**: 如插件未启动、断联或崩溃,通常表现为连接超时或 HTTP 50x 错误。
|
||||
|
||||
### 3.1. 打开模型 API
|
||||
- **接口路径**: `/api/project/open` (打开工程) / `/api/mdb/open` (打开 MDB 数据库)
|
||||
- **请求方式**: `POST`
|
||||
|
||||
45
CAD插件探活API文档.md
Normal file
45
CAD插件探活API文档.md
Normal file
@ -0,0 +1,45 @@
|
||||
# CAD 插件可用性探活 API 接入文档
|
||||
|
||||
为了在队列执行前快速判断各 CAD(Creo、Revit、PDMS)插件是否在线、能否接收任务,从而减少无效的接口重试,特提供以下统一的探活(Health Check)API 说明。后端开发在接入调度队列前,可先通过本接口进行快速判活。
|
||||
|
||||
## 1. 统一接口规范
|
||||
|
||||
对所有 CAD 插件,推荐的探活接口标准如下,后端可统一做异常和状态处理:
|
||||
|
||||
- **典型接口路径**: `/api/health` 或 `/api/status`
|
||||
- **请求方式**: `GET`
|
||||
- **请求参数**: 无
|
||||
- **请求头**: 无特殊要求
|
||||
- **成功响应格式**:
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "[CAD软件名称] 插件在线就绪",
|
||||
"data": {
|
||||
"isBusy": false
|
||||
}
|
||||
}
|
||||
```
|
||||
- `data.isBusy`: (Boolean) `false` 表示空闲,可以接受新任务;`true` 表示当前插件正在忙于处理其他任务(例如正在解析一个非常大的模型)。队列调度时,可以结合此字段进行等待、延迟派发或抛出忙碌异常。
|
||||
|
||||
- **异常表现**:
|
||||
- 如果插件崩溃、未启动或网络断联,该接口通常会直接抛出 **连接超时 (Timeout)** 或 **HTTP 502/503/500/拒绝连接** 错误。
|
||||
- 队列调度进行预检查时,若捕获到任何网络层或 HTTP 非 2xx 异常,应即刻将当前节点判断为离线/不健康。
|
||||
|
||||
---
|
||||
|
||||
## 2. 各个 CAD 软件对接详情
|
||||
|
||||
各个 CAD 插件的基础地址和端口号不尽相同,后端组装对应 URL 发送请求测试连通性。
|
||||
|
||||
### 2.1. Creo Parametric
|
||||
- **当前 Base URL**: `http://localhost:12345` _(根据实际部署调整)_
|
||||
- **完整探活请求**: `GET http://localhost:12345/api/health`
|
||||
|
||||
### 2.2. Revit
|
||||
- **当前 Base URL**: `http://localhost:9000` _(根据实际部署调整)_
|
||||
- **完整探活请求**: `GET http://localhost:9000/api/health`
|
||||
|
||||
### 2.3. PDMS
|
||||
- **当前 Base URL**: `http://localhost:9001` _(根据实际部署调整)_
|
||||
- **完整探活请求**: `GET http://localhost:9001/api/health`
|
||||
@ -159,7 +159,7 @@
|
||||
<div v-show="wizardStep === 1" class="step-panel">
|
||||
<el-form :model="taskForm" label-width="120px">
|
||||
<el-form-item label="执行策略序列">
|
||||
<el-select v-model="taskForm.strategy" placeholder="请选择策略" style="width: 100%">
|
||||
<el-select v-model="taskForm.strategy" placeholder="请选择策略" style="width: 100%" @change="onStrategyChange">
|
||||
<el-option label="模型打开 -> Shrinkwrap外壳 -> 关闭模型 (Creo)" value="creo_shrinkwrap" />
|
||||
<el-option label="模型打开 -> 建筑模型剥壳 -> 关闭模型 (Revit)" value="revit_shell" />
|
||||
<el-option label="工程打开 -> 模型包裹化防泄密 -> 占位关闭 (PDMS)" value="pdms_shrinkwrap" />
|
||||
@ -169,6 +169,51 @@
|
||||
<el-form-item label="策略说明">
|
||||
<span class="form-tip" style="margin-left:0;">提交时会将策略转化为相应的 task_type 序述串通过 WebSocket 下发。</span>
|
||||
</el-form-item>
|
||||
|
||||
<div class="strategy-params" v-if="taskForm.strategy">
|
||||
<el-divider content-position="left"><i class="fas fa-sliders-h"></i> 策略级参数配置</el-divider>
|
||||
|
||||
<template v-if="taskForm.strategy === 'creo_shrinkwrap'">
|
||||
<el-form-item label="轻量化质量">
|
||||
<el-slider v-model="taskForm.params.quality" :min="1" :max="10" show-input style="max-width: 400px;"></el-slider>
|
||||
</el-form-item>
|
||||
<el-form-item label="导出格式">
|
||||
<el-select v-model="taskForm.params.exportFormat" placeholder="输出格式" style="width: 200px">
|
||||
<el-option label="默认 (.prt / .asm)" value="default" />
|
||||
<el-option label="STEP (.stp)" value="step" />
|
||||
<el-option label="IGES (.igs)" value="iges" />
|
||||
<el-option label="OBJ (.obj)" value="obj" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="高级过滤">
|
||||
<el-checkbox v-model="taskForm.params.ignoreSkeletons">忽略骨架</el-checkbox>
|
||||
<el-checkbox v-model="taskForm.params.ignoreQuilts">忽略面组 (Quilts)</el-checkbox>
|
||||
<el-checkbox v-model="taskForm.params.fillHoles">自动补孔</el-checkbox>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else-if="taskForm.strategy === 'revit_shell'">
|
||||
<el-form-item label="细节级别 (LOD)">
|
||||
<el-radio-group v-model="taskForm.params.lod">
|
||||
<el-radio label="粗糙">粗糙 (Coarse)</el-radio>
|
||||
<el-radio label="中等">中等 (Medium)</el-radio>
|
||||
<el-radio label="精细">精细 (Fine)</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="移除内部构件">
|
||||
<el-switch v-model="taskForm.params.removeInternal" active-text="是" inactive-text="否" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else-if="taskForm.strategy.includes('pdms')">
|
||||
<el-form-item label="层级保留">
|
||||
<el-input v-model="taskForm.params.levelFilter" placeholder="例如: /SITE/ZONE" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="移除管道附件">
|
||||
<el-switch v-model="taskForm.params.removeAttachments" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -212,7 +257,8 @@ const wizardStep = ref(0)
|
||||
const taskForm = ref({
|
||||
strategy: 'creo_shrinkwrap',
|
||||
priority: '普通',
|
||||
modelPaths: []
|
||||
modelPaths: [],
|
||||
params: { quality: 5, exportFormat: 'step', ignoreSkeletons: true, ignoreQuilts: false, fillHoles: false }
|
||||
})
|
||||
const newModelPath = ref('')
|
||||
|
||||
@ -285,11 +331,24 @@ const openWizard = () => {
|
||||
taskForm.value = {
|
||||
strategy: 'creo_shrinkwrap',
|
||||
priority: '普通',
|
||||
modelPaths: []
|
||||
modelPaths: [],
|
||||
params: { quality: 5, exportFormat: 'step', ignoreSkeletons: true, ignoreQuilts: false, fillHoles: false }
|
||||
}
|
||||
wizardVisible.value = true
|
||||
}
|
||||
|
||||
const onStrategyChange = (val) => {
|
||||
if (val === 'creo_shrinkwrap') {
|
||||
taskForm.value.params = { quality: 5, exportFormat: 'step', ignoreSkeletons: true, ignoreQuilts: false, fillHoles: false }
|
||||
} else if (val === 'revit_shell') {
|
||||
taskForm.value.params = { lod: '粗糙', removeInternal: true }
|
||||
} else if (val.includes('pdms')) {
|
||||
taskForm.value.params = { levelFilter: '', removeAttachments: true }
|
||||
} else {
|
||||
taskForm.value.params = {}
|
||||
}
|
||||
}
|
||||
|
||||
const submitTask = () => {
|
||||
if (taskForm.value.modelPaths.length === 0) {
|
||||
ElMessage.warning('请先添加至少一个模型路径')
|
||||
@ -309,6 +368,7 @@ const submitTask = () => {
|
||||
batchId: `B-${Date.now().toString().slice(-8)}`,
|
||||
strategy: taskForm.value.strategy,
|
||||
priority: taskForm.value.priority,
|
||||
params: { ...taskForm.value.params },
|
||||
progress: 0,
|
||||
status: 'queued',
|
||||
totalCount: taskForm.value.modelPaths.length,
|
||||
@ -576,6 +636,19 @@ const viewDetails = (row) => {
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.strategy-params {
|
||||
background: var(--color-bg-card-secondary, rgba(255,255,255,0.05));
|
||||
border-radius: var(--size-border-radius);
|
||||
padding: var(--spacing-md) var(--spacing-lg);
|
||||
margin-top: var(--spacing-md);
|
||||
border: 1px dashed var(--color-border-primary);
|
||||
}
|
||||
|
||||
.strategy-params .el-divider {
|
||||
margin-top: 0;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* 覆盖 Element UI 为深色主题适配 */
|
||||
:deep(.el-table) {
|
||||
--el-table-bg-color: transparent;
|
||||
|
||||
@ -118,13 +118,112 @@
|
||||
<div class="comparison-view">
|
||||
<div class="comparison-mode-switch">
|
||||
<el-radio-group v-model="comparisonMode" size="small">
|
||||
<el-radio-button label="auto">自动读取 (当前任务记录)</el-radio-button>
|
||||
<el-radio-button label="manual">手动选择比对文件</el-radio-button>
|
||||
<el-radio-button label="live">实时穿透 (当前CAD模型)</el-radio-button>
|
||||
<el-radio-button label="auto">分析报告 (当前记录)</el-radio-button>
|
||||
<el-radio-button label="manual">离线文件 (手动选择)</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<!-- 实时模式内容 -->
|
||||
<div v-if="comparisonMode === 'live'" class="live-comparison">
|
||||
<div class="live-flow-container">
|
||||
<!-- 步骤 1: 捕获基准 -->
|
||||
<div class="flow-step" :class="{ 'step-active': liveStep === 1, 'step-done': liveStep > 1 }">
|
||||
<div class="step-header">
|
||||
<div class="step-num">1</div>
|
||||
<h3>记录当前模型基准状态</h3>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<el-button v-if="liveStep === 1" type="primary" :loading="isCapturingBaseline" @click="captureBaseline" class="live-btn">
|
||||
<i class="fas fa-crosshairs"></i> 一键读取 CAD 当前基准参数
|
||||
</el-button>
|
||||
<div v-else class="captured-data card-panel">
|
||||
<h4><i class="fas fa-cube text-info"></i> 基准原始模型</h4>
|
||||
<ul class="data-list">
|
||||
<li><span class="lbl">模型文件:</span> <span class="val">{{ baselineData.name }}</span></li>
|
||||
<li><span class="lbl">内存占用:</span> <span class="val">{{ baselineData.mem }}</span></li>
|
||||
<li><span class="lbl">面片数量:</span> <span class="val">{{ baselineData.poly }}</span></li>
|
||||
<li><span class="lbl">特征数量:</span> <span class="val">{{ baselineData.features }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤 2: 执行轻量化 -->
|
||||
<div class="flow-step" :class="{ 'step-active': liveStep === 2, 'step-done': liveStep > 2 }">
|
||||
<div class="step-header">
|
||||
<div class="step-num">2</div>
|
||||
<h3>执行轻量化处理</h3>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div v-if="liveStep <= 2" class="wait-msg">
|
||||
<i class="fas fa-info-circle"></i> 记录基准后,请在对应 CAD 插件中直接执行处理,或由系统在此处触发:
|
||||
</div>
|
||||
<el-button v-if="liveStep === 2" type="warning" :loading="isLightweighting" @click="executeLightweight" class="live-btn">
|
||||
<i class="fas fa-magic"></i> 发送轻量化指令并等待
|
||||
</el-button>
|
||||
<div v-if="liveStep > 2" class="success-msg">
|
||||
<i class="fas fa-check-circle text-success"></i> 轻量化操作已完成
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 步骤 3: 捕获轻量化后状态 -->
|
||||
<div class="flow-step" :class="{ 'step-active': liveStep === 3, 'step-done': liveStep > 3 }">
|
||||
<div class="step-header">
|
||||
<div class="step-num">3</div>
|
||||
<h3>捕获结果并生成对比</h3>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<el-button v-if="liveStep === 3" type="success" :loading="isCapturingResult" @click="captureResult" class="live-btn" plain>
|
||||
<i class="fas fa-sync-alt"></i> 读取轻量化后状态并对比
|
||||
</el-button>
|
||||
|
||||
<transition name="el-zoom-in-top">
|
||||
<div v-if="liveStep === 4" class="comparison-results mt-4">
|
||||
<div class="compress-rates">
|
||||
<div class="rate-card">
|
||||
<div class="rate-title">内存占用降低</div>
|
||||
<div class="rate-value text-success">-65.4%</div>
|
||||
</div>
|
||||
<div class="rate-card">
|
||||
<div class="rate-title">面片数量缩减</div>
|
||||
<div class="rate-value text-success">-72.1%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-columns mt-4">
|
||||
<div class="comp-col source-col">
|
||||
<h4><i class="fas fa-cube"></i> 基准状态</h4>
|
||||
<ul class="prop-list">
|
||||
<li><span class="prop-label">内存占用</span> <span class="prop-value">{{ baselineData.mem }}</span></li>
|
||||
<li><span class="prop-label">面片数量</span> <span class="prop-value">{{ baselineData.poly }}</span></li>
|
||||
<li><span class="prop-label">特征总数</span> <span class="prop-value">{{ baselineData.features }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="vs-divider">VS</div>
|
||||
<div class="comp-col target-col">
|
||||
<h4><i class="fas fa-leaf text-success"></i> 轻量化后</h4>
|
||||
<ul class="prop-list">
|
||||
<li><span class="prop-label">内存占用</span> <span class="prop-value text-success">{{ resultData.mem }}</span></li>
|
||||
<li><span class="prop-label">面片数量</span> <span class="prop-value text-success">{{ resultData.poly }}</span></li>
|
||||
<li><span class="prop-label">特征总数</span> <span class="prop-value text-success">{{ resultData.features }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex-center">
|
||||
<el-button plain @click="resetLiveFlow">开启新一轮对比</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自动模式内容 -->
|
||||
<div v-if="comparisonMode === 'auto'" class="auto-comparison">
|
||||
<div v-else-if="comparisonMode === 'auto'" class="auto-comparison">
|
||||
<div v-if="!currentReport.comparisonData" class="empty-data">
|
||||
<i class="fas fa-info-circle"></i> 当前报告未包含比对数据
|
||||
</div>
|
||||
@ -209,7 +308,58 @@ import { ElMessage } from 'element-plus'
|
||||
|
||||
const searchQuery = ref('')
|
||||
const activeTab = ref('overview')
|
||||
const comparisonMode = ref('auto')
|
||||
const comparisonMode = ref('live')
|
||||
|
||||
const liveStep = ref(1) // 1: 捕获基准, 2: 执行轻量化, 3: 捕获结果, 4: 显示报告
|
||||
const isCapturingBaseline = ref(false)
|
||||
const isLightweighting = ref(false)
|
||||
const isCapturingResult = ref(false)
|
||||
const baselineData = ref(null)
|
||||
const resultData = ref(null)
|
||||
|
||||
const captureBaseline = () => {
|
||||
isCapturingBaseline.value = true
|
||||
setTimeout(() => {
|
||||
isCapturingBaseline.value = false
|
||||
baselineData.value = {
|
||||
name: 'Engine_Assembly_V8_Final.asm',
|
||||
mem: '1420 MB',
|
||||
poly: '2,450,120',
|
||||
features: '12,054'
|
||||
}
|
||||
liveStep.value = 2
|
||||
ElMessage.success('基准状态捕获成功')
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const executeLightweight = () => {
|
||||
isLightweighting.value = true
|
||||
setTimeout(() => {
|
||||
isLightweighting.value = false
|
||||
liveStep.value = 3
|
||||
ElMessage.success('轻量化指令执行完成')
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
const captureResult = () => {
|
||||
isCapturingResult.value = true
|
||||
setTimeout(() => {
|
||||
isCapturingResult.value = false
|
||||
resultData.value = {
|
||||
mem: '490 MB',
|
||||
poly: '682,100',
|
||||
features: '342'
|
||||
}
|
||||
liveStep.value = 4
|
||||
ElMessage.success('最新状态捕获及对比报告已生成')
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const resetLiveFlow = () => {
|
||||
liveStep.value = 1
|
||||
baselineData.value = null
|
||||
resultData.value = null
|
||||
}
|
||||
|
||||
// 模拟报告数据
|
||||
const mockReports = [
|
||||
@ -749,4 +899,134 @@ const exportSelectedReport = () => {
|
||||
.manual-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 实时流程逻辑样式 */
|
||||
.live-flow-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.flow-step {
|
||||
background: var(--color-bg-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.flow-step.step-active {
|
||||
opacity: 1;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 10px rgba(var(--color-primary-rgb), 0.1);
|
||||
}
|
||||
|
||||
.flow-step.step-done {
|
||||
opacity: 0.8;
|
||||
border-color: var(--color-success);
|
||||
}
|
||||
|
||||
.step-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.step-num {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: var(--color-white-rgb-05);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.step-active .step-num {
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.step-done .step-num {
|
||||
background: var(--color-success);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.step-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.step-content {
|
||||
padding-left: 44px;
|
||||
}
|
||||
|
||||
.live-btn {
|
||||
border-radius: 8px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.wait-msg {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 14px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.success-msg {
|
||||
color: var(--color-text-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.success-msg i {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.captured-data {
|
||||
padding: 16px;
|
||||
background: rgba(var(--color-primary-rgb), 0.05);
|
||||
border: 1px dashed var(--color-primary);
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.captured-data h4 {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.data-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.data-list li {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.data-list .lbl {
|
||||
color: var(--color-text-secondary);
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.data-list .val {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user