| | |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.financeData" class="sales-structured-card"> |
| | | <div class="sales-structured-card__title">{{ getFinancialTypeLabel(message.type) }}</div> |
| | | |
| | | <div v-if="message.financeData.summaryEntries?.length" class="sales-summary-grid"> |
| | | <div |
| | | v-for="(entry, entryIndex) in message.financeData.summaryEntries" |
| | | :key="`finance-summary-${entry.key}-${entryIndex}`" |
| | | class="sales-summary-item" |
| | | > |
| | | <span class="sales-summary-label">{{ entry.label }}</span> |
| | | <strong class="sales-summary-value">{{ entry.value }}</strong> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.financeData.headline" class="finance-headline"> |
| | | {{ message.financeData.headline }} |
| | | </div> |
| | | |
| | | <div v-if="message.financeData.conclusions?.length" class="finance-text-section"> |
| | | <div class="sales-section-title">æ ¸å¿ç»è®º</div> |
| | | <ul> |
| | | <li v-for="(item, idx) in message.financeData.conclusions" :key="`finance-conclusion-${idx}`"> |
| | | {{ item }} |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div v-if="message.financeData.riskSuggestions?.length" class="finance-text-section"> |
| | | <div class="sales-section-title">é£é©å»ºè®®</div> |
| | | <ul> |
| | | <li v-for="(item, idx) in message.financeData.riskSuggestions" :key="`finance-risk-${idx}`"> |
| | | {{ item }} |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div |
| | | v-for="section in message.financeData.sections" |
| | | :key="`finance-section-${section.key}`" |
| | | class="table-wrapper manufacturing-table-wrapper" |
| | | > |
| | | <div class="sales-section-title">{{ section.title }}</div> |
| | | <el-table :data="section.items" border stripe size="small" style="width: 100%"> |
| | | <el-table-column |
| | | v-for="col in section.columns" |
| | | :key="`finance-${section.key}-${col}`" |
| | | :label="getStructuredFieldLabel(col)" |
| | | min-width="120" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatStructuredValue(row[col]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="message.purchaseIntentData?.quickPrompts?.length" class="purchase-intent-quick-prompt-wrap"> |
| | | <div class="purchase-intent-quick-prompt-title">è¯è¯ä»¥ä¸æé®</div> |
| | | <div class="quick-prompt-list purchase-intent-quick-prompt-list"> |
| | |
| | | purchase_material_rank: 'éè´ç©æé颿è¡', |
| | | purchase_pending_payment_list: 'å¾
仿¬¾éè´å' |
| | | } |
| | | const financialStructuredTypeSet = new Set([ |
| | | 'financial_cost_accounting', |
| | | 'financial_order_profit_analysis', |
| | | 'financial_inventory_capital_analysis', |
| | | 'financial_cashflow_forecast', |
| | | 'financial_business_anomaly_warning', |
| | | 'financial_business_cockpit', |
| | | 'financial_operation_report', |
| | | 'financial_rag_knowledge' |
| | | ]) |
| | | const financialTypeLabelMap = { |
| | | financial_cost_accounting: 'ææ¬æ ¸ç®', |
| | | financial_order_profit_analysis: '订å婿¶¦åæ', |
| | | financial_inventory_capital_analysis: 'åºåèµéåæ', |
| | | financial_cashflow_forecast: 'ç°éæµé¢æµ', |
| | | financial_business_anomaly_warning: 'ç»è¥å¼å¸¸é¢è¦', |
| | | financial_business_cockpit: 'ç»è¥é©¾é©¶è±', |
| | | financial_operation_report: 'ç»è¥æ¥å', |
| | | financial_rag_knowledge: 'è´¢å¡ç¥è¯æ£ç´¢' |
| | | } |
| | | const manufacturingStructuredTypeSet = new Set([ |
| | | 'manufacturing_site_snapshot', |
| | | 'manufacturing_plan_list', |
| | |
| | | collectionStrategy: '忬¾çç¥', |
| | | quotationStrategy: 'æ¥ä»·çç¥', |
| | | nextAction: 'ä¸ä¸æ¥å¨ä½', |
| | | salesContractNo: 'éå®ååå·', |
| | | revenue: 'æ¶å
¥', |
| | | materialCost: 'ææææ¬', |
| | | laborCost: 'äººå·¥ææ¬', |
| | | depreciationCost: 'ææ§ææ¬', |
| | | scrapCost: 'æ¥åºææ¬', |
| | | totalCost: 'æ»ææ¬', |
| | | profit: '婿¶¦', |
| | | profitRate: '婿¶¦ç', |
| | | reasons: 'åå ', |
| | | suggestion: '建议', |
| | | productName: '产ååç§°', |
| | | model: 'åå·', |
| | | quantity: 'æ°é', |
| | | inventoryValue: 'åºåèµé', |
| | | stagnantDays: '忻天æ°', |
| | | overstock: 'æ¯å¦è¶
å¨', |
| | | month: 'æä»½', |
| | | income: 'æ¶å
¥', |
| | | expense: 'æ¯åº', |
| | | netFlow: 'åç°éæµ', |
| | | message: 'é¢è¦ä¿¡æ¯', |
| | | headline: 'æ¥åæ é¢', |
| | | conclusions: 'æ ¸å¿ç»è®º', |
| | | riskSuggestions: 'é£é©å»ºè®®', |
| | | orderProfitTop: '婿¶¦Top', |
| | | contractAmountTotal: 'ååæ»é¢', |
| | | receivedAmountTotal: '已忬¾éé¢', |
| | | pendingAmountTotal: 'å¾
忬¾æ»é¢', |
| | |
| | | |
| | | const getPurchaseTypeLabel = (type = '') => purchaseTypeLabelMap[String(type || '')] || 'éè´æ¥è¯¢ç»æ' |
| | | |
| | | const financialDataSectionConfig = [ |
| | | { key: 'orders', title: '订åæç»' }, |
| | | { key: 'items', title: 'æç»å表' }, |
| | | { key: 'actualMonthly', title: 'åå²ç°éæµ' }, |
| | | { key: 'forecastMonthly', title: '颿µç°éæµ' }, |
| | | { key: 'receivableRiskTop', title: 'åºæ¶é£é©Top' }, |
| | | { key: 'payablePressureTop', title: 'åºä»ååTop' }, |
| | | { key: 'orderProfitTop', title: '婿¶¦Top' } |
| | | ] |
| | | |
| | | const buildFinancialStructuredSections = (rawData = {}) => { |
| | | const sections = [] |
| | | financialDataSectionConfig.forEach((section) => { |
| | | const items = normalizeSalesListItems(rawData?.[section.key]) |
| | | if (!items.length) return |
| | | sections.push({ |
| | | key: section.key, |
| | | title: section.title, |
| | | items, |
| | | columns: inferSalesColumns(items) |
| | | }) |
| | | }) |
| | | return sections |
| | | } |
| | | |
| | | const buildFinancialStructuredData = (parsedData) => { |
| | | const type = String(parsedData?.type || '') |
| | | if (!financialStructuredTypeSet.has(type) || parsedData?.success !== true) return null |
| | | |
| | | const rawData = isPlainObject(parsedData?.data) ? parsedData.data : {} |
| | | const headline = String(rawData?.headline || '').trim() |
| | | |
| | | return { |
| | | type, |
| | | summaryEntries: normalizeManufacturingSummaryEntries(parsedData?.summary), |
| | | headline, |
| | | conclusions: toStructuredStringArray(rawData?.conclusions), |
| | | riskSuggestions: toStructuredStringArray(rawData?.riskSuggestions), |
| | | sections: buildFinancialStructuredSections(rawData) |
| | | } |
| | | } |
| | | |
| | | const getFinancialTypeLabel = (type = '') => financialTypeLabelMap[String(type || '')] || 'è´¢å¡æ¥è¯¢ç»æ' |
| | | |
| | | const isSalesFocusType = (type = '') => salesFocusTypeSet.has(String(type || '')) |
| | | |
| | | const getSalesLevelTagType = (level = '') => { |
| | |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null, |
| | | financeData: null, |
| | | localUploadFiles: isUser ? mapHistoryFilePathsToSnapshots(msg.filePaths, uuid.value, idx) : [] |
| | | } |
| | | |
| | |
| | | messageObj.salesData = null |
| | | messageObj.purchaseData = null |
| | | messageObj.purchaseIntentData = null |
| | | messageObj.financeData = null |
| | | |
| | | if (isPurchaseIntentNotRecognized) { |
| | | messageObj.purchaseIntentData = normalizePurchaseIntentNotRecognizedData(parsedData) |
| | |
| | | messageObj.purchaseData = purchaseData |
| | | } |
| | | |
| | | const financeData = buildFinancialStructuredData(parsedData) |
| | | if (financeData) { |
| | | messageObj.financeData = financeData |
| | | } |
| | | |
| | | if (parsedData.action === 'confirm_required' && parsedData.businessType) { |
| | | messageObj.type = 'purchase_analysis_confirm' |
| | | messageObj.purchaseAnalysisData = parsedData |
| | | messageObj.manufacturingData = null |
| | | messageObj.salesData = null |
| | | messageObj.purchaseData = null |
| | | messageObj.financeData = null |
| | | if (!Array.isArray(messageObj.payloadTreeData) || !messageObj.payloadTreeData.length) { |
| | | initializePurchasePayloadTree(messageObj, parsedData.payload || {}) |
| | | } |
| | |
| | | if (parsedData.type === 'manufacturing_analysis') return '已为æ¨çæå¶é åæç»æã' |
| | | return 'å·²è¿åå¶é æ¥è¯¢ç»æã' |
| | | } |
| | | if (financialStructuredTypeSet.has(parsedData.type)) return 'å·²è¿åè´¢å¡åæç»æã' |
| | | if (String(parsedData.type || '').startsWith('purchase_')) return 'å·²è¿åéè´æ¥è¯¢ç»æã' |
| | | if (parsedData.charts && Object.keys(parsedData.charts).length > 0) return '已为æ¨çæåæå¾è¡¨ã' |
| | | return 'æ£å¨ä¸ºæ¨å±ç¤ºåæç»æ...' |
| | |
| | | manufacturingData: null, |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null |
| | | purchaseIntentData: null, |
| | | financeData: null |
| | | }) |
| | | |
| | | outputState.value[botMsgIndex] = { |
| | |
| | | manufacturingData: null, |
| | | salesData: null, |
| | | purchaseData: null, |
| | | purchaseIntentData: null |
| | | purchaseIntentData: null, |
| | | financeData: null |
| | | } |
| | | messages.value.push(botMsg) |
| | | |
| | |
| | | color: $deep-blue; |
| | | } |
| | | |
| | | .finance-headline { |
| | | margin-top: 4px; |
| | | font-size: 13px; |
| | | line-height: 1.7; |
| | | color: #344054; |
| | | } |
| | | |
| | | .finance-text-section { |
| | | margin-top: 10px; |
| | | |
| | | ul { |
| | | margin: 6px 0 0; |
| | | padding-left: 18px; |
| | | font-size: 13px; |
| | | line-height: 1.7; |
| | | color: #344054; |
| | | } |
| | | } |
| | | |
| | | .purchase-intent-quick-prompt-wrap { |
| | | margin-top: 12px; |
| | | } |