| ¶Ô±ÈÐÂÎļþ | 
 |  |  | 
 |  |  | <template> | 
 |  |  |   <div class="app-container strategy-control"> | 
 |  |  |     <el-tabs v-model="activeTab" type="border-card" class="main-tabs" @tab-change="handleTabChange"> | 
 |  |  |       <!-- ä»·æ ¼çç¥é
ç½® --> | 
 |  |  |       <el-tab-pane label="ä»·æ ¼çç¥é
ç½®" name="priceStrategy"> | 
 |  |  |         <el-card class="box-card"> | 
 |  |  |           <el-row :gutter="20" class="search-row"> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="priceSearchForm.customerName" placeholder="è¯·éæ©å®¢æ·" clearable> | 
 |  |  |                 <el-option label="å
¨é¨å®¢æ·" value=""></el-option> | 
 |  |  |                 <el-option label="åä¸å»ºæéå¢" value="åä¸å»ºæéå¢"></el-option> | 
 |  |  |                 <el-option label="é¿æ±æ··ååå
¬å¸" value="é¿æ±æ··ååå
¬å¸"></el-option> | 
 |  |  |                 <el-option label="æµ¦æ±æ°´æ³¥å¶åå" value="æµ¦æ±æ°´æ³¥å¶åå"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="priceSearchForm.productType" placeholder="è¯·éæ©æ°´æ³¥ç±»å" clearable> | 
 |  |  |                 <el-option label="å
¨é¨ç±»å" value=""></el-option> | 
 |  |  |                 <el-option label="æ®éç¡
é
¸çæ°´æ³¥" value="æ®éç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="ç¿æ¸£ç¡
é
¸çæ°´æ³¥" value="ç¿æ¸£ç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="å¤åç¡
é
¸çæ°´æ³¥" value="å¤åç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="priceSearchForm.strategyType" placeholder="çç¥ç±»å" clearable> | 
 |  |  |                 <el-option label="å
¨é¨çç¥" value=""></el-option> | 
 |  |  |                 <el-option label="ä¸å±ä»·æ ¼" value="ä¸å±ä»·æ ¼"></el-option> | 
 |  |  |                 <el-option label="é¶æ¢¯æ¥ä»·" value="é¶æ¢¯æ¥ä»·"></el-option> | 
 |  |  |                 <el-option label="ä¿éææ£" value="ä¿éææ£"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-button type="primary" @click="searchPriceStrategy">æ¥è¯¢</el-button> | 
 |  |  |               <el-button @click="resetPriceSearch">éç½®</el-button> | 
 |  |  |               <el-button type="primary" @click="handleAddPriceStrategy">æ°å¢çç¥</el-button> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <el-table :data="priceStrategyList" border stripe v-loading="priceLoading" height="calc(100vh - 26em)"> | 
 |  |  |             <el-table-column prop="id" label="ID" width="60" align="center"/> | 
 |  |  |             <el-table-column prop="strategyNo" label="çç¥ç¼å·" width="150"/> | 
 |  |  |             <el-table-column prop="strategyType" label="çç¥ç±»å" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="getStrategyTypeColor(scope.row.strategyType)"> | 
 |  |  |                   {{ scope.row.strategyType }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="customerName" label="客æ·åç§°" width="180"/> | 
 |  |  |             <el-table-column prop="productName" label="产ååç§°" width="200"/> | 
 |  |  |             <el-table-column prop="specification" label="è§æ ¼åå·" width="120"/> | 
 |  |  |             <el-table-column prop="basePrice" label="åºç¡ä»·æ ¼" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.basePrice }}/å¨ | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="strategyPrice" label="çç¥ä»·æ ¼" width="120"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <span style="color: #f56c6c; font-weight: bold;"> | 
 |  |  |                   {{ scope.row.strategyPrice }} | 
 |  |  |                 </span> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="validPeriod" label="æææ" width="200"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.startDate }} è³ {{ scope.row.endDate }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="status" label="ç¶æ" width="80"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="scope.row.status === 'çæä¸' ? 'success' : 'info'"> | 
 |  |  |                   {{ scope.row.status }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" width="200" fixed="right" align="center"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button link type="primary" @click="handleViewPriceStrategy(scope.row)">æ¥ç</el-button> | 
 |  |  |                 <el-button link type="primary" @click="handleEditPriceStrategy(scope.row)">ç¼è¾</el-button> | 
 |  |  |                 <el-button link type="danger" @click="handleDeletePriceStrategy(scope.row)">å é¤</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |  | 
 |  |  |           <pagination | 
 |  |  |             :total="pricePagination.total" | 
 |  |  |             :page="pricePagination.currentPage" | 
 |  |  |             :limit="pricePagination.pageSize" | 
 |  |  |             @pagination="handlePricePageChange" | 
 |  |  |           /> | 
 |  |  |         </el-card> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- ååæ§è¡çæ§ --> | 
 |  |  |       <el-tab-pane label="ååæ§è¡çæ§" name="contractMonitor"> | 
 |  |  |         <el-card class="box-card"> | 
 |  |  |           <!-- ç»è®¡æ¦è§ --> | 
 |  |  |           <el-row :gutter="20" class="stats-row"> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <div class="stat-card"> | 
 |  |  |                 <div class="stat-icon" style="background: #ecf5ff;"> | 
 |  |  |                   <el-icon :size="30" color="#409eff"><Document /></el-icon> | 
 |  |  |                 </div> | 
 |  |  |                 <div class="stat-content"> | 
 |  |  |                   <div class="stat-value">{{ contractStats.totalContracts }}</div> | 
 |  |  |                   <div class="stat-label">ååæ»æ°</div> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <div class="stat-card"> | 
 |  |  |                 <div class="stat-icon" style="background: #f0f9ff;"> | 
 |  |  |                   <el-icon :size="30" color="#67c23a"><Van /></el-icon> | 
 |  |  |                 </div> | 
 |  |  |                 <div class="stat-content"> | 
 |  |  |                   <div class="stat-value">{{ contractStats.deliveryRate }}%</div> | 
 |  |  |                   <div class="stat-label">交ä»å®æç</div> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <div class="stat-card"> | 
 |  |  |                 <div class="stat-icon" style="background: #fef0f0;"> | 
 |  |  |                   <el-icon :size="30" color="#e6a23c"><Tickets /></el-icon> | 
 |  |  |                 </div> | 
 |  |  |                 <div class="stat-content"> | 
 |  |  |                   <div class="stat-value">{{ contractStats.invoiceRate }}%</div> | 
 |  |  |                   <div class="stat-label">å票å¼å
·ç</div> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <div class="stat-card"> | 
 |  |  |                 <div class="stat-icon" style="background: #f4f4f5;"> | 
 |  |  |                   <el-icon :size="30" color="#f56c6c"><Wallet /></el-icon> | 
 |  |  |                 </div> | 
 |  |  |                 <div class="stat-content"> | 
 |  |  |                   <div class="stat-value">{{ contractStats.paymentRate }}%</div> | 
 |  |  |                   <div class="stat-label">忬¾å®æç</div> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <!-- æç´¢åºå --> | 
 |  |  |           <el-row :gutter="20" class="search-row"> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-input v-model="contractSearchForm.contractNo" placeholder="请è¾å
¥ååç¼å·" clearable> | 
 |  |  |                 <template #prefix> | 
 |  |  |                   <el-icon><Search /></el-icon> | 
 |  |  |                 </template> | 
 |  |  |               </el-input> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="contractSearchForm.customerName" placeholder="è¯·éæ©å®¢æ·" clearable> | 
 |  |  |                 <el-option label="åä¸å»ºæéå¢" value="åä¸å»ºæéå¢"></el-option> | 
 |  |  |                 <el-option label="é¿æ±æ··ååå
¬å¸" value="é¿æ±æ··ååå
¬å¸"></el-option> | 
 |  |  |                 <el-option label="æµ¦æ±æ°´æ³¥å¶åå" value="æµ¦æ±æ°´æ³¥å¶åå"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="contractSearchForm.executionStatus" placeholder="æ§è¡ç¶æ" clearable> | 
 |  |  |                 <el-option label="å¾
æ§è¡" value="å¾
æ§è¡"></el-option> | 
 |  |  |                 <el-option label="æ§è¡ä¸" value="æ§è¡ä¸"></el-option> | 
 |  |  |                 <el-option label="已宿" value="已宿"></el-option> | 
 |  |  |                 <el-option label="å¼å¸¸" value="å¼å¸¸"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-button type="primary" @click="searchContract">æ¥è¯¢</el-button> | 
 |  |  |               <el-button @click="resetContractSearch">éç½®</el-button> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <!-- ååå表 --> | 
 |  |  |           <el-table :data="contractList" border stripe v-loading="contractLoading" height="calc(100vh - 36em)"> | 
 |  |  |             <el-table-column type="expand"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <div class="contract-detail-expand"> | 
 |  |  |                   <el-steps :active="getContractStep(scope.row)" align-center> | 
 |  |  |                     <el-step title="订å确认" :description="scope.row.orderDate"> | 
 |  |  |                       <template #icon> | 
 |  |  |                         <el-icon :color="scope.row.orderStatus === '已宿' ? '#67c23a' : '#909399'"> | 
 |  |  |                           <Check v-if="scope.row.orderStatus === '已宿'" /> | 
 |  |  |                           <Clock v-else /> | 
 |  |  |                         </el-icon> | 
 |  |  |                       </template> | 
 |  |  |                     </el-step> | 
 |  |  |                     <el-step title="è´§ç©äº¤ä»" :description="`${scope.row.deliveryProgress}%`"> | 
 |  |  |                       <template #icon> | 
 |  |  |                         <el-icon :color="scope.row.deliveryProgress === 100 ? '#67c23a' : '#409eff'"> | 
 |  |  |                           <Check v-if="scope.row.deliveryProgress === 100" /> | 
 |  |  |                           <Van v-else /> | 
 |  |  |                         </el-icon> | 
 |  |  |                       </template> | 
 |  |  |                     </el-step> | 
 |  |  |                     <el-step title="å票å¼å
·" :description="`${scope.row.invoiceProgress}%`"> | 
 |  |  |                       <template #icon> | 
 |  |  |                         <el-icon :color="scope.row.invoiceProgress === 100 ? '#67c23a' : '#e6a23c'"> | 
 |  |  |                           <Check v-if="scope.row.invoiceProgress === 100" /> | 
 |  |  |                           <Tickets v-else /> | 
 |  |  |                         </el-icon> | 
 |  |  |                       </template> | 
 |  |  |                     </el-step> | 
 |  |  |                     <el-step title="款项æ¶å" :description="`${scope.row.paymentProgress}%`"> | 
 |  |  |                       <template #icon> | 
 |  |  |                         <el-icon :color="scope.row.paymentProgress === 100 ? '#67c23a' : '#f56c6c'"> | 
 |  |  |                           <Check v-if="scope.row.paymentProgress === 100" /> | 
 |  |  |                           <Wallet v-else /> | 
 |  |  |                         </el-icon> | 
 |  |  |                       </template> | 
 |  |  |                     </el-step> | 
 |  |  |                   </el-steps> | 
 |  |  |                 </div> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="contractNo" label="ååç¼å·" width="150"/> | 
 |  |  |             <el-table-column prop="customerName" label="客æ·åç§°" width="180"/> | 
 |  |  |             <el-table-column prop="contractAmount" label="ååéé¢" width="120"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.contractAmount.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="signDate" label="ç¾è®¢æ¥æ" width="120"/> | 
 |  |  |             <el-table-column label="æ§è¡è¿åº¦" width="150"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-progress  | 
 |  |  |                   :percentage="scope.row.executionProgress"  | 
 |  |  |                   :color="getProgressColor(scope.row.executionProgress)" | 
 |  |  |                 /> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="deliveryProgress" label="交ä»è¿åº¦" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.deliveryProgress }}% | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="invoiceProgress" label="å¼ç¥¨è¿åº¦" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.invoiceProgress }}% | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="paymentProgress" label="忬¾è¿åº¦" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.paymentProgress }}% | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="executionStatus" label="æ§è¡ç¶æ" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="getExecutionStatusType(scope.row.executionStatus)"> | 
 |  |  |                   {{ scope.row.executionStatus }} | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column label="æä½" width="120" fixed="right" align="center"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-button link type="primary" @click="handleViewContract(scope.row)">æ¥ç详æ
</el-button> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |           </el-table> | 
 |  |  |  | 
 |  |  |           <pagination | 
 |  |  |             :total="contractPagination.total" | 
 |  |  |             :page="contractPagination.currentPage" | 
 |  |  |             :limit="contractPagination.pageSize" | 
 |  |  |             @pagination="handleContractPageChange" | 
 |  |  |           /> | 
 |  |  |         </el-card> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- å岿¯ä»·åæ --> | 
 |  |  |       <el-tab-pane label="å岿¯ä»·åæ" name="priceComparison"> | 
 |  |  |         <el-card class="box-card"> | 
 |  |  |           <el-row :gutter="20" class="search-row"> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="compareSearchForm.productName" placeholder="è¯·éæ©äº§å" clearable> | 
 |  |  |                 <el-option label="P.O 42.5æ®éç¡
é
¸çæ°´æ³¥" value="P.O 42.5æ®éç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥" value="P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="P.C 32.5å¤åç¡
é
¸çæ°´æ³¥" value="P.C 32.5å¤åç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="8"> | 
 |  |  |               <el-date-picker | 
 |  |  |                 v-model="compareSearchForm.dateRange" | 
 |  |  |                 type="daterange" | 
 |  |  |                 range-separator="è³" | 
 |  |  |                 start-placeholder="å¼å§æ¥æ" | 
 |  |  |                 end-placeholder="ç»ææ¥æ" | 
 |  |  |                 value-format="YYYY-MM-DD" | 
 |  |  |                 style="width: 100%" | 
 |  |  |               /> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="compareSearchForm.region" placeholder="éå®åºå" clearable> | 
 |  |  |                 <el-option label="åä¸å°åº" value="åä¸å°åº"></el-option> | 
 |  |  |                 <el-option label="ååå°åº" value="ååå°åº"></el-option> | 
 |  |  |                 <el-option label="ååå°åº" value="ååå°åº"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="4"> | 
 |  |  |               <el-button type="primary" @click="searchPriceComparison">æ¥è¯¢</el-button> | 
 |  |  |               <el-button @click="resetCompareSearch">éç½®</el-button> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <!-- ä»·æ ¼è¶å¿å¾ --> | 
 |  |  |           <div class="chart-container"> | 
 |  |  |             <div ref="priceChartRef" style="width: 100%; height: 350px;"></div> | 
 |  |  |           </div> | 
 |  |  |  | 
 |  |  |           <!-- åå²ä»·æ ¼å表 --> | 
 |  |  |           <el-table :data="priceComparisonList" border stripe v-loading="compareLoading" style="margin-top: 20px;"> | 
 |  |  |             <el-table-column prop="date" label="æ¥æ" width="120"/> | 
 |  |  |             <el-table-column prop="productName" label="产ååç§°" width="200"/> | 
 |  |  |             <el-table-column prop="specification" label="è§æ ¼" width="120"/> | 
 |  |  |             <el-table-column prop="customerName" label="客æ·" width="180"/> | 
 |  |  |             <el-table-column prop="region" label="åºå" width="100"/> | 
 |  |  |             <el-table-column prop="quantity" label="æ°é(å¨)" width="100" align="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.quantity.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="price" label="æäº¤åä»·" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.price }}/å¨ | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="totalAmount" label="æäº¤éé¢" width="120"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.totalAmount.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="priceChange" label="ä»·æ ¼åå¨" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <span :style="{ color: scope.row.priceChange > 0 ? '#f56c6c' : scope.row.priceChange < 0 ? '#67c23a' : '#909399' }"> | 
 |  |  |                   {{ scope.row.priceChange > 0 ? '+' : '' }}{{ scope.row.priceChange }} | 
 |  |  |                 </span> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="remark" label="夿³¨" show-overflow-tooltip/> | 
 |  |  |           </el-table> | 
 |  |  |         </el-card> | 
 |  |  |       </el-tab-pane> | 
 |  |  |  | 
 |  |  |       <!-- å©æ¶¦åæ --> | 
 |  |  |       <el-tab-pane label="婿¶¦åæ" name="profitAnalysis"> | 
 |  |  |         <el-card class="box-card"> | 
 |  |  |           <!-- å©æ¶¦ç»è®¡å¡ç --> | 
 |  |  |           <el-row :gutter="20" class="profit-stats-row"> | 
 |  |  |             <el-col :span="8"> | 
 |  |  |               <div class="profit-card"> | 
 |  |  |                 <div class="profit-header">æ»éå®é¢</div> | 
 |  |  |                 <div class="profit-value">Â¥{{ profitStats.totalSales.toLocaleString() }}</div> | 
 |  |  |                 <div class="profit-footer"> | 
 |  |  |                   <span>è¾ä¸æ</span> | 
 |  |  |                   <span :class="profitStats.salesGrowth > 0 ? 'growth-up' : 'growth-down'"> | 
 |  |  |                     {{ profitStats.salesGrowth > 0 ? '+' : '' }}{{ profitStats.salesGrowth }}% | 
 |  |  |                   </span> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="8"> | 
 |  |  |               <div class="profit-card"> | 
 |  |  |                 <div class="profit-header">æ»ææ¬</div> | 
 |  |  |                 <div class="profit-value">Â¥{{ profitStats.totalCost.toLocaleString() }}</div> | 
 |  |  |                 <div class="profit-footer"> | 
 |  |  |                   <span>ææ¬ç</span> | 
 |  |  |                   <span class="cost-rate">{{ profitStats.costRate }}%</span> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="8"> | 
 |  |  |               <div class="profit-card"> | 
 |  |  |                 <div class="profit-header">æ¯å©æ¶¦</div> | 
 |  |  |                 <div class="profit-value profit-highlight">Â¥{{ profitStats.grossProfit.toLocaleString() }}</div> | 
 |  |  |                 <div class="profit-footer"> | 
 |  |  |                   <span>æ¯å©ç</span> | 
 |  |  |                   <span class="gross-profit-rate">{{ profitStats.grossProfitRate }}%</span> | 
 |  |  |                 </div> | 
 |  |  |               </div> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <!-- æç´¢åºå --> | 
 |  |  |           <el-row :gutter="20" class="search-row"> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="profitSearchForm.productType" placeholder="产åç±»å" clearable> | 
 |  |  |                 <el-option label="æ®éç¡
é
¸çæ°´æ³¥" value="æ®éç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="ç¿æ¸£ç¡
é
¸çæ°´æ³¥" value="ç¿æ¸£ç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="å¤åç¡
é
¸çæ°´æ³¥" value="å¤åç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="6"> | 
 |  |  |               <el-select v-model="profitSearchForm.customerName" placeholder="客æ·åç§°" clearable> | 
 |  |  |                 <el-option label="åä¸å»ºæéå¢" value="åä¸å»ºæéå¢"></el-option> | 
 |  |  |                 <el-option label="é¿æ±æ··ååå
¬å¸" value="é¿æ±æ··ååå
¬å¸"></el-option> | 
 |  |  |                 <el-option label="æµ¦æ±æ°´æ³¥å¶åå" value="æµ¦æ±æ°´æ³¥å¶åå"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="8"> | 
 |  |  |               <el-date-picker | 
 |  |  |                 v-model="profitSearchForm.dateRange" | 
 |  |  |                 type="monthrange" | 
 |  |  |                 range-separator="è³" | 
 |  |  |                 start-placeholder="å¼å§æä»½" | 
 |  |  |                 end-placeholder="ç»ææä»½" | 
 |  |  |                 value-format="YYYY-MM" | 
 |  |  |                 style="width: 100%" | 
 |  |  |               /> | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="4"> | 
 |  |  |               <el-button type="primary" @click="searchProfit">æ¥è¯¢</el-button> | 
 |  |  |               <el-button @click="resetProfitSearch">éç½®</el-button> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  |  | 
 |  |  |           <!-- å©æ¶¦åæå¾è¡¨ --> | 
 |  |  |           <div class="chart-container"> | 
 |  |  |             <div ref="profitChartRef" style="width: 100%; height: 350px;"></div> | 
 |  |  |           </div> | 
 |  |  |  | 
 |  |  |           <!-- å©æ¶¦æç»è¡¨ --> | 
 |  |  |           <el-table :data="profitAnalysisList" border stripe v-loading="profitLoading" style="margin-top: 20px;" show-summary :summary-method="getProfitSummary"> | 
 |  |  |             <el-table-column prop="orderNo" label="订åç¼å·" width="150"/> | 
 |  |  |             <el-table-column prop="customerName" label="客æ·åç§°" width="180"/> | 
 |  |  |             <el-table-column prop="productName" label="产ååç§°" width="200"/> | 
 |  |  |             <el-table-column prop="quantity" label="æ°é(å¨)" width="100" align="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 {{ scope.row.quantity.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="salesPrice" label="éå®åä»·" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.salesPrice }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="costPrice" label="ææ¬åä»·" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.costPrice }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="salesAmount" label="éå®éé¢" width="120" align="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.salesAmount.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="costAmount" label="ææ¬éé¢" width="120" align="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 Â¥{{ scope.row.costAmount.toLocaleString() }} | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="grossProfit" label="æ¯å©æ¶¦" width="120" align="right"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <span :style="{ color: scope.row.grossProfit > 0 ? '#67c23a' : '#f56c6c', fontWeight: 'bold' }"> | 
 |  |  |                   Â¥{{ scope.row.grossProfit.toLocaleString() }} | 
 |  |  |                 </span> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="grossProfitRate" label="æ¯å©ç" width="100"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-tag :type="getProfitRateType(scope.row.grossProfitRate)"> | 
 |  |  |                   {{ scope.row.grossProfitRate }}% | 
 |  |  |                 </el-tag> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="orderDate" label="è®¢åæ¥æ" width="120"/> | 
 |  |  |           </el-table> | 
 |  |  |  | 
 |  |  |           <pagination | 
 |  |  |             :total="profitPagination.total" | 
 |  |  |             :page="profitPagination.currentPage" | 
 |  |  |             :limit="profitPagination.pageSize" | 
 |  |  |             @pagination="handleProfitPageChange" | 
 |  |  |           /> | 
 |  |  |         </el-card> | 
 |  |  |       </el-tab-pane> | 
 |  |  |     </el-tabs> | 
 |  |  |  | 
 |  |  |     <!-- ä»·æ ¼çç¥å¯¹è¯æ¡ --> | 
 |  |  |     <el-dialog v-model="priceStrategyDialogVisible" :title="priceStrategyDialogTitle" width="900px" :close-on-click-modal="false"> | 
 |  |  |       <el-form :model="priceStrategyForm" :rules="priceStrategyRules" ref="priceStrategyFormRef" label-width="120px"> | 
 |  |  |         <el-row :gutter="20"> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="çç¥ç±»å" prop="strategyType"> | 
 |  |  |               <el-select v-model="priceStrategyForm.strategyType" placeholder="è¯·éæ©çç¥ç±»å" style="width: 100%;"> | 
 |  |  |                 <el-option label="ä¸å±ä»·æ ¼" value="ä¸å±ä»·æ ¼"></el-option> | 
 |  |  |                 <el-option label="é¶æ¢¯æ¥ä»·" value="é¶æ¢¯æ¥ä»·"></el-option> | 
 |  |  |                 <el-option label="ä¿éææ£" value="ä¿éææ£"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="客æ·åç§°" prop="customerName"> | 
 |  |  |               <el-select v-model="priceStrategyForm.customerName" placeholder="è¯·éæ©å®¢æ·" style="width: 100%;"> | 
 |  |  |                 <el-option label="åä¸å»ºæéå¢" value="åä¸å»ºæéå¢"></el-option> | 
 |  |  |                 <el-option label="é¿æ±æ··ååå
¬å¸" value="é¿æ±æ··ååå
¬å¸"></el-option> | 
 |  |  |                 <el-option label="æµ¦æ±æ°´æ³¥å¶åå" value="æµ¦æ±æ°´æ³¥å¶åå"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |         </el-row> | 
 |  |  |         <el-row :gutter="20"> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="产ååç§°" prop="productName"> | 
 |  |  |               <el-select v-model="priceStrategyForm.productName" placeholder="è¯·éæ©äº§å" style="width: 100%;"> | 
 |  |  |                 <el-option label="P.O 42.5æ®éç¡
é
¸çæ°´æ³¥" value="P.O 42.5æ®éç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥" value="P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |                 <el-option label="P.C 32.5å¤åç¡
é
¸çæ°´æ³¥" value="P.C 32.5å¤åç¡
é
¸çæ°´æ³¥"></el-option> | 
 |  |  |               </el-select> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="è§æ ¼åå·" prop="specification"> | 
 |  |  |               <el-input v-model="priceStrategyForm.specification" placeholder="请è¾å
¥è§æ ¼åå·" /> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |         </el-row> | 
 |  |  |         <el-row :gutter="20"> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="åºç¡ä»·æ ¼(å
/å¨)" prop="basePrice"> | 
 |  |  |               <el-input-number v-model="priceStrategyForm.basePrice" :min="0" :precision="2" style="width: 100%;" /> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="çç¥ä»·æ ¼" prop="strategyPrice"> | 
 |  |  |               <el-input v-model="priceStrategyForm.strategyPrice" placeholder="å¦: Â¥350/娠æ 9æ" /> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |         </el-row> | 
 |  |  |         <el-row :gutter="20"> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="çææ¥æ" prop="startDate"> | 
 |  |  |               <el-date-picker | 
 |  |  |                 v-model="priceStrategyForm.startDate" | 
 |  |  |                 type="date" | 
 |  |  |                 placeholder="éæ©çææ¥æ" | 
 |  |  |                 style="width: 100%" | 
 |  |  |                 value-format="YYYY-MM-DD" | 
 |  |  |               /> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |           <el-col :span="12"> | 
 |  |  |             <el-form-item label="å¤±ææ¥æ" prop="endDate"> | 
 |  |  |               <el-date-picker | 
 |  |  |                 v-model="priceStrategyForm.endDate" | 
 |  |  |                 type="date" | 
 |  |  |                 placeholder="éæ©å¤±ææ¥æ" | 
 |  |  |                 style="width: 100%" | 
 |  |  |                 value-format="YYYY-MM-DD" | 
 |  |  |               /> | 
 |  |  |             </el-form-item> | 
 |  |  |           </el-col> | 
 |  |  |         </el-row> | 
 |  |  |         <el-form-item label="çç¥è¯´æ" prop="description"> | 
 |  |  |           <el-input type="textarea" v-model="priceStrategyForm.description" :rows="3" placeholder="请è¾å
¥çç¥è¯´æ" /> | 
 |  |  |         </el-form-item> | 
 |  |  |       </el-form> | 
 |  |  |       <template #footer> | 
 |  |  |         <el-button @click="priceStrategyDialogVisible = false">åæ¶</el-button> | 
 |  |  |         <el-button type="primary" @click="handleSavePriceStrategy">ä¿å</el-button> | 
 |  |  |       </template> | 
 |  |  |     </el-dialog> | 
 |  |  |   </div> | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | <script setup> | 
 |  |  | import { ref, reactive, onMounted, nextTick, watch } from 'vue' | 
 |  |  | import { ElMessage, ElMessageBox } from 'element-plus' | 
 |  |  | import { Document, Van, Tickets, Wallet, Check, Clock, Search } from '@element-plus/icons-vue' | 
 |  |  | import * as echarts from 'echarts' | 
 |  |  | import Pagination from '@/components/PIMTable/Pagination.vue' | 
 |  |  |  | 
 |  |  | // æ´»å¨æ ç¾é¡µ | 
 |  |  | const activeTab = ref('priceStrategy') | 
 |  |  |  | 
 |  |  | // ========== ä»·æ ¼çç¥é
ç½® ========== | 
 |  |  | const priceLoading = ref(false) | 
 |  |  | const priceSearchForm = reactive({ | 
 |  |  |   customerName: '', | 
 |  |  |   productType: '', | 
 |  |  |   strategyType: '' | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const priceStrategyList = ref([ | 
 |  |  |   { | 
 |  |  |     id: 1, | 
 |  |  |     strategyNo: 'PS202501001', | 
 |  |  |     strategyType: 'ä¸å±ä»·æ ¼', | 
 |  |  |     customerName: 'åä¸å»ºæéå¢', | 
 |  |  |     productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', | 
 |  |  |     specification: '50kg/è¢', | 
 |  |  |     basePrice: 380, | 
 |  |  |     strategyPrice: 'Â¥350/å¨', | 
 |  |  |     startDate: '2025-01-01', | 
 |  |  |     endDate: '2025-12-31', | 
 |  |  |     status: 'çæä¸', | 
 |  |  |     description: 'æç¥åä½å®¢æ·ä¸å±ä¼æ ä»·æ ¼' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 2, | 
 |  |  |     strategyNo: 'PS202501002', | 
 |  |  |     strategyType: 'é¶æ¢¯æ¥ä»·', | 
 |  |  |     customerName: 'é¿æ±æ··ååå
¬å¸', | 
 |  |  |     productName: 'P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥', | 
 |  |  |     specification: '50kg/è¢', | 
 |  |  |     basePrice: 320, | 
 |  |  |     strategyPrice: '500å¨ä»¥ä¸9æ', | 
 |  |  |     startDate: '2025-01-01', | 
 |  |  |     endDate: '2025-06-30', | 
 |  |  |     status: 'çæä¸', | 
 |  |  |     description: '大æ¹ééè´é¶æ¢¯ä¼æ ' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 3, | 
 |  |  |     strategyNo: 'PS202501003', | 
 |  |  |     strategyType: 'ä¿éææ£', | 
 |  |  |     customerName: 'æµ¦æ±æ°´æ³¥å¶åå', | 
 |  |  |     productName: 'P.C 32.5å¤åç¡
é
¸çæ°´æ³¥', | 
 |  |  |     specification: '50kg/è¢', | 
 |  |  |     basePrice: 300, | 
 |  |  |     strategyPrice: '8.5æ', | 
 |  |  |     startDate: '2025-01-15', | 
 |  |  |     endDate: '2025-02-28', | 
 |  |  |     status: 'çæä¸', | 
 |  |  |     description: 'æ¥èä¿éæ´»å¨' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 4, | 
 |  |  |     strategyNo: 'PS202412015', | 
 |  |  |     strategyType: 'ä¸å±ä»·æ ¼', | 
 |  |  |     customerName: 'åä¸å»ºæéå¢', | 
 |  |  |     productName: 'P.C 32.5å¤åç¡
é
¸çæ°´æ³¥', | 
 |  |  |     specification: '50kg/è¢', | 
 |  |  |     basePrice: 300, | 
 |  |  |     strategyPrice: 'Â¥285/å¨', | 
 |  |  |     startDate: '2024-10-01', | 
 |  |  |     endDate: '2024-12-31', | 
 |  |  |     status: 'å·²è¿æ', | 
 |  |  |     description: '第åå£åº¦ä¸å±ä»·æ ¼' | 
 |  |  |   } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const pricePagination = reactive({ | 
 |  |  |   total: 4, | 
 |  |  |   currentPage: 1, | 
 |  |  |   pageSize: 10 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const priceStrategyDialogVisible = ref(false) | 
 |  |  | const priceStrategyDialogTitle = ref('æ°å¢ä»·æ ¼çç¥') | 
 |  |  | const priceStrategyForm = reactive({ | 
 |  |  |   strategyType: '', | 
 |  |  |   customerName: '', | 
 |  |  |   productName: '', | 
 |  |  |   specification: '', | 
 |  |  |   basePrice: 0, | 
 |  |  |   strategyPrice: '', | 
 |  |  |   startDate: '', | 
 |  |  |   endDate: '', | 
 |  |  |   description: '' | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const priceStrategyRules = { | 
 |  |  |   strategyType: [{ required: true, message: 'è¯·éæ©çç¥ç±»å', trigger: 'change' }], | 
 |  |  |   customerName: [{ required: true, message: 'è¯·éæ©å®¢æ·', trigger: 'change' }], | 
 |  |  |   productName: [{ required: true, message: 'è¯·éæ©äº§å', trigger: 'change' }], | 
 |  |  |   basePrice: [{ required: true, message: '请è¾å
¥åºç¡ä»·æ ¼', trigger: 'blur' }], | 
 |  |  |   strategyPrice: [{ required: true, message: '请è¾å
¥çç¥ä»·æ ¼', trigger: 'blur' }], | 
 |  |  |   startDate: [{ required: true, message: 'è¯·éæ©çææ¥æ', trigger: 'change' }], | 
 |  |  |   endDate: [{ required: true, message: 'è¯·éæ©å¤±ææ¥æ', trigger: 'change' }] | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const priceStrategyFormRef = ref() | 
 |  |  |  | 
 |  |  | // ========== ååæ§è¡çæ§ ========== | 
 |  |  | const contractLoading = ref(false) | 
 |  |  | const contractStats = reactive({ | 
 |  |  |   totalContracts: 48, | 
 |  |  |   deliveryRate: 87.5, | 
 |  |  |   invoiceRate: 82.3, | 
 |  |  |   paymentRate: 75.6 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const contractSearchForm = reactive({ | 
 |  |  |   contractNo: '', | 
 |  |  |   customerName: '', | 
 |  |  |   executionStatus: '' | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const contractList = ref([ | 
 |  |  |   { | 
 |  |  |     id: 1, | 
 |  |  |     contractNo: 'CT202501001', | 
 |  |  |     customerName: 'åä¸å»ºæéå¢', | 
 |  |  |     contractAmount: 2850000, | 
 |  |  |     signDate: '2025-01-05', | 
 |  |  |     executionProgress: 85, | 
 |  |  |     deliveryProgress: 90, | 
 |  |  |     invoiceProgress: 85, | 
 |  |  |     paymentProgress: 75, | 
 |  |  |     executionStatus: 'æ§è¡ä¸', | 
 |  |  |     orderStatus: '已宿', | 
 |  |  |     orderDate: '2025-01-05' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 2, | 
 |  |  |     contractNo: 'CT202501002', | 
 |  |  |     customerName: 'é¿æ±æ··ååå
¬å¸', | 
 |  |  |     contractAmount: 1650000, | 
 |  |  |     signDate: '2025-01-08', | 
 |  |  |     executionProgress: 95, | 
 |  |  |     deliveryProgress: 100, | 
 |  |  |     invoiceProgress: 100, | 
 |  |  |     paymentProgress: 85, | 
 |  |  |     executionStatus: 'æ§è¡ä¸', | 
 |  |  |     orderStatus: '已宿', | 
 |  |  |     orderDate: '2025-01-08' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 3, | 
 |  |  |     contractNo: 'CT202501003', | 
 |  |  |     customerName: 'æµ¦æ±æ°´æ³¥å¶åå', | 
 |  |  |     contractAmount: 980000, | 
 |  |  |     signDate: '2025-01-12', | 
 |  |  |     executionProgress: 60, | 
 |  |  |     deliveryProgress: 65, | 
 |  |  |     invoiceProgress: 60, | 
 |  |  |     paymentProgress: 50, | 
 |  |  |     executionStatus: 'æ§è¡ä¸', | 
 |  |  |     orderStatus: '已宿', | 
 |  |  |     orderDate: '2025-01-12' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 4, | 
 |  |  |     contractNo: 'CT202412028', | 
 |  |  |     customerName: 'åä¸å»ºæéå¢', | 
 |  |  |     contractAmount: 3200000, | 
 |  |  |     signDate: '2024-12-15', | 
 |  |  |     executionProgress: 100, | 
 |  |  |     deliveryProgress: 100, | 
 |  |  |     invoiceProgress: 100, | 
 |  |  |     paymentProgress: 100, | 
 |  |  |     executionStatus: '已宿', | 
 |  |  |     orderStatus: '已宿', | 
 |  |  |     orderDate: '2024-12-15' | 
 |  |  |   }, | 
 |  |  |   { | 
 |  |  |     id: 5, | 
 |  |  |     contractNo: 'CT202501004', | 
 |  |  |     customerName: 'é¿æ±æ··ååå
¬å¸', | 
 |  |  |     contractAmount: 750000, | 
 |  |  |     signDate: '2025-01-20', | 
 |  |  |     executionProgress: 25, | 
 |  |  |     deliveryProgress: 30, | 
 |  |  |     invoiceProgress: 20, | 
 |  |  |     paymentProgress: 0, | 
 |  |  |     executionStatus: 'å¼å¸¸', | 
 |  |  |     orderStatus: '已宿', | 
 |  |  |     orderDate: '2025-01-20' | 
 |  |  |   } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const contractPagination = reactive({ | 
 |  |  |   total: 5, | 
 |  |  |   currentPage: 1, | 
 |  |  |   pageSize: 10 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | // ========== å岿¯ä»·åæ ========== | 
 |  |  | const compareLoading = ref(false) | 
 |  |  | const compareSearchForm = reactive({ | 
 |  |  |   productName: '', | 
 |  |  |   dateRange: [], | 
 |  |  |   region: '' | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const priceComparisonList = ref([ | 
 |  |  |   { date: '2025-01-20', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: 'åä¸å»ºæéå¢', region: 'åä¸å°åº', quantity: 5000, price: 350, totalAmount: 1750000, priceChange: 0, remark: 'é¿æåä½å®¢æ·' }, | 
 |  |  |   { date: '2025-01-15', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: 'æµ¦ä¸æ°åºå»ºçå
¬å¸', region: 'åä¸å°åº', quantity: 3000, price: 365, totalAmount: 1095000, priceChange: +15, remark: 'ç°æ¬¾ç°è´§' }, | 
 |  |  |   { date: '2025-01-10', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: 'é¿æ±æ··ååå
¬å¸', region: 'åä¸å°åº', quantity: 8000, price: 345, totalAmount: 2760000, priceChange: -5, remark: '大æ¹é伿 ' }, | 
 |  |  |   { date: '2025-01-05', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: 'æ±èå·¥ç¨éå¢', region: 'åä¸å°åº', quantity: 4500, price: 360, totalAmount: 1620000, priceChange: +10, remark: 'å·¥ç¨é¡¹ç®ä¸ç¨' }, | 
 |  |  |   { date: '2024-12-28', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: 'åä¸å»ºæéå¢', region: 'åä¸å°åº', quantity: 6000, price: 355, totalAmount: 2130000, priceChange: +5, remark: 'å¹´åºå¤è´§' }, | 
 |  |  |   { date: '2024-12-20', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', specification: '50kg/è¢', customerName: '䏿µ·å¸æ¿å·¥ç¨', region: 'åä¸å°åº', quantity: 10000, price: 340, totalAmount: 3400000, priceChange: -10, remark: 'æ¿åºé¡¹ç®' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const priceChartRef = ref(null) | 
 |  |  | let priceChart = null | 
 |  |  |  | 
 |  |  | // ========== å©æ¶¦åæ ========== | 
 |  |  | const profitLoading = ref(false) | 
 |  |  | const profitStats = reactive({ | 
 |  |  |   totalSales: 15680000, | 
 |  |  |   totalCost: 11256000, | 
 |  |  |   grossProfit: 4424000, | 
 |  |  |   grossProfitRate: 28.2, | 
 |  |  |   salesGrowth: 12.5, | 
 |  |  |   costRate: 71.8 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const profitSearchForm = reactive({ | 
 |  |  |   productType: '', | 
 |  |  |   customerName: '', | 
 |  |  |   dateRange: [] | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const profitAnalysisList = ref([ | 
 |  |  |   { orderNo: 'SO202501015', customerName: 'åä¸å»ºæéå¢', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', quantity: 5000, salesPrice: 350, costPrice: 245, salesAmount: 1750000, costAmount: 1225000, grossProfit: 525000, grossProfitRate: 30.0, orderDate: '2025-01-20' }, | 
 |  |  |   { orderNo: 'SO202501012', customerName: 'é¿æ±æ··ååå
¬å¸', productName: 'P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥', quantity: 3500, salesPrice: 288, costPrice: 210, salesAmount: 1008000, costAmount: 735000, grossProfit: 273000, grossProfitRate: 27.1, orderDate: '2025-01-18' }, | 
 |  |  |   { orderNo: 'SO202501008', customerName: 'æµ¦æ±æ°´æ³¥å¶åå', productName: 'P.C 32.5å¤åç¡
é
¸çæ°´æ³¥', quantity: 2800, salesPrice: 255, costPrice: 185, salesAmount: 714000, costAmount: 518000, grossProfit: 196000, grossProfitRate: 27.5, orderDate: '2025-01-15' }, | 
 |  |  |   { orderNo: 'SO202501005', customerName: 'åä¸å»ºæéå¢', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', quantity: 6000, salesPrice: 350, costPrice: 248, salesAmount: 2100000, costAmount: 1488000, grossProfit: 612000, grossProfitRate: 29.1, orderDate: '2025-01-10' }, | 
 |  |  |   { orderNo: 'SO202501003', customerName: 'æ±èå·¥ç¨éå¢', productName: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', quantity: 4500, salesPrice: 360, costPrice: 250, salesAmount: 1620000, costAmount: 1125000, grossProfit: 495000, grossProfitRate: 30.6, orderDate: '2025-01-08' }, | 
 |  |  |   { orderNo: 'SO202412025', customerName: 'é¿æ±æ··ååå
¬å¸', productName: 'P.S 32.5ç¿æ¸£ç¡
é
¸çæ°´æ³¥', quantity: 8000, salesPrice: 290, costPrice: 215, salesAmount: 2320000, costAmount: 1720000, grossProfit: 600000, grossProfitRate: 25.9, orderDate: '2024-12-28' } | 
 |  |  | ]) | 
 |  |  |  | 
 |  |  | const profitPagination = reactive({ | 
 |  |  |   total: 6, | 
 |  |  |   currentPage: 1, | 
 |  |  |   pageSize: 10 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const profitChartRef = ref(null) | 
 |  |  | let profitChart = null | 
 |  |  |  | 
 |  |  | // ========== æ¹æ³ ========== | 
 |  |  |  | 
 |  |  | // ä»·æ ¼çç¥ç¸å
³æ¹æ³ | 
 |  |  | const getStrategyTypeColor = (type) => { | 
 |  |  |   const colorMap = { | 
 |  |  |     'ä¸å±ä»·æ ¼': 'success', | 
 |  |  |     'é¶æ¢¯æ¥ä»·': 'primary', | 
 |  |  |     'ä¿éææ£': 'warning' | 
 |  |  |   } | 
 |  |  |   return colorMap[type] || 'info' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const searchPriceStrategy = () => { | 
 |  |  |   priceLoading.value = true | 
 |  |  |   setTimeout(() => { | 
 |  |  |     priceLoading.value = false | 
 |  |  |   }, 500) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetPriceSearch = () => { | 
 |  |  |   priceSearchForm.customerName = '' | 
 |  |  |   priceSearchForm.productType = '' | 
 |  |  |   priceSearchForm.strategyType = '' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleAddPriceStrategy = () => { | 
 |  |  |   priceStrategyDialogTitle.value = 'æ°å¢ä»·æ ¼çç¥' | 
 |  |  |   resetPriceStrategyForm() | 
 |  |  |   priceStrategyDialogVisible.value = true | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleViewPriceStrategy = (row) => { | 
 |  |  |   ElMessage.info('æ¥ççç¥è¯¦æ
: ' + row.strategyNo) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleEditPriceStrategy = (row) => { | 
 |  |  |   priceStrategyDialogTitle.value = 'ç¼è¾ä»·æ ¼çç¥' | 
 |  |  |   Object.assign(priceStrategyForm, row) | 
 |  |  |   priceStrategyDialogVisible.value = true | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleDeletePriceStrategy = (row) => { | 
 |  |  |   ElMessageBox.confirm('确认å é¤è¯¥ä»·æ ¼çç¥åï¼', 'æç¤º', { | 
 |  |  |     confirmButtonText: 'ç¡®å®', | 
 |  |  |     cancelButtonText: 'åæ¶', | 
 |  |  |     type: 'warning' | 
 |  |  |   }).then(() => { | 
 |  |  |     ElMessage.success('å é¤æå') | 
 |  |  |   }) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetPriceStrategyForm = () => { | 
 |  |  |   Object.keys(priceStrategyForm).forEach(key => { | 
 |  |  |     if (key === 'basePrice') { | 
 |  |  |       priceStrategyForm[key] = 0 | 
 |  |  |     } else { | 
 |  |  |       priceStrategyForm[key] = '' | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleSavePriceStrategy = () => { | 
 |  |  |   priceStrategyFormRef.value.validate((valid) => { | 
 |  |  |     if (valid) { | 
 |  |  |       ElMessage.success('ä¿åæå') | 
 |  |  |       priceStrategyDialogVisible.value = false | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handlePricePageChange = (val) => { | 
 |  |  |   pricePagination.currentPage = val.page | 
 |  |  |   pricePagination.pageSize = val.limit | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // ååæ§è¡çæ§ç¸å
³æ¹æ³ | 
 |  |  | const getExecutionStatusType = (status) => { | 
 |  |  |   const statusMap = { | 
 |  |  |     'å¾
æ§è¡': 'info', | 
 |  |  |     'æ§è¡ä¸': 'primary', | 
 |  |  |     '已宿': 'success', | 
 |  |  |     'å¼å¸¸': 'danger' | 
 |  |  |   } | 
 |  |  |   return statusMap[status] || 'info' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getProgressColor = (percentage) => { | 
 |  |  |   if (percentage < 30) return '#f56c6c' | 
 |  |  |   if (percentage < 70) return '#e6a23c' | 
 |  |  |   return '#67c23a' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getContractStep = (row) => { | 
 |  |  |   if (row.paymentProgress === 100) return 4 | 
 |  |  |   if (row.invoiceProgress === 100) return 3 | 
 |  |  |   if (row.deliveryProgress === 100) return 2 | 
 |  |  |   if (row.orderStatus === '已宿') return 1 | 
 |  |  |   return 0 | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const searchContract = () => { | 
 |  |  |   contractLoading.value = true | 
 |  |  |   setTimeout(() => { | 
 |  |  |     contractLoading.value = false | 
 |  |  |   }, 500) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetContractSearch = () => { | 
 |  |  |   contractSearchForm.contractNo = '' | 
 |  |  |   contractSearchForm.customerName = '' | 
 |  |  |   contractSearchForm.executionStatus = '' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleViewContract = (row) => { | 
 |  |  |   ElMessage.info('æ¥çåå详æ
: ' + row.contractNo) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleContractPageChange = (val) => { | 
 |  |  |   contractPagination.currentPage = val.page | 
 |  |  |   contractPagination.pageSize = val.limit | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // å岿¯ä»·åæç¸å
³æ¹æ³ | 
 |  |  | const searchPriceComparison = () => { | 
 |  |  |   compareLoading.value = true | 
 |  |  |   setTimeout(() => { | 
 |  |  |     compareLoading.value = false | 
 |  |  |     initPriceChart() | 
 |  |  |   }, 500) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetCompareSearch = () => { | 
 |  |  |   compareSearchForm.productName = '' | 
 |  |  |   compareSearchForm.dateRange = [] | 
 |  |  |   compareSearchForm.region = '' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const initPriceChart = () => { | 
 |  |  |   if (!priceChartRef.value) return | 
 |  |  |    | 
 |  |  |   if (priceChart) { | 
 |  |  |     priceChart.dispose() | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   priceChart = echarts.init(priceChartRef.value) | 
 |  |  |    | 
 |  |  |   const option = { | 
 |  |  |     title: { | 
 |  |  |       text: '水泥价格è¶å¿åæ', | 
 |  |  |       left: 'center' | 
 |  |  |     }, | 
 |  |  |     tooltip: { | 
 |  |  |       trigger: 'axis', | 
 |  |  |       formatter: '{b}<br/>{a}: Â¥{c}/å¨' | 
 |  |  |     }, | 
 |  |  |     legend: { | 
 |  |  |       data: ['P.O 42.5æ®éç¡
é
¸çæ°´æ³¥'], | 
 |  |  |       top: 30 | 
 |  |  |     }, | 
 |  |  |     grid: { | 
 |  |  |       left: '3%', | 
 |  |  |       right: '4%', | 
 |  |  |       bottom: '3%', | 
 |  |  |       containLabel: true | 
 |  |  |     }, | 
 |  |  |     xAxis: { | 
 |  |  |       type: 'category', | 
 |  |  |       boundaryGap: false, | 
 |  |  |       data: ['2024-12-20', '2024-12-28', '2025-01-05', '2025-01-10', '2025-01-15', '2025-01-20'] | 
 |  |  |     }, | 
 |  |  |     yAxis: { | 
 |  |  |       type: 'value', | 
 |  |  |       name: 'ä»·æ ¼(å
/å¨)', | 
 |  |  |       min: 330, | 
 |  |  |       max: 370 | 
 |  |  |     }, | 
 |  |  |     series: [ | 
 |  |  |       { | 
 |  |  |         name: 'P.O 42.5æ®éç¡
é
¸çæ°´æ³¥', | 
 |  |  |         type: 'line', | 
 |  |  |         data: [340, 355, 360, 345, 365, 350], | 
 |  |  |         smooth: true, | 
 |  |  |         itemStyle: { | 
 |  |  |           color: '#409eff' | 
 |  |  |         }, | 
 |  |  |         areaStyle: { | 
 |  |  |           color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | 
 |  |  |             { offset: 0, color: 'rgba(64, 158, 255, 0.3)' }, | 
 |  |  |             { offset: 1, color: 'rgba(64, 158, 255, 0.1)' } | 
 |  |  |           ]) | 
 |  |  |         } | 
 |  |  |       } | 
 |  |  |     ] | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   priceChart.setOption(option) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // å©æ¶¦åæç¸å
³æ¹æ³ | 
 |  |  | const searchProfit = () => { | 
 |  |  |   profitLoading.value = true | 
 |  |  |   setTimeout(() => { | 
 |  |  |     profitLoading.value = false | 
 |  |  |     initProfitChart() | 
 |  |  |   }, 500) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const resetProfitSearch = () => { | 
 |  |  |   profitSearchForm.productType = '' | 
 |  |  |   profitSearchForm.customerName = '' | 
 |  |  |   profitSearchForm.dateRange = [] | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getProfitRateType = (rate) => { | 
 |  |  |   if (rate >= 30) return 'success' | 
 |  |  |   if (rate >= 25) return 'warning' | 
 |  |  |   return 'danger' | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getProfitSummary = (param) => { | 
 |  |  |   const { columns, data } = param | 
 |  |  |   const sums = [] | 
 |  |  |   columns.forEach((column, index) => { | 
 |  |  |     if (index === 0) { | 
 |  |  |       sums[index] = 'å计' | 
 |  |  |       return | 
 |  |  |     } | 
 |  |  |     if (['quantity', 'salesAmount', 'costAmount', 'grossProfit'].includes(column.property)) { | 
 |  |  |       const values = data.map(item => Number(item[column.property])) | 
 |  |  |       if (!values.every(value => isNaN(value))) { | 
 |  |  |         const total = values.reduce((prev, curr) => { | 
 |  |  |           const value = Number(curr) | 
 |  |  |           if (!isNaN(value)) { | 
 |  |  |             return prev + curr | 
 |  |  |           } else { | 
 |  |  |             return prev | 
 |  |  |           } | 
 |  |  |         }, 0) | 
 |  |  |         sums[index] = column.property === 'quantity' ? total.toLocaleString() : 'Â¥' + total.toLocaleString() | 
 |  |  |       } | 
 |  |  |     } else if (column.property === 'grossProfitRate') { | 
 |  |  |       // è®¡ç®å¹³åæ¯å©ç | 
 |  |  |       const totalSales = data.reduce((sum, item) => sum + item.salesAmount, 0) | 
 |  |  |       const totalProfit = data.reduce((sum, item) => sum + item.grossProfit, 0) | 
 |  |  |       sums[index] = ((totalProfit / totalSales) * 100).toFixed(1) + '%' | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  |   return sums | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const initProfitChart = () => { | 
 |  |  |   if (!profitChartRef.value) return | 
 |  |  |    | 
 |  |  |   if (profitChart) { | 
 |  |  |     profitChart.dispose() | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   profitChart = echarts.init(profitChartRef.value) | 
 |  |  |    | 
 |  |  |   const option = { | 
 |  |  |     title: { | 
 |  |  |       text: 'éå®ä¸å©æ¶¦è¶å¿åæ', | 
 |  |  |       left: 'center' | 
 |  |  |     }, | 
 |  |  |     tooltip: { | 
 |  |  |       trigger: 'axis', | 
 |  |  |       axisPointer: { | 
 |  |  |         type: 'cross', | 
 |  |  |         crossStyle: { | 
 |  |  |           color: '#999' | 
 |  |  |         } | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     legend: { | 
 |  |  |       data: ['éå®éé¢', 'ææ¬éé¢', 'æ¯å©æ¶¦', 'æ¯å©ç'], | 
 |  |  |       top: 30 | 
 |  |  |     }, | 
 |  |  |     grid: { | 
 |  |  |       left: '3%', | 
 |  |  |       right: '4%', | 
 |  |  |       bottom: '3%', | 
 |  |  |       containLabel: true | 
 |  |  |     }, | 
 |  |  |     xAxis: [ | 
 |  |  |       { | 
 |  |  |         type: 'category', | 
 |  |  |         data: ['2024-12', '2025-01'], | 
 |  |  |         axisPointer: { | 
 |  |  |           type: 'shadow' | 
 |  |  |         } | 
 |  |  |       } | 
 |  |  |     ], | 
 |  |  |     yAxis: [ | 
 |  |  |       { | 
 |  |  |         type: 'value', | 
 |  |  |         name: 'éé¢(ä¸å
)', | 
 |  |  |         axisLabel: { | 
 |  |  |           formatter: '{value}' | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |       { | 
 |  |  |         type: 'value', | 
 |  |  |         name: 'æ¯å©ç(%)', | 
 |  |  |         min: 0, | 
 |  |  |         max: 40, | 
 |  |  |         axisLabel: { | 
 |  |  |           formatter: '{value}%' | 
 |  |  |         } | 
 |  |  |       } | 
 |  |  |     ], | 
 |  |  |     series: [ | 
 |  |  |       { | 
 |  |  |         name: 'éå®éé¢', | 
 |  |  |         type: 'bar', | 
 |  |  |         data: [820, 950], | 
 |  |  |         itemStyle: { | 
 |  |  |           color: '#409eff' | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |       { | 
 |  |  |         name: 'ææ¬éé¢', | 
 |  |  |         type: 'bar', | 
 |  |  |         data: [605, 670], | 
 |  |  |         itemStyle: { | 
 |  |  |           color: '#e6a23c' | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |       { | 
 |  |  |         name: 'æ¯å©æ¶¦', | 
 |  |  |         type: 'bar', | 
 |  |  |         data: [215, 280], | 
 |  |  |         itemStyle: { | 
 |  |  |           color: '#67c23a' | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |       { | 
 |  |  |         name: 'æ¯å©ç', | 
 |  |  |         type: 'line', | 
 |  |  |         yAxisIndex: 1, | 
 |  |  |         data: [26.2, 29.5], | 
 |  |  |         itemStyle: { | 
 |  |  |           color: '#f56c6c' | 
 |  |  |         } | 
 |  |  |       } | 
 |  |  |     ] | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   profitChart.setOption(option) | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const handleProfitPageChange = (val) => { | 
 |  |  |   profitPagination.currentPage = val.page | 
 |  |  |   profitPagination.pageSize = val.limit | 
 |  |  | } | 
 |  |  |  | 
 |  |  | // çå½å¨æ | 
 |  |  | onMounted(() => { | 
 |  |  |   // ç»ä»¶æè½½åä¸ç«å³åå§åå¾è¡¨ï¼çå¾
ç¨æ·åæ¢å°å¯¹åºæ ç¾é¡µ | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | // ç嬿 ç¾é¡µåæ¢ | 
 |  |  | watch(activeTab, (newVal) => { | 
 |  |  |   nextTick(() => { | 
 |  |  |     if (newVal === 'priceComparison') { | 
 |  |  |       initPriceChart() | 
 |  |  |     } else if (newVal === 'profitAnalysis') { | 
 |  |  |       initProfitChart() | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const handleTabChange = () => { | 
 |  |  |   // æ ç¾é¡µåæ¢å¤ç | 
 |  |  | } | 
 |  |  | </script> | 
 |  |  |  | 
 |  |  | <style scoped> | 
 |  |  | .strategy-control { | 
 |  |  |   padding: 0; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .main-tabs { | 
 |  |  |   border: none; | 
 |  |  |   box-shadow: none; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .main-tabs :deep(.el-tabs__content) { | 
 |  |  |   padding: 0; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .box-card { | 
 |  |  |   border: none; | 
 |  |  |   box-shadow: none; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .search-row { | 
 |  |  |   margin-bottom: 20px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | /* ç»è®¡å¡çæ ·å¼ */ | 
 |  |  | .stats-row { | 
 |  |  |   margin-bottom: 24px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .stat-card { | 
 |  |  |   display: flex; | 
 |  |  |   align-items: center; | 
 |  |  |   padding: 20px; | 
 |  |  |   background: #fff; | 
 |  |  |   border-radius: 8px; | 
 |  |  |   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .stat-icon { | 
 |  |  |   width: 60px; | 
 |  |  |   height: 60px; | 
 |  |  |   display: flex; | 
 |  |  |   align-items: center; | 
 |  |  |   justify-content: center; | 
 |  |  |   border-radius: 8px; | 
 |  |  |   margin-right: 16px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .stat-content { | 
 |  |  |   flex: 1; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .stat-value { | 
 |  |  |   font-size: 28px; | 
 |  |  |   font-weight: bold; | 
 |  |  |   color: #303133; | 
 |  |  |   margin-bottom: 4px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .stat-label { | 
 |  |  |   font-size: 14px; | 
 |  |  |   color: #909399; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | /* åå详æ
å±å¼æ ·å¼ */ | 
 |  |  | .contract-detail-expand { | 
 |  |  |   padding: 30px 60px; | 
 |  |  |   background: #f5f7fa; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .contract-detail-expand :deep(.el-step__title) { | 
 |  |  |   font-size: 14px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .contract-detail-expand :deep(.el-step__description) { | 
 |  |  |   font-size: 12px; | 
 |  |  |   margin-top: 4px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | /* å©æ¶¦ç»è®¡å¡ç */ | 
 |  |  | .profit-stats-row { | 
 |  |  |   margin-bottom: 24px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-card { | 
 |  |  |   padding: 24px; | 
 |  |  |   background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | 
 |  |  |   border-radius: 12px; | 
 |  |  |   color: #fff; | 
 |  |  |   box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-card:nth-child(2) .profit-card { | 
 |  |  |   background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-card:nth-child(3) .profit-card { | 
 |  |  |   background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-header { | 
 |  |  |   font-size: 14px; | 
 |  |  |   opacity: 0.9; | 
 |  |  |   margin-bottom: 12px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-value { | 
 |  |  |   font-size: 32px; | 
 |  |  |   font-weight: bold; | 
 |  |  |   margin-bottom: 12px; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-highlight { | 
 |  |  |   color: #fff; | 
 |  |  |   text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .profit-footer { | 
 |  |  |   display: flex; | 
 |  |  |   justify-content: space-between; | 
 |  |  |   align-items: center; | 
 |  |  |   font-size: 13px; | 
 |  |  |   opacity: 0.9; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .growth-up { | 
 |  |  |   color: #fff; | 
 |  |  |   font-weight: bold; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .growth-down { | 
 |  |  |   color: #ffd04b; | 
 |  |  |   font-weight: bold; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .cost-rate, .gross-profit-rate { | 
 |  |  |   font-weight: bold; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | /* å¾è¡¨å®¹å¨ */ | 
 |  |  | .chart-container { | 
 |  |  |   margin: 20px 0; | 
 |  |  |   padding: 20px; | 
 |  |  |   background: #fff; | 
 |  |  |   border-radius: 8px; | 
 |  |  |   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); | 
 |  |  | } | 
 |  |  | </style> | 
 |  |  |  |