| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # 客æ·å¾æ¥å¤ç»´åº¦æç»åè½å端èè°ææ¡£ |
| | | |
| | | > ä¼å客æ·å¾æ¥åè½ï¼æ°å¢å¤ç»´åº¦æç»æ¥è¯¢æ¥å£ï¼æ¯æäº§åæç»ååè´§æç»ç»´åº¦ |
| | | |
| | | ## æ¶åé¡µé¢ |
| | | |
| | | - è¥é管ç / 客æ·å¾æ¥ - 客æ·å¾æ¥å表页 |
| | | - è¥é管ç / 客æ·å¾æ¥ - 客æ·å¾æ¥è¯¦æ
é¡µï¼æ°å¢ï¼ |
| | | - è¥é管ç / 客æ·å¾æ¥ - 产åæç»Tabï¼æ°å¢ï¼ |
| | | - è¥é管ç / 客æ·å¾æ¥ - åè´§æç»Tabï¼æ°å¢ï¼ |
| | | |
| | | ## API |
| | | |
| | | ### 1. 客æ·å¾æ¥å表ï¼åææ¥å£ï¼æªåæ´ï¼ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /metricStatistics/customewTransactions | 客æ·å¾æ¥å表 | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | pageNum | Long | å¦ | 页ç ï¼é»è®¤1 | |
| | | | pageSize | Long | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | |
| | | | customerName | String | å¦ | 客æ·åç§°ï¼æ¨¡ç³æç´¢ï¼ | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | customerId | Long | 客æ·ID | |
| | | | customerName | String | 客æ·åç§° | |
| | | | contractAmounts | BigDecimal | ååæ»éé¢ | |
| | | | receiptPaymentAmount | BigDecimal | æ¶æ¬¾éé¢ | |
| | | | receiptableAmount | BigDecimal | åºæ¶éé¢ | |
| | | |
| | | --- |
| | | |
| | | ### 1.5 客æ·å¾æ¥æç»ï¼åææ¥å£ï¼æ°å¢åæ®µï¼ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /metricStatistics/customewTransactionsDetails | 客æ·å¾æ¥æç»ï¼ååç»´åº¦ï¼ | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | customerId | Long | æ¯ | 客æ·ID | |
| | | | pageNum | Long | å¦ | 页ç ï¼é»è®¤1 | |
| | | | pageSize | Long | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | salesLedgerId | Long | éå®å°è´¦ID | |
| | | | salesContractNo | String | éå®ååå· | |
| | | | executionDate | LocalDate | ååç¾è®¢æ¥æ | |
| | | | contractAmount | BigDecimal | ååéé¢ | |
| | | | **productNames** | String | **产ååç§°å表ï¼éå·åéï¼ãæ°å¢ã** | |
| | | | receiptPaymentAmount | BigDecimal | æ¶æ¬¾éé¢ | |
| | | | receiptableAmount | BigDecimal | åºæ¶éé¢ | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "æä½æå", |
| | | "data": { |
| | | "records": [ |
| | | { |
| | | "salesLedgerId": 1, |
| | | "salesContractNo": "HT-2026-001", |
| | | "executionDate": "2026-06-01", |
| | | "contractAmount": 50000.00, |
| | | "productNames": "产åA,产åB,产åC", |
| | | "receiptPaymentAmount": 30000.00, |
| | | "receiptableAmount": 20000.00 |
| | | } |
| | | ], |
| | | "total": 10 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 2. 客æ·å¾æ¥ç»è®¡æ±æ»ï¼æ°å¢ï¼ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /metricStatistics/customerTransactionsSummary | 客æ·å¾æ¥ç»è®¡æ±æ» | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | customerId | Long | æ¯ | 客æ·ID | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | customerId | Long | 客æ·ID | |
| | | | customerName | String | 客æ·åç§° | |
| | | | contractAmounts | BigDecimal | ååæ»éé¢ | |
| | | | contractCount | Integer | ååæ°é | |
| | | | productCount | Integer | 产åç§ç±»æ° | |
| | | | shippedAmounts | BigDecimal | åè´§æ»éé¢ | |
| | | | shippedQuantity | BigDecimal | åè´§æ»æ°é | |
| | | | receivedAmounts | BigDecimal | æ¶æ¬¾éé¢ | |
| | | | receivableAmounts | BigDecimal | åºæ¶éé¢ | |
| | | | returnAmounts | BigDecimal | éè´§éé¢ | |
| | | | unshippedAmounts | BigDecimal | æªåè´§éé¢ | |
| | | | receivedRate | BigDecimal | æ¶æ¬¾ç(%) | |
| | | | shippedRate | BigDecimal | åè´§ç(%) | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "æä½æå", |
| | | "data": { |
| | | "customerId": 1, |
| | | "customerName": "客æ·A", |
| | | "contractAmounts": 100000.00, |
| | | "contractCount": 5, |
| | | "productCount": 12, |
| | | "shippedAmounts": 80000.00, |
| | | "shippedQuantity": 500, |
| | | "receivedAmounts": 60000.00, |
| | | "receivableAmounts": 20000.00, |
| | | "returnAmounts": 5000.00, |
| | | "unshippedAmounts": 20000.00, |
| | | "receivedRate": 75.00, |
| | | "shippedRate": 80.00 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 3. 客æ·å¾æ¥äº§åæç»ï¼æ°å¢ï¼ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /metricStatistics/customerTransactionsProducts | 客æ·å¾æ¥äº§åæç» | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | customerId | Long | æ¯ | 客æ·ID | |
| | | | salesLedgerId | Long | å¦ | éå®å°è´¦IDï¼å¯éï¼ç¨äºçéæååï¼ | |
| | | | pageNum | Long | å¦ | 页ç ï¼é»è®¤1 | |
| | | | pageSize | Long | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | salesLedgerId | Long | éå®å°è´¦ID | |
| | | | salesContractNo | String | éå®ååå· | |
| | | | productId | Long | 产åID | |
| | | | productName | String | 产ååç§° | |
| | | | model | String | è§æ ¼åå· | |
| | | | unit | String | åä½ | |
| | | | contractQuantity | BigDecimal | ååæ°é | |
| | | | taxInclusiveUnitPrice | BigDecimal | åååä»·(å«ç¨) | |
| | | | contractAmount | BigDecimal | ååéé¢ | |
| | | | shippedQuantity | BigDecimal | å·²åè´§æ°é | |
| | | | shippedAmount | BigDecimal | å·²åè´§éé¢ | |
| | | | receivedAmount | BigDecimal | å·²æ¶æ¬¾éé¢ | |
| | | | receivableAmount | BigDecimal | åºæ¶éé¢ | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "æä½æå", |
| | | "data": { |
| | | "records": [ |
| | | { |
| | | "salesLedgerId": 1, |
| | | "salesContractNo": "HT-2026-001", |
| | | "productId": 10, |
| | | "productName": "产åA", |
| | | "model": "è§æ ¼1", |
| | | "unit": "ä»¶", |
| | | "contractQuantity": 100, |
| | | "taxInclusiveUnitPrice": 50.00, |
| | | "contractAmount": 5000.00, |
| | | "shippedQuantity": 80, |
| | | "shippedAmount": 4000.00, |
| | | "receivedAmount": 3000.00, |
| | | "receivableAmount": 1000.00 |
| | | } |
| | | ], |
| | | "total": 25, |
| | | "pageNum": 1, |
| | | "pageSize": 10 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 4. 客æ·å¾æ¥åè´§æç»ï¼æ°å¢ï¼ |
| | | |
| | | | æ¹æ³ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | GET | /metricStatistics/customerTransactionsShipments | 客æ·å¾æ¥åè´§æç» | |
| | | |
| | | **请æ±åæ°ï¼** |
| | | |
| | | | åæ° | ç±»å | å¿
å¡« | 说æ | |
| | | |------|------|------|------| |
| | | | customerId | Long | æ¯ | 客æ·ID | |
| | | | salesLedgerId | Long | å¦ | éå®å°è´¦IDï¼å¯éï¼ç¨äºçéæååï¼ | |
| | | | pageNum | Long | å¦ | 页ç ï¼é»è®¤1 | |
| | | | pageSize | Long | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | |
| | | |
| | | **ååºå段ï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | salesLedgerId | Long | éå®å°è´¦ID | |
| | | | salesContractNo | String | éå®ååå· | |
| | | | shippingId | Long | åè´§åID | |
| | | | shippingNo | String | åè´§åå· | |
| | | | productName | String | 产ååç§° | |
| | | | model | String | è§æ ¼åå· | |
| | | | shippingQuantity | BigDecimal | åè´§æ°é | |
| | | | shippingAmount | BigDecimal | åè´§éé¢(å«ç¨) | |
| | | | batchNo | String | åºåºæ¹å· | |
| | | | shippingDate | LocalDate | åè´§æ¥æ | |
| | | | approvalStatus | Integer | 审æ¹ç¶æ(0å¾
审/1已审) | |
| | | | receivedAmount | BigDecimal | å·²æ¶æ¬¾éé¢ | |
| | | | receivableAmount | BigDecimal | åºæ¶éé¢ | |
| | | |
| | | **ååºç¤ºä¾ï¼** |
| | | |
| | | ```json |
| | | { |
| | | "code": 200, |
| | | "msg": "æä½æå", |
| | | "data": { |
| | | "records": [ |
| | | { |
| | | "salesLedgerId": 1, |
| | | "salesContractNo": "HT-2026-001", |
| | | "shippingId": 100, |
| | | "shippingNo": "FH-2026-001", |
| | | "productName": "产åA", |
| | | "model": "è§æ ¼1", |
| | | "shippingQuantity": 50, |
| | | "shippingAmount": 2500.00, |
| | | "batchNo": "20260618001", |
| | | "shippingDate": "2026-06-18", |
| | | "approvalStatus": 1, |
| | | "receivedAmount": 2000.00, |
| | | "receivableAmount": 500.00 |
| | | } |
| | | ], |
| | | "total": 30, |
| | | "pageNum": 1, |
| | | "pageSize": 10 |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## å端页é¢è®¾è®¡ |
| | | |
| | | ### 1. 客æ·å¾æ¥å表页ï¼ä¼åï¼ |
| | | |
| | | ```html |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢æ --> |
| | | <el-form :model="queryParams" ref="queryForm" :inline="true"> |
| | | <el-form-item label="客æ·åç§°" prop="customerName"> |
| | | <el-input v-model="queryParams.customerName" placeholder="请è¾å
¥å®¢æ·åç§°" clearable /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getList">æç´¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- æ°æ®è¡¨æ ¼ --> |
| | | <el-table :data="list" v-loading="loading"> |
| | | <el-table-column label="客æ·åç§°" prop="customerName" /> |
| | | <el-table-column label="ååæ»éé¢" prop="contractAmounts" align="right"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.contractAmounts) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¶æ¬¾éé¢" prop="receiptPaymentAmount" align="right"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.receiptPaymentAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºæ¶éé¢" prop="receiptableAmount" align="right"> |
| | | <template #default="{ row }"> |
| | | <span :class="{ 'text-danger': row.receiptableAmount > 0 }"> |
| | | {{ formatMoney(row.receiptableAmount) }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="150" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="viewDetail(row)">æ¥çæç»</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <el-pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | :page.sync="queryParams.pageNum" |
| | | :limit.sync="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'CustomerTransactions', |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | list: [], |
| | | total: 0, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | customerName: '' |
| | | } |
| | | } |
| | | }, |
| | | created() { |
| | | this.getList() |
| | | }, |
| | | methods: { |
| | | getList() { |
| | | this.loading = true |
| | | this.$axios.get('/metricStatistics/customewTransactions', { params: this.queryParams }) |
| | | .then(res => { |
| | | this.list = res.data.records |
| | | this.total = res.data.total |
| | | }) |
| | | .finally(() => { |
| | | this.loading = false |
| | | }) |
| | | }, |
| | | resetQuery() { |
| | | this.queryParams.customerName = '' |
| | | this.getList() |
| | | }, |
| | | formatMoney(value) { |
| | | if (!value) return '0.00' |
| | | return Number(value).toFixed(2) |
| | | }, |
| | | viewDetail(row) { |
| | | this.$router.push({ path: '/sales/customerTransactions/detail', query: { customerId: row.customerId } }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 2. 客æ·å¾æ¥è¯¦æ
é¡µï¼æ°å¢ï¼ |
| | | |
| | | ```html |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- é¡¶é¨ç»è®¡å¡ç --> |
| | | <el-card class="summary-card"> |
| | | <div slot="header"> |
| | | <span>{{ summary.customerName }} - 徿¥ç»è®¡</span> |
| | | </div> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">ååæ»éé¢</div> |
| | | <div class="stat-value">{{ formatMoney(summary.contractAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">ååæ°é</div> |
| | | <div class="stat-value">{{ summary.contractCount }}份</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">产åç§ç±»</div> |
| | | <div class="stat-value">{{ summary.productCount }}ç§</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">åè´§éé¢</div> |
| | | <div class="stat-value">{{ formatMoney(summary.shippedAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">æ¶æ¬¾éé¢</div> |
| | | <div class="stat-value text-success">{{ formatMoney(summary.receivedAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">åºæ¶éé¢</div> |
| | | <div class="stat-value text-danger">{{ formatMoney(summary.receivableAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20" style="margin-top: 15px;"> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">éè´§éé¢</div> |
| | | <div class="stat-value">{{ formatMoney(summary.returnAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">æªåè´§éé¢</div> |
| | | <div class="stat-value text-warning">{{ formatMoney(summary.unshippedAmounts) }}</div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">æ¶æ¬¾ç</div> |
| | | <div class="stat-value"> |
| | | <el-progress :percentage="summary.receivedRate || 0" :stroke-width="18" /> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <div class="stat-item"> |
| | | <div class="stat-label">åè´§ç</div> |
| | | <div class="stat-value"> |
| | | <el-progress :percentage="summary.shippedRate || 0" :stroke-width="18" color="#67c23a" /> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | </el-card> |
| | | |
| | | <!-- Tab 忢 --> |
| | | <el-tabs v-model="activeTab" @tab-click="handleTabChange"> |
| | | <el-tab-pane label="产åæç»" name="products"> |
| | | <product-table :customerId="customerId" /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="åè´§æç»" name="shipments"> |
| | | <shipment-table :customerId="customerId" /> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="ååæç»" name="contracts"> |
| | | <contract-table :customerId="customerId" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import ProductTable from './components/ProductTable.vue' |
| | | import ShipmentTable from './components/ShipmentTable.vue' |
| | | import ContractTable from './components/ContractTable.vue' |
| | | |
| | | export default { |
| | | name: 'CustomerTransactionsDetail', |
| | | components: { ProductTable, ShipmentTable, ContractTable }, |
| | | data() { |
| | | return { |
| | | customerId: null, |
| | | summary: {}, |
| | | activeTab: 'products' |
| | | } |
| | | }, |
| | | created() { |
| | | this.customerId = this.$route.query.customerId |
| | | if (this.customerId) { |
| | | this.getSummary() |
| | | } |
| | | }, |
| | | methods: { |
| | | getSummary() { |
| | | this.$axios.get('/metricStatistics/customerTransactionsSummary', { |
| | | params: { customerId: this.customerId } |
| | | }).then(res => { |
| | | this.summary = res.data |
| | | }) |
| | | }, |
| | | formatMoney(value) { |
| | | if (!value) return '0.00' |
| | | return Number(value).toFixed(2) |
| | | }, |
| | | handleTabChange(tab) { |
| | | // Tab 忢æ¶å·æ°åç»ä»¶æ°æ® |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .summary-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .stat-item { |
| | | text-align: center; |
| | | } |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | .stat-value { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-top: 5px; |
| | | } |
| | | .text-success { |
| | | color: #67c23a; |
| | | } |
| | | .text-danger { |
| | | color: #f56c6c; |
| | | } |
| | | .text-warning { |
| | | color: #e6a23c; |
| | | } |
| | | </style> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 3. 产åæç»ç»ä»¶ (ProductTable.vue) |
| | | |
| | | ```html |
| | | <template> |
| | | <div> |
| | | <!-- çé --> |
| | | <el-form :inline="true" size="small"> |
| | | <el-form-item label="ååå·"> |
| | | <el-select v-model="filterData.salesLedgerId" clearable placeholder="å
¨é¨åå" @change="getList"> |
| | | <el-option v-for="item in contractList" :key="item.id" :label="item.salesContractNo" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- è¡¨æ ¼ --> |
| | | <el-table :data="list" v-loading="loading" size="small"> |
| | | <el-table-column label="ååå·" prop="salesContractNo" width="150" /> |
| | | <el-table-column label="产ååç§°" prop="productName" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" width="120" /> |
| | | <el-table-column label="åä½" prop="unit" width="80" /> |
| | | <el-table-column label="ååæ°é" prop="contractQuantity" align="right" width="100" /> |
| | | <el-table-column label="åååä»·" prop="taxInclusiveUnitPrice" align="right" width="100"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.taxInclusiveUnitPrice) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ååéé¢" prop="contractAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.contractAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å·²åè´§æ°é" prop="shippedQuantity" align="right" width="100" /> |
| | | <el-table-column label="å·²åè´§éé¢" prop="shippedAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.shippedAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å·²æ¶æ¬¾éé¢" prop="receivedAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | <span class="text-success">{{ formatMoney(row.receivedAmount) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºæ¶éé¢" prop="receivableAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | <span :class="{ 'text-danger': row.receivableAmount > 0 }"> |
| | | {{ formatMoney(row.receivableAmount) }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åè´§è¿åº¦" width="150"> |
| | | <template #default="{ row }"> |
| | | <el-progress |
| | | :percentage="calcPercent(row.shippedQuantity, row.contractQuantity)" |
| | | :stroke-width="10" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <el-pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | :page.sync="queryParams.pageNum" |
| | | :limit.sync="queryParams.pageSize" |
| | | layout="total, prev, pager, next" |
| | | @pagination="getList" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'ProductTable', |
| | | props: { |
| | | customerId: { |
| | | type: Number, |
| | | required: true |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | list: [], |
| | | total: 0, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | customerId: null, |
| | | salesLedgerId: null |
| | | }, |
| | | filterData: { |
| | | salesLedgerId: null |
| | | }, |
| | | contractList: [] |
| | | } |
| | | }, |
| | | watch: { |
| | | customerId(val) { |
| | | if (val) { |
| | | this.queryParams.customerId = val |
| | | this.getList() |
| | | this.getContractList() |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | getList() { |
| | | this.loading = true |
| | | this.queryParams.salesLedgerId = this.filterData.salesLedgerId |
| | | this.$axios.get('/metricStatistics/customerTransactionsProducts', { params: this.queryParams }) |
| | | .then(res => { |
| | | this.list = res.data.records |
| | | this.total = res.data.total |
| | | }) |
| | | .finally(() => { |
| | | this.loading = false |
| | | }) |
| | | }, |
| | | getContractList() { |
| | | // è·å该客æ·çååå表ç¨äºçé |
| | | this.$axios.get('/metricStatistics/customewTransactionsDetails', { |
| | | params: { customerId: this.customerId, pageNum: 1, pageSize: 100 } |
| | | }).then(res => { |
| | | this.contractList = res.data.records |
| | | }) |
| | | }, |
| | | formatMoney(value) { |
| | | if (!value) return '0.00' |
| | | return Number(value).toFixed(2) |
| | | }, |
| | | calcPercent(shipped, total) { |
| | | if (!total || total === 0) return 0 |
| | | return Math.round((shipped / total) * 100) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### 4. åè´§æç»ç»ä»¶ (ShipmentTable.vue) |
| | | |
| | | ```html |
| | | <template> |
| | | <div> |
| | | <!-- çé --> |
| | | <el-form :inline="true" size="small"> |
| | | <el-form-item label="ååå·"> |
| | | <el-select v-model="filterData.salesLedgerId" clearable placeholder="å
¨é¨åå" @change="getList"> |
| | | <el-option v-for="item in contractList" :key="item.id" :label="item.salesContractNo" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- è¡¨æ ¼ --> |
| | | <el-table :data="list" v-loading="loading" size="small"> |
| | | <el-table-column label="ååå·" prop="salesContractNo" width="150" /> |
| | | <el-table-column label="åè´§åå·" prop="shippingNo" width="150" /> |
| | | <el-table-column label="产ååç§°" prop="productName" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" width="120" /> |
| | | <el-table-column label="åè´§æ°é" prop="shippingQuantity" align="right" width="100" /> |
| | | <el-table-column label="åè´§éé¢" prop="shippingAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | {{ formatMoney(row.shippingAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºåºæ¹å·" prop="batchNo" width="150" /> |
| | | <el-table-column label="åè´§æ¥æ" prop="shippingDate" width="120" /> |
| | | <el-table-column label="审æ¹ç¶æ" prop="approvalStatus" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.approvalStatus === 1 ? 'success' : 'warning'" size="mini"> |
| | | {{ row.approvalStatus === 1 ? '已审' : 'å¾
审' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å·²æ¶æ¬¾éé¢" prop="receivedAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | <span class="text-success">{{ formatMoney(row.receivedAmount) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºæ¶éé¢" prop="receivableAmount" align="right" width="120"> |
| | | <template #default="{ row }"> |
| | | <span :class="{ 'text-danger': row.receivableAmount > 0 }"> |
| | | {{ formatMoney(row.receivableAmount) }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å页 --> |
| | | <el-pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | :page.sync="queryParams.pageNum" |
| | | :limit.sync="queryParams.pageSize" |
| | | layout="total, prev, pager, next" |
| | | @pagination="getList" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'ShipmentTable', |
| | | props: { |
| | | customerId: { |
| | | type: Number, |
| | | required: true |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | list: [], |
| | | total: 0, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | customerId: null, |
| | | salesLedgerId: null |
| | | }, |
| | | filterData: { |
| | | salesLedgerId: null |
| | | }, |
| | | contractList: [] |
| | | } |
| | | }, |
| | | watch: { |
| | | customerId(val) { |
| | | if (val) { |
| | | this.queryParams.customerId = val |
| | | this.getList() |
| | | this.getContractList() |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | getList() { |
| | | this.loading = true |
| | | this.queryParams.salesLedgerId = this.filterData.salesLedgerId |
| | | this.$axios.get('/metricStatistics/customerTransactionsShipments', { params: this.queryParams }) |
| | | .then(res => { |
| | | this.list = res.data.records |
| | | this.total = res.data.total |
| | | }) |
| | | .finally(() => { |
| | | this.loading = false |
| | | }) |
| | | }, |
| | | getContractList() { |
| | | this.$axios.get('/metricStatistics/customewTransactionsDetails', { |
| | | params: { customerId: this.customerId, pageNum: 1, pageSize: 100 } |
| | | }).then(res => { |
| | | this.contractList = res.data.records |
| | | }) |
| | | }, |
| | | formatMoney(value) { |
| | | if (!value) return '0.00' |
| | | return Number(value).toFixed(2) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | 1. **è·¯ç±é
ç½®**ï¼éå¨è·¯ç±ä¸æ°å¢å®¢æ·å¾æ¥è¯¦æ
é¡µè·¯ç± `/sales/customerTransactions/detail` |
| | | 2. **ç»ä»¶æå**ï¼äº§åæç»ååè´§æç»å»ºè®®æå为ç¬ç«ç»ä»¶ï¼ä¾¿äºå¤ç¨åç»´æ¤ |
| | | 3. **çéèå¨**ï¼äº§åæç»ååè´§æç»æ¯ææååçéï¼ååå表ä»åææ¥å£è·å |
| | | 4. **æ°æ®æ ¼å¼**ï¼éé¢å段éç»ä¸ä½¿ç¨ `formatMoney` æ¹æ³æ ¼å¼åæ¾ç¤º |
| | | 5. **è¿åº¦æ¡æ¾ç¤º**ï¼äº§åæç»ä¸çåè´§è¿åº¦ä½¿ç¨ `el-progress` ç»ä»¶ç´è§å±ç¤º |
| | | 6. **ç¶ææ è¯**ï¼åºæ¶éé¢å¤§äº0æ¶ä½¿ç¨çº¢è²æ è¯ï¼å·²æ¶æ¬¾ä½¿ç¨ç»¿è²æ è¯ |
| | | 7. **审æ¹ç¶æ**ï¼åè´§æç»ä¸ç审æ¹ç¶æä½¿ç¨ `el-tag` å±ç¤ºï¼å·²å®¡ä¸ºç»¿è²ï¼å¾
审为é»è² |
| | | |
| | | --- |
| | | |
| | | ## æ°æ®å¯¹æ¯ |
| | | |
| | | ### ä¼åå vs ä¼åå |
| | | |
| | | | 维度 | ä¼åå | ä¼åå | |
| | | |------|--------|--------| |
| | | | 客æ·å¾æ¥ | åªæååéé¢ãæ¶æ¬¾ãåºæ¶ | æ°å¢ååæ°ãäº§åæ°ãåè´§çãæ¶æ¬¾çç12é¡¹ææ | |
| | | | æç»ç»´åº¦ | ä»
ååæç» | æ°å¢äº§åæç»ãåè´§æç» | |
| | | | çéè½å | ä»
æå®¢æ·åçé | æ¯ææååçé产å/åè´§æç» | |
| | | | æ°æ®è¿½æº¯ | æ æ³è¿½æº¯å
·ä½åè´§ | å¯è¿½æº¯æ¯æ¡åè´§è®°å½çæ¶æ¬¾æ
åµ | |
| | | | è¿åº¦å±ç¤º | æ | åè´§è¿åº¦æ¡ç´è§å±ç¤º | |