From eecd51db2f0e1094650206fa534dd02f5de58c9c Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期一, 18 五月 2026 10:22:50 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro
---
src/components/AIChatSidebar/index.vue | 763 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 745 insertions(+), 18 deletions(-)
diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
index a2a365a..e3a9e3c 100644
--- a/src/components/AIChatSidebar/index.vue
+++ b/src/components/AIChatSidebar/index.vue
@@ -242,7 +242,123 @@
</el-table>
</div>
- <!-- 鎵撳瓧涓姩鐢� -->
+ <div v-if="message.manufacturingData" class="manufacturing-card">
+ <div class="manufacturing-card__title">{{ getManufacturingTypeLabel(message.type) }}</div>
+
+ <div
+ v-if="message.manufacturingData.summaryEntries?.length || message.manufacturingData.coreMetrics?.length"
+ class="manufacturing-summary-grid"
+ >
+ <div
+ v-for="(entry, entryIndex) in message.manufacturingData.summaryEntries"
+ :key="`summary-${entry.key}-${entryIndex}`"
+ class="manufacturing-summary-item"
+ >
+ <span class="manufacturing-summary-label">{{ entry.label }}</span>
+ <strong class="manufacturing-summary-value">{{ entry.value }}</strong>
+ </div>
+ <div
+ v-for="(metric, metricIndex) in message.manufacturingData.coreMetrics"
+ :key="`core-${metric.key}-${metricIndex}`"
+ class="manufacturing-summary-item manufacturing-summary-item--core"
+ >
+ <span class="manufacturing-summary-label">{{ metric.label }}</span>
+ <strong class="manufacturing-summary-value">{{ metric.value }}</strong>
+ </div>
+ </div>
+
+ <div v-if="message.manufacturingData.warningItems?.length" class="manufacturing-warning-list">
+ <div
+ v-for="(warning, warningIndex) in message.manufacturingData.warningItems"
+ :key="`warning-${warning.title || warningIndex}`"
+ class="manufacturing-warning-item"
+ >
+ <div class="manufacturing-warning-item__head">
+ <el-tag size="small" :type="getManufacturingWarningLevelType(warning.level)">
+ {{ getManufacturingWarningLevelLabel(warning.level) }}
+ </el-tag>
+ <strong>{{ warning.title || `棰勮 ${warningIndex + 1}` }}</strong>
+ <span v-if="warning.count !== '' && warning.count !== null && warning.count !== undefined" class="manufacturing-warning-count">
+ {{ warning.count }}
+ </span>
+ </div>
+ <p v-if="warning.detail" class="manufacturing-warning-detail">{{ warning.detail }}</p>
+ </div>
+ </div>
+
+ <div
+ v-if="message.manufacturingData.listItems?.length && message.manufacturingData.columns?.length"
+ class="table-wrapper manufacturing-table-wrapper"
+ >
+ <el-table :data="message.manufacturingData.listItems" border stripe size="small" style="width: 100%">
+ <el-table-column
+ v-for="col in message.manufacturingData.columns"
+ :key="col"
+ :label="getStructuredFieldLabel(col)"
+ min-width="140"
+ show-overflow-tooltip
+ >
+ <template #default="{ row }">
+ {{ formatStructuredValue(row[col]) }}
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+
+ <div v-if="message.manufacturingData.actionCards?.length" class="manufacturing-action-list">
+ <div
+ v-for="(card, cardIndex) in message.manufacturingData.actionCards"
+ :key="card.runtimeKey || `${card.code}-${card.targetApi}-${cardIndex}`"
+ class="manufacturing-action-card"
+ >
+ <div class="manufacturing-action-card__head">
+ <strong>{{ card.name || `鍔ㄤ綔 ${cardIndex + 1}` }}</strong>
+ <el-tag size="small" type="info">{{ getNormalizedRequestMethod(card.method) }}</el-tag>
+ </div>
+ <div class="manufacturing-action-card__meta">
+ <span>{{ card.code || '--' }}</span>
+ <span>{{ card.targetApi || '--' }}</span>
+ </div>
+ <p v-if="card.description" class="manufacturing-action-card__desc">{{ card.description }}</p>
+ <div v-if="card.requiredFields?.length" class="manufacturing-required-fields">
+ <span>蹇呭~瀛楁</span>
+ <el-tag
+ v-for="field in card.requiredFields"
+ :key="field"
+ size="small"
+ type="warning"
+ >
+ {{ getStructuredPathLabel(field) }}
+ </el-tag>
+ </div>
+ <el-input
+ v-model="card.payloadText"
+ type="textarea"
+ :rows="6"
+ resize="vertical"
+ :disabled="card.executing"
+ placeholder="璇疯緭鍏� JSON 璇锋眰鍙傛暟"
+ />
+ <div class="manufacturing-action-footer">
+ <span
+ v-if="card.executeResult"
+ :class="['manufacturing-action-result', card.executeError ? 'error' : 'success']"
+ >
+ {{ card.executeResult }}
+ </span>
+ <el-button
+ type="primary"
+ size="small"
+ :loading="card.executing"
+ @click="executeManufacturingAction(message, card, cardIndex)"
+ >
+ 纭骞舵墽琛�
+ </el-button>
+ </div>
+ </div>
+ </div>
+ </div>
+
<div v-if="message.purchaseAnalysisData" class="purchase-confirm-card">
<div class="purchase-confirm-header">
<span>{{ businessTypeLabelMap[message.purchaseAnalysisData.businessType] || message.purchaseAnalysisData.businessType || '閲囪喘涓氬姟' }}</span>
@@ -523,7 +639,7 @@
import request from '@/utils/request'
import * as echarts from 'echarts'
import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, Promotion, RefreshRight } from '@element-plus/icons-vue'
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
import { builtInAssistants, generalAssistant } from './assistants'
import todoAssistantAvatar from '@/assets/AI/寰呭姙鍔╂墜.png'
import salesAssistantAvatar from '@/assets/AI/閿�鍞姪鎵�.png'
@@ -633,6 +749,75 @@
payment_registration: '浠樻鐧昏',
purchase_return_order: '閲囪喘閫�璐у崟',
unknown: '鏈煡閲囪喘涓氬姟'
+}
+const manufacturingStructuredTypeSet = new Set([
+ 'manufacturing_site_snapshot',
+ 'manufacturing_plan_list',
+ 'manufacturing_workorder_list',
+ 'manufacturing_device_list',
+ 'manufacturing_device_repair_list',
+ 'manufacturing_quality_list',
+ 'manufacturing_material_list',
+ 'manufacturing_exception_list',
+ 'manufacturing_warning',
+ 'manufacturing_analysis',
+ 'manufacturing_action_plan'
+])
+const manufacturingListTypeSet = new Set([
+ 'manufacturing_plan_list',
+ 'manufacturing_workorder_list',
+ 'manufacturing_device_list',
+ 'manufacturing_device_repair_list',
+ 'manufacturing_quality_list',
+ 'manufacturing_material_list',
+ 'manufacturing_exception_list'
+])
+const manufacturingTypeLabelMap = {
+ manufacturing_site_snapshot: '鐢熶骇鐜板満姒傝',
+ manufacturing_plan_list: '璁″垝鏌ヨ',
+ manufacturing_workorder_list: '宸ュ崟鏌ヨ',
+ manufacturing_device_list: '璁惧鏌ヨ',
+ manufacturing_device_repair_list: '璁惧缁翠慨璁板綍鏌ヨ',
+ manufacturing_quality_list: '璐ㄩ噺鏌ヨ',
+ manufacturing_material_list: '鐗╂枡鏌ヨ',
+ manufacturing_exception_list: '寮傚父鏌ヨ',
+ manufacturing_warning: '棰勮鐪嬫澘',
+ manufacturing_analysis: '缁忚惀鍒嗘瀽',
+ manufacturing_action_plan: '鍔炵悊寤鸿'
+}
+const structuredFieldLabelMap = {
+ workOrderNo: '宸ュ崟鍙�',
+ planEndTime: '璁″垝缁撴潫鏃堕棿',
+ planStartTime: '璁″垝寮�濮嬫椂闂�',
+ timeRange: '鏃堕棿鑼冨洿',
+ startDate: '寮�濮嬫棩鏈�',
+ endDate: '缁撴潫鏃ユ湡',
+ warningCount: '棰勮鏁伴噺',
+ overduePlanCount: '閫炬湡璁″垝鏁�',
+ overdueWorkOrderCount: '閫炬湡宸ュ崟鏁�',
+ actionCount: '寤鸿鍔ㄤ綔鏁�',
+ qualityOpenCount: '璐ㄩ噺寰呭鐞嗘暟',
+ lowStockCount: '浣庡簱瀛樻暟',
+ exceptionCount: '寮傚父鏁�',
+ userId: '鐢ㄦ埛ID',
+ tenantId: '绉熸埛ID',
+ status: '鐘舵��',
+ deviceName: '璁惧鍚嶇О',
+ deviceModel: '璁惧鍨嬪彿',
+ pendingRepairCount: '寰呯淮淇暟',
+ repairTime: '缁翠慨鏃堕棿',
+ repairName: '鎶ヤ慨浜�',
+ maintenanceName: '缁翠慨浜哄憳',
+ level: '棰勮绛夌骇',
+ title: '鏍囬',
+ count: '鏁伴噺',
+ detail: '璇︽儏',
+ remark: '澶囨敞',
+ createTime: '鍒涘缓鏃堕棿',
+ updateTime: '鏇存柊鏃堕棿',
+ exceptionType: '寮傚父绫诲瀷',
+ materialName: '鐗╂枡鍚嶇О',
+ stockQty: '搴撳瓨閲�'
}
const purchasePayloadFieldLabelMap = {
purchaseLedgers: '閲囪喘鍙拌处',
@@ -785,6 +970,366 @@
inventoryWarningQuantity: 'inventoryWarningQuantity',
isInspected: 'isInspected',
isChecked: 'isInspected'
+}
+const isPlainObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
+
+const stringifyStructuredPayload = (value, spaces = 2) => {
+ if (typeof value === 'string') return value
+ try {
+ return JSON.stringify(value ?? {}, null, spaces)
+ } catch (err) {
+ return '{}'
+ }
+}
+
+const structuredFieldTokenLabelMap = {
+ time: '鏃堕棿',
+ range: '鑼冨洿',
+ start: '寮�濮�',
+ end: '缁撴潫',
+ date: '鏃ユ湡',
+ warning: '棰勮',
+ overdue: '閫炬湡',
+ plan: '璁″垝',
+ work: '宸�',
+ order: '鍗�',
+ workorder: '宸ュ崟',
+ count: '鏁伴噺',
+ quality: '璐ㄩ噺',
+ low: '浣�',
+ stock: '搴撳瓨',
+ exception: '寮傚父',
+ action: '鍔ㄤ綔',
+ user: '鐢ㄦ埛',
+ tenant: '绉熸埛',
+ id: 'ID',
+ no: '缂栧彿',
+ number: '缂栧彿',
+ code: '缂栫爜',
+ name: '鍚嶇О',
+ status: '鐘舵��',
+ level: '绛夌骇',
+ title: '鏍囬',
+ detail: '璇︽儏',
+ total: '鎬绘暟',
+ rate: '姣旂巼',
+ type: '绫诲瀷',
+ pending: '寰�',
+ repair: '缁翠慨',
+ device: '璁惧',
+ material: '鐗╂枡'
+}
+
+const convertStructuredFieldKeyToChinese = (fieldKey = '') => {
+ const key = String(fieldKey || '').trim()
+ if (!key) return '-'
+ if (structuredFieldLabelMap[key]) return structuredFieldLabelMap[key]
+ if (/[\u4e00-\u9fa5]/.test(key)) return key
+
+ const rawTokens = key
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
+ .replace(/[_-]+/g, ' ')
+ .trim()
+ .split(/\s+/)
+ .filter(Boolean)
+ .map(token => token.toLowerCase())
+
+ if (!rawTokens.length) return '瀛楁'
+
+ const mappedTokens = rawTokens
+ .map(token => structuredFieldTokenLabelMap[token] || '')
+ .filter(Boolean)
+
+ if (mappedTokens.length) {
+ return mappedTokens.join('')
+ }
+
+ return '瀛楁'
+}
+
+const getStructuredFieldLabel = (fieldKey = '') => {
+ return convertStructuredFieldKeyToChinese(fieldKey)
+}
+
+const getStructuredPathLabel = (fieldPath = '') => {
+ const path = String(fieldPath || '').trim()
+ if (!path) return '-'
+
+ const segments = path
+ .replace(/\[(\d+)]/g, '.$1')
+ .split('.')
+ .filter(Boolean)
+
+ if (!segments.length) return getStructuredFieldLabel(path)
+
+ return segments.map((segment) => {
+ if (/^\d+$/.test(segment)) {
+ return `绗�${Number(segment) + 1}椤筦
+ }
+ return getStructuredFieldLabel(segment)
+ }).join(' / ')
+}
+
+const formatStructuredValue = (value) => {
+ if (value === null || value === undefined || value === '') return '-'
+ if (Array.isArray(value)) {
+ const preview = value.slice(0, 3).map(item => formatStructuredValue(item)).join('銆�')
+ return value.length > 3 ? `${preview} 绛�${value.length}椤筦 : preview
+ }
+ if (isPlainObject(value)) return stringifyStructuredPayload(value, 0)
+ return String(value)
+}
+
+const normalizeManufacturingSummaryEntries = (summary) => {
+ if (!isPlainObject(summary)) return []
+ return Object.entries(summary)
+ .filter(([, value]) => value !== undefined && value !== null && `${value}`.trim() !== '')
+ .map(([key, value]) => ({
+ key,
+ label: getStructuredFieldLabel(key),
+ value: formatStructuredValue(value)
+ }))
+}
+
+const normalizeManufacturingCoreMetrics = (coreMetrics) => {
+ if (Array.isArray(coreMetrics)) {
+ return coreMetrics.map((item, index) => {
+ if (isPlainObject(item)) {
+ const label = item.label || item.name || item.key || `鎸囨爣${index + 1}`
+ const metricValue = item.value ?? item.metricValue ?? item.data ?? '-'
+ const unit = item.unit ? ` ${item.unit}` : ''
+ return {
+ key: String(item.key || item.name || index),
+ label,
+ value: `${formatStructuredValue(metricValue)}${unit}`.trim()
+ }
+ }
+ return {
+ key: String(index),
+ label: `鎸囨爣${index + 1}`,
+ value: formatStructuredValue(item)
+ }
+ })
+ }
+
+ if (isPlainObject(coreMetrics)) {
+ return Object.entries(coreMetrics).map(([key, value]) => ({
+ key,
+ label: getStructuredFieldLabel(key),
+ value: formatStructuredValue(value)
+ }))
+ }
+
+ return []
+}
+
+const normalizeManufacturingWarningItems = (items = []) => {
+ if (!Array.isArray(items)) return []
+ return items
+ .filter(item => isPlainObject(item))
+ .map(item => ({
+ level: String(item.level || '').toLowerCase(),
+ title: item.title || '',
+ count: item.count ?? '',
+ detail: item.detail ?? ''
+ }))
+}
+
+const inferManufacturingColumns = (items = []) => {
+ if (!Array.isArray(items) || !items.length) return []
+ const fieldSet = new Set()
+ items.forEach((item) => {
+ if (!isPlainObject(item)) return
+ Object.keys(item).forEach((key) => fieldSet.add(key))
+ })
+ return Array.from(fieldSet)
+}
+
+const getManufacturingActionCardRuntimeKey = (card = {}, index = 0) => {
+ const code = String(card?.code || '').trim()
+ const api = String(card?.targetApi || '').trim()
+ const name = String(card?.name || '').trim()
+ return `${code}::${api}::${name}::${index}`
+}
+
+const normalizeManufacturingActionCards = (actionCards = [], previousCards = []) => {
+ const previousMap = new Map()
+ if (Array.isArray(previousCards)) {
+ previousCards.forEach((card, index) => {
+ previousMap.set(getManufacturingActionCardRuntimeKey(card, index), card)
+ })
+ }
+
+ return (Array.isArray(actionCards) ? actionCards : [])
+ .filter(card => isPlainObject(card))
+ .map((card, index) => {
+ const runtimeKey = getManufacturingActionCardRuntimeKey(card, index)
+ const previousCard = previousMap.get(runtimeKey)
+ const fallbackPayloadText = stringifyStructuredPayload(card.examplePayload, 2)
+ return {
+ ...card,
+ runtimeKey,
+ payloadText: previousCard?.payloadText ?? fallbackPayloadText,
+ executing: Boolean(previousCard?.executing),
+ executed: Boolean(previousCard?.executed),
+ executeResult: previousCard?.executeResult || '',
+ executeError: Boolean(previousCard?.executeError)
+ }
+ })
+}
+
+const buildManufacturingStructuredData = (parsedData, previousData = null) => {
+ const type = String(parsedData?.type || '')
+ if (!manufacturingStructuredTypeSet.has(type)) return null
+
+ const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {}
+ const items = Array.isArray(rawData.items) ? rawData.items.filter(item => isPlainObject(item)) : []
+ const warningItems = type === 'manufacturing_warning' ? normalizeManufacturingWarningItems(items) : []
+ const listItems = manufacturingListTypeSet.has(type) ? items : []
+ const actionCards = type === 'manufacturing_action_plan'
+ ? normalizeManufacturingActionCards(rawData.actionCards, previousData?.actionCards)
+ : []
+
+ return {
+ type,
+ summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary),
+ coreMetrics: normalizeManufacturingCoreMetrics(rawData.coreMetrics),
+ listItems,
+ columns: inferManufacturingColumns(listItems),
+ warningItems,
+ actionCards
+ }
+}
+
+const getManufacturingTypeLabel = (type = '') => manufacturingTypeLabelMap[String(type || '')] || '鍒堕�犵粨鏋�'
+
+const getManufacturingWarningLevelType = (level = '') => {
+ const normalizedLevel = String(level || '').toLowerCase()
+ if (normalizedLevel === 'high') return 'danger'
+ if (normalizedLevel === 'medium') return 'warning'
+ return 'info'
+}
+
+const getManufacturingWarningLevelLabel = (level = '') => {
+ const normalizedLevel = String(level || '').toLowerCase()
+ if (normalizedLevel === 'high') return '楂�'
+ if (normalizedLevel === 'medium') return '涓�'
+ return normalizedLevel ? normalizedLevel.toUpperCase() : '涓�鑸�'
+}
+
+const normalizeRequestMethod = (method = 'POST') => {
+ const normalized = String(method || 'POST').trim().toUpperCase()
+ if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) return normalized
+ return 'POST'
+}
+
+const getNormalizedRequestMethod = (method) => normalizeRequestMethod(method)
+
+const getPayloadValueByPath = (payload, fieldPath = '') => {
+ const normalizedPath = String(fieldPath || '').trim()
+ if (!normalizedPath || !isPlainObject(payload)) return undefined
+
+ const pathSegments = normalizedPath
+ .replace(/\[(\d+)]/g, '.$1')
+ .split('.')
+ .filter(Boolean)
+
+ return pathSegments.reduce((current, segment) => {
+ if (current === null || current === undefined) return undefined
+ if (!['object', 'function'].includes(typeof current)) return undefined
+ return current[segment]
+ }, payload)
+}
+
+const getMissingRequiredFields = (requiredFields = [], payload = {}) => {
+ if (!Array.isArray(requiredFields) || !requiredFields.length) return []
+ return requiredFields.filter((fieldPath) => {
+ const value = getPayloadValueByPath(payload, fieldPath)
+ return !hasMeaningfulPayloadValue(value)
+ })
+}
+
+const parseManufacturingActionPayload = (payloadText = '') => {
+ const text = String(payloadText ?? '').trim()
+ if (!text) return {}
+ return JSON.parse(text)
+}
+
+const executeManufacturingAction = async (message, actionCard, cardIndex = 0) => {
+ if (!message?.manufacturingData || !actionCard || actionCard.executing) return
+
+ const actionName = actionCard.name || `鍔ㄤ綔 ${cardIndex + 1}`
+ const targetApi = String(actionCard.targetApi || '').trim()
+ if (!targetApi) {
+ actionCard.executeError = true
+ actionCard.executeResult = '缂哄皯 targetApi锛屾棤娉曟墽琛屽姩浣�'
+ return
+ }
+
+ let payload = {}
+ try {
+ payload = parseManufacturingActionPayload(actionCard.payloadText)
+ } catch (err) {
+ actionCard.executeError = true
+ actionCard.executeResult = '璇锋眰鍙傛暟涓嶆槸鍚堟硶 JSON锛岃妫�鏌ュ悗閲嶈瘯'
+ return
+ }
+
+ const requiredFields = Array.isArray(actionCard.requiredFields) ? actionCard.requiredFields : []
+ if (requiredFields.length && !isPlainObject(payload)) {
+ actionCard.executeError = true
+ actionCard.executeResult = '蹇呭~瀛楁鏍¢獙澶辫触锛氳姹傚弬鏁板繀椤绘槸 JSON 瀵硅薄'
+ return
+ }
+
+ const missingFields = getMissingRequiredFields(requiredFields, payload)
+ if (missingFields.length) {
+ actionCard.executeError = true
+ const missingFieldLabels = missingFields.map(field => getStructuredPathLabel(field))
+ actionCard.executeResult = `缂哄皯蹇呭~瀛楁锛�${missingFieldLabels.join('銆�')}`
+ return
+ }
+
+ try {
+ await ElMessageBox.confirm(`纭鎵ц銆�${actionName}銆嶅悧锛焋, '鎵ц纭', {
+ confirmButtonText: '纭鎵ц',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ })
+ } catch (err) {
+ return
+ }
+
+ actionCard.executing = true
+ actionCard.executeError = false
+ actionCard.executeResult = ''
+
+ const method = normalizeRequestMethod(actionCard.method)
+ const requestConfig = {
+ url: targetApi,
+ method: method.toLowerCase()
+ }
+
+ if (method === 'GET') {
+ requestConfig.params = payload
+ } else {
+ requestConfig.data = payload
+ }
+
+ try {
+ const res = await request(requestConfig)
+ const successMsg = res?.msg || `${actionName}鎵ц鎴愬姛`
+ actionCard.executed = true
+ actionCard.executeError = false
+ actionCard.executeResult = successMsg
+ ElMessage.success(successMsg)
+ } catch (err) {
+ actionCard.executed = false
+ actionCard.executeError = true
+ actionCard.executeResult = err?.message || `${actionName}鎵ц澶辫触锛岃绋嶅悗閲嶈瘯`
+ } finally {
+ actionCard.executing = false
+ }
}
// 鍘嗗彶浼氳瘽鐩稿叧
@@ -1034,6 +1579,8 @@
tableData: null,
payloadTreeData: null,
payloadHiddenData: null,
+ purchaseAnalysisData: null,
+ manufacturingData: null,
localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : []
}
@@ -1273,15 +1820,25 @@
const applyStructuredMessageData = (messageObj, parsedData, msgIndex, shouldRenderCharts = true) => {
if (!messageObj || !parsedData?.success) return
+ const previousManufacturingData = messageObj.manufacturingData
messageObj.type = parsedData.type || ''
+ messageObj.tableData = null
+ messageObj.purchaseAnalysisData = null
+ messageObj.manufacturingData = null
if (messageObj.type === 'todo_list' && parsedData.data) {
messageObj.tableData = parsedData.data
}
+ const manufacturingData = buildManufacturingStructuredData(parsedData, previousManufacturingData)
+ if (manufacturingData) {
+ messageObj.manufacturingData = manufacturingData
+ }
+
if (parsedData.action === 'confirm_required' && parsedData.businessType) {
messageObj.type = 'purchase_analysis_confirm'
messageObj.purchaseAnalysisData = parsedData
+ messageObj.manufacturingData = null
if (!Array.isArray(messageObj.payloadTreeData) || !messageObj.payloadTreeData.length) {
initializePurchasePayloadTree(messageObj, parsedData.payload || {})
}
@@ -1321,6 +1878,19 @@
}
return null
+}
+
+const getStructuredFallbackText = (parsedData) => {
+ if (!parsedData) return '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
+ if (parsedData.type === 'todo_list') return '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁銆�'
+ if (manufacturingStructuredTypeSet.has(parsedData.type)) {
+ if (parsedData.type === 'manufacturing_action_plan') return '宸蹭负鎮ㄧ敓鎴愬姙鐞嗗缓璁紝璇风‘璁ゅ姩浣滃悗鎵ц銆�'
+ if (parsedData.type === 'manufacturing_warning') return '宸蹭负鎮ㄧ敓鎴愬埗閫犻璀︾湅鏉裤��'
+ if (parsedData.type === 'manufacturing_analysis') return '宸蹭负鎮ㄧ敓鎴愬埗閫犲垎鏋愮粨鏋溿��'
+ return '宸茶繑鍥炲埗閫犳煡璇㈢粨鏋溿��'
+ }
+ if (parsedData.charts && Object.keys(parsedData.charts).length > 0) return '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛ㄣ��'
+ return '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
}
const buildPurchaseMaterialRankCharts = (parsedData) => {
@@ -2446,7 +3016,9 @@
type: '',
tableData: null,
payloadTreeData: null,
- payloadHiddenData: null
+ payloadHiddenData: null,
+ purchaseAnalysisData: null,
+ manufacturingData: null
})
outputState.value[botMsgIndex] = {
@@ -2569,7 +3141,9 @@
type: '',
tableData: null,
payloadTreeData: null,
- payloadHiddenData: null
+ payloadHiddenData: null,
+ purchaseAnalysisData: null,
+ manufacturingData: null
}
messages.value.push(botMsg)
@@ -2735,13 +3309,7 @@
}
if (!display) {
- if (parsed.type === 'todo_list') {
- display = '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁銆�'
- } else if (parsed.charts && Object.keys(parsed.charts).length > 0) {
- display = '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛ㄣ��'
- } else {
- display = '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
- }
+ display = getStructuredFallbackText(parsed)
}
} else if (startIdx !== -1) {
const lastBraceIdx = output.lastIndexOf('}')
@@ -2763,13 +3331,7 @@
}
if (!display) {
- if (parsed.type === 'todo_list') {
- display = '宸蹭负鎮ㄦ暣鐞嗗ソ鐩稿叧鏁版嵁锛�'
- } else if (parsed.charts && Object.keys(parsed.charts).length > 0) {
- display = '宸蹭负鎮ㄧ敓鎴愬垎鏋愬浘琛細'
- } else {
- display = '姝e湪涓烘偍灞曠ず鍒嗘瀽缁撴灉...'
- }
+ display = getStructuredFallbackText(parsed)
}
} catch (e) {
// 瑙f瀽澶辫触锛岃鏄� JSON 杩樺湪浼犺緭涓垨鏍煎紡涓嶆纭�
@@ -3792,6 +4354,171 @@
}
}
+.manufacturing-card {
+ margin-top: 12px;
+ width: 100%;
+ background: #fff;
+ border: 1px solid rgba(0, 85, 212, 0.12);
+ border-radius: 12px;
+ box-shadow: $shadow-card;
+ padding: 14px;
+}
+
+.manufacturing-card__title {
+ font-size: 14px;
+ font-weight: 700;
+ color: $deep-blue;
+ margin-bottom: 10px;
+}
+
+.manufacturing-summary-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+ gap: 8px;
+ margin-bottom: 12px;
+}
+
+.manufacturing-summary-item {
+ border-radius: 10px;
+ padding: 10px 12px;
+ border: 1px solid rgba(0, 85, 212, 0.08);
+ background: linear-gradient(180deg, #f8fbff, #f1f7ff);
+ min-height: 66px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: 6px;
+}
+
+.manufacturing-summary-item--core {
+ border-color: rgba(30, 91, 255, 0.24);
+}
+
+.manufacturing-summary-label {
+ font-size: 12px;
+ color: #4b5563;
+}
+
+.manufacturing-summary-value {
+ font-size: 15px;
+ color: #1f2937;
+ line-height: 1.4;
+ word-break: break-all;
+}
+
+.manufacturing-warning-list {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ margin-bottom: 12px;
+}
+
+.manufacturing-warning-item {
+ border-radius: 10px;
+ border: 1px solid rgba(245, 158, 11, 0.22);
+ background: linear-gradient(135deg, rgba(255, 247, 237, 0.9), rgba(255, 255, 255, 0.98));
+ padding: 10px 12px;
+}
+
+.manufacturing-warning-item__head {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ color: #92400e;
+ font-size: 13px;
+}
+
+.manufacturing-warning-count {
+ margin-left: auto;
+ font-weight: 700;
+ color: #c2410c;
+}
+
+.manufacturing-warning-detail {
+ margin: 8px 0 0;
+ font-size: 12px;
+ line-height: 1.6;
+ color: #7c2d12;
+ word-break: break-all;
+}
+
+.manufacturing-table-wrapper {
+ margin-top: 10px;
+}
+
+.manufacturing-action-list {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 12px;
+}
+
+.manufacturing-action-card {
+ border: 1px solid rgba(0, 85, 212, 0.1);
+ border-radius: 10px;
+ padding: 10px 12px;
+ background: #f8fbff;
+}
+
+.manufacturing-action-card__head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ font-size: 13px;
+ color: #1f2937;
+ margin-bottom: 8px;
+}
+
+.manufacturing-action-card__meta {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ margin-bottom: 8px;
+ font-size: 12px;
+ color: #64748b;
+ word-break: break-all;
+}
+
+.manufacturing-action-card__desc {
+ margin: 0 0 8px;
+ font-size: 12px;
+ line-height: 1.6;
+ color: #475467;
+}
+
+.manufacturing-required-fields {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 6px;
+ margin-bottom: 8px;
+ font-size: 12px;
+ color: #7c2d12;
+}
+
+.manufacturing-action-footer {
+ margin-top: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 12px;
+}
+
+.manufacturing-action-result {
+ flex: 1;
+ font-size: 12px;
+ line-height: 1.5;
+
+ &.success {
+ color: #1f9d55;
+ }
+
+ &.error {
+ color: #d93025;
+ }
+}
+
.purchase-confirm-card {
margin-top: 12px;
width: 100%;
--
Gitblit v1.9.3