From fd1ab35c60963b4619be680fb7671c85c6ed0dad Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期二, 27 一月 2026 15:49:46 +0800
Subject: [PATCH] Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New
---
src/views/salesManagement/deliveryLedger/index.vue | 38 +
src/views/basicData/supplierManage/index.vue | 32
src/api/procurementManagement/procurementLedger.js | 8
src/views/collaborativeApproval/approvalProcess/index.vue | 3
src/views/inventoryManagement/stockManagement/Qualified.vue | 5
src/views/salesManagement/salesLedger/index.vue | 149 +++++-
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue | 2
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue | 80 +++
src/views/inventoryManagement/stockManagement/Import.vue | 9
src/views/salesManagement/indicatorStats/index.vue | 537 +++++++++++++++++++++----
src/views/basicData/supplierManage/components/BlacklistTab.vue | 6
src/views/inventoryManagement/stockReport/index.vue | 365 ++++++++--------
src/views/basicData/supplierManage/components/HomeTab.vue | 6
13 files changed, 890 insertions(+), 350 deletions(-)
diff --git a/src/api/procurementManagement/procurementLedger.js b/src/api/procurementManagement/procurementLedger.js
index c9a2da8..5f9df05 100644
--- a/src/api/procurementManagement/procurementLedger.js
+++ b/src/api/procurementManagement/procurementLedger.js
@@ -114,4 +114,12 @@
method: "delete",
data: id,
});
+}
+// 鏌ヨ閲囪喘璇︽儏
+export function getPurchaseByCode(id) {
+ return request({
+ url: "/purchase/ledger/getPurchaseByCode",
+ method: "get",
+ params: id,
+ });
}
\ No newline at end of file
diff --git a/src/views/basicData/supplierManage/components/BlacklistTab.vue b/src/views/basicData/supplierManage/components/BlacklistTab.vue
index 894a286..51df93c 100644
--- a/src/views/basicData/supplierManage/components/BlacklistTab.vue
+++ b/src/views/basicData/supplierManage/components/BlacklistTab.vue
@@ -499,7 +499,7 @@
type: "warning",
})
.then(() => {
- proxy.download("/system/supplier/export", {}, "渚涘簲鍟嗘。妗�.xlsx");
+ proxy.download("/system/supplier/export", { isWhite: 1 }, "渚涘簲鍟嗘。妗�.xlsx");
})
.catch(() => {
proxy.$modal.msg("宸插彇娑�");
@@ -559,6 +559,10 @@
onMounted(() => {
getList();
});
+
+defineExpose({
+ getList,
+});
</script>
diff --git a/src/views/basicData/supplierManage/components/HomeTab.vue b/src/views/basicData/supplierManage/components/HomeTab.vue
index 67e3646..7b90272 100644
--- a/src/views/basicData/supplierManage/components/HomeTab.vue
+++ b/src/views/basicData/supplierManage/components/HomeTab.vue
@@ -505,7 +505,7 @@
type: "warning",
})
.then(() => {
- proxy.download("/system/supplier/export", {}, "渚涘簲鍟嗘。妗�.xlsx");
+ proxy.download("/system/supplier/export", { isWhite: 0 }, "渚涘簲鍟嗘。妗�.xlsx");
})
.catch(() => {
proxy.$modal.msg("宸插彇娑�");
@@ -565,5 +565,9 @@
onMounted(() => {
getList();
});
+
+defineExpose({
+ getList,
+});
</script>
diff --git a/src/views/basicData/supplierManage/index.vue b/src/views/basicData/supplierManage/index.vue
index bb83fcf..d87a45b 100644
--- a/src/views/basicData/supplierManage/index.vue
+++ b/src/views/basicData/supplierManage/index.vue
@@ -1,12 +1,12 @@
<!-- 鍦ㄤ綘鐨勪富椤甸潰涓� -->
<template>
<div class="app-container">
- <el-tabs v-model="activeTab" type="card">
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane label="姝e父渚涘簲鍟�" name="home">
- <HomeTab />
+ <HomeTab ref="homeTab" />
</el-tab-pane>
<el-tab-pane label="榛戝悕鍗�" name="blacklist">
- <BlacklistTab />
+ <BlacklistTab ref="blacklistTab" />
</el-tab-pane>
</el-tabs>
</div>
@@ -27,21 +27,17 @@
activeTab: 'home'
}
},
- watch: {
- activeTab(newVal) {
- if (newVal === 'home') {
- this.$refs.homeTab && this.$refs.homeTab.getList()
- } else if (newVal === 'blacklist') {
- this.$refs.blacklistTab && this.$refs.blacklistTab.getList()
- }
- }
+ methods: {
+ handleTabChange(tabName) {
+ this.activeTab = tabName
+ this.$nextTick(() => {
+ if (tabName === 'home') {
+ this.$refs.homeTab && this.$refs.homeTab.getList && this.$refs.homeTab.getList()
+ } else if (tabName === 'blacklist') {
+ this.$refs.blacklistTab && this.$refs.blacklistTab.getList && this.$refs.blacklistTab.getList()
+ }
+ })
+ },
}
}
</script>
-<style>
-.main-container :deep(.el-tabs__item.is-active) {
- color: #1883f6 !important;
- border-bottom: 2px solid #409EFF;
-}
-
-</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
index 44a0bcd..aad5b23 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -2,7 +2,7 @@
<div>
<el-dialog
v-model="dialogFormVisible"
- :title="operationType === 'add' ? '鏂板瀹℃壒娴佺▼' : '缂栬緫瀹℃壒娴佺▼'"
+ :title="operationType === 'approval' ? '瀹℃壒' : '璇︽儏'"
width="700px"
@close="closeDia"
>
@@ -32,9 +32,9 @@
</el-form-item>
</el-col>
</el-row>
- <el-row v-if="!isQuotationApproval">
+ <el-row v-if="!isQuotationApproval && !isPurchaseApproval">
<el-col :span="24">
- <el-form-item label="瀹℃壒浜嬬敱锛�" prop="approveReason">
+ <el-form-item :label="props.approveType == 5 ? '閲囪喘鍚堝悓鍙凤細' : '瀹℃壒浜嬬敱锛�'" prop="approveReason">
<el-input v-model="form.approveReason" placeholder="璇疯緭鍏�" clearable type="textarea" disabled/>
</el-form-item>
</el-col>
@@ -74,7 +74,7 @@
</el-row>
</el-form>
- <!-- 鎶ヤ环瀹℃壒锛氬睍绀烘姤浠疯鎯咃紙澶嶇敤閿�鍞姤浠封�滄煡鐪嬭鎯呭璇濇鈥濆唴瀹圭粨鏋勶級 -->
+ <!-- 鎶ヤ环瀹℃壒锛氬睍绀烘姤浠疯鎯咃紙澶嶇敤閿�鍞姤浠�"鏌ョ湅璇︽儏瀵硅瘽妗�"鍐呭缁撴瀯锛� -->
<div v-if="isQuotationApproval" style="margin: 10px 0 18px;">
<el-divider content-position="left">鎶ヤ环璇︽儏</el-divider>
<el-skeleton :loading="quotationLoading" animated>
@@ -115,6 +115,53 @@
<div v-if="currentQuotation.remark" style="margin-top: 20px;">
<h4>澶囨敞</h4>
<p>{{ currentQuotation.remark }}</p>
+ </div>
+ </template>
+ </template>
+ </el-skeleton>
+ </div>
+
+ <!-- 閲囪喘瀹℃壒锛氬睍绀洪噰璐鎯� -->
+ <div v-if="isPurchaseApproval" style="margin: 10px 0 18px;">
+ <el-divider content-position="left">閲囪喘璇︽儏</el-divider>
+ <el-skeleton :loading="purchaseLoading" animated>
+ <template #template>
+ <el-skeleton-item variant="h3" style="width: 30%" />
+ <el-skeleton-item variant="text" style="width: 100%" />
+ <el-skeleton-item variant="text" style="width: 100%" />
+ </template>
+ <template #default>
+ <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" description="鏈煡璇㈠埌瀵瑰簲閲囪喘璇︽儏" />
+ <template v-else>
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="閲囪喘鍚堝悓鍙�">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item>
+ <el-descriptions-item label="渚涘簲鍟嗗悕绉�">{{ currentPurchase.supplierName }}</el-descriptions-item>
+ <el-descriptions-item label="椤圭洰鍚嶇О">{{ currentPurchase.projectName }}</el-descriptions-item>
+ <el-descriptions-item label="閿�鍞悎鍚屽彿">{{ currentPurchase.salesContractNo }}</el-descriptions-item>
+ <el-descriptions-item label="绛捐鏃ユ湡">{{ currentPurchase.executionDate }}</el-descriptions-item>
+ <el-descriptions-item label="褰曞叆鏃ユ湡">{{ currentPurchase.entryDate }}</el-descriptions-item>
+ <el-descriptions-item label="浠樻鏂瑰紡">{{ currentPurchase.paymentMethod }}</el-descriptions-item>
+ <el-descriptions-item label="鍚堝悓閲戦" :span="2">
+ <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
+ 楼{{ Number(currentPurchase.contractAmount ?? 0).toFixed(2) }}
+ </span>
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div style="margin-top: 20px;">
+ <h4>浜у搧鏄庣粏</h4>
+ <el-table :data="currentPurchase.productData || []" border style="width: 100%">
+ <el-table-column prop="productCategory" label="浜у搧鍚嶇О" />
+ <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" />
+ <el-table-column prop="unit" label="鍗曚綅" />
+ <el-table-column prop="quantity" label="鏁伴噺" />
+ <el-table-column prop="taxInclusiveUnitPrice" label="鍚◣鍗曚环">
+ <template #default="scope">楼{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
+ </el-table-column>
+ <el-table-column prop="taxInclusiveTotalPrice" label="鍚◣鎬讳环">
+ <template #default="scope">楼{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
+ </el-table-column>
+ </el-table>
</div>
</template>
</template>
@@ -188,6 +235,7 @@
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
+import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance()
@@ -207,7 +255,10 @@
const userList = ref([])
const quotationLoading = ref(false)
const currentQuotation = ref({})
+const purchaseLoading = ref(false)
+const currentPurchase = ref({})
const isQuotationApproval = computed(() => Number(props.approveType) === 6)
+const isPurchaseApproval = computed(() => Number(props.approveType) === 5)
const data = reactive({
form: {
@@ -247,6 +298,7 @@
operationType.value = type;
dialogFormVisible.value = true;
currentQuotation.value = {}
+ currentPurchase.value = {}
userListNoPageByTenantId().then((res) => {
userList.value = res.data;
});
@@ -277,7 +329,7 @@
});
});
- // 鎶ヤ环瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨勨�滄姤浠峰崟鍙封�濆幓鏌ユ姤浠峰垪琛�
+ // 鎶ヤ环瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"鎶ヤ环鍗曞彿"鍘绘煡鎶ヤ环鍒楄〃
if (isQuotationApproval.value) {
const quotationNo = row?.approveReason;
if (quotationNo) {
@@ -287,6 +339,22 @@
currentQuotation.value = records[0] || {}
}).finally(() => {
quotationLoading.value = false
+ })
+ }
+ }
+
+ // 閲囪喘瀹℃壒锛氱敤瀹℃壒浜嬬敱瀛楁鎵胯浇鐨�"閲囪喘鍚堝悓鍙�"鍘绘煡閲囪喘璇︽儏
+ if (isPurchaseApproval.value) {
+ const purchaseContractNumber = row?.approveReason;
+ if (purchaseContractNumber) {
+ purchaseLoading.value = true
+ getPurchaseByCode({ purchaseContractNumber }).then((res) => {
+ currentPurchase.value = res
+ }).catch((err) => {
+ console.error('鏌ヨ閲囪喘璇︽儏澶辫触:', err)
+ proxy.$modal.msgError('鏌ヨ閲囪喘璇︽儏澶辫触')
+ }).finally(() => {
+ purchaseLoading.value = false
})
}
}
@@ -341,6 +409,8 @@
dialogFormVisible.value = false;
quotationLoading.value = false
currentQuotation.value = {}
+ purchaseLoading.value = false
+ currentPurchase.value = {}
emit('close')
};
defineExpose({
diff --git a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
index 67a635c..998fa33 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -35,7 +35,7 @@
</el-row>
<el-row>
<el-col :span="24">
- <el-form-item :label="props.approveType == 5 ? '閲囪喘璇存槑锛�' : '瀹℃壒浜嬬敱锛�'" prop="approveReason">
+ <el-form-item :label="props.approveType == 5 ? '閲囪喘鍚堝悓鍙凤細' : '瀹℃壒浜嬬敱锛�'" prop="approveReason">
<el-input v-model="form.approveReason" placeholder="璇疯緭鍏�" clearable type="textarea" />
</el-form-item>
</el-col>
diff --git a/src/views/collaborativeApproval/approvalProcess/index.vue b/src/views/collaborativeApproval/approvalProcess/index.vue
index 95d97cb..bd281dd 100644
--- a/src/views/collaborativeApproval/approvalProcess/index.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index.vue
@@ -113,6 +113,7 @@
const isLeaveType = currentApproveType.value === 2; // 璇峰亣绠$悊
const isReimburseType = currentApproveType.value === 4; // 鎶ラ攢绠$悊
const isQuotationType = currentApproveType.value === 6; // 鎶ヤ环瀹℃壒
+ const isPurchaseType = currentApproveType.value === 5; // 閲囪喘瀹℃壒
// 鍩虹鍒楅厤缃�
const baseColumns = [
@@ -159,7 +160,7 @@
width: 220
},
{
- label: isQuotationType ? "鎶ヤ环鍗曞彿" : "瀹℃壒浜嬬敱",
+ label: isQuotationType ? "鎶ヤ环鍗曞彿" : isPurchaseType ? "閲囪喘鍚堝悓鍙�" : "瀹℃壒浜嬬敱",
prop: "approveReason",
width: 200
},
diff --git a/src/views/inventoryManagement/stockManagement/Import.vue b/src/views/inventoryManagement/stockManagement/Import.vue
index 7d898e1..2f3ff00 100644
--- a/src/views/inventoryManagement/stockManagement/Import.vue
+++ b/src/views/inventoryManagement/stockManagement/Import.vue
@@ -8,6 +8,7 @@
:disabled="upload.isUploading"
:showTip="true"
@success="handleFileSuccess"
+ :downloadTemplate="downloadTemplate"
/>
<template #footer>
<div class="dialog-footer">
@@ -19,7 +20,7 @@
</template>
<script setup>
-import {computed, reactive} from "vue";
+import {computed, getCurrentInstance, reactive} from "vue";
import { getToken } from "@/utils/auth.js";
import { FileUpload } from "@/components/Upload";
import { ElMessage } from "element-plus";
@@ -27,6 +28,8 @@
defineOptions({
name: "瀵煎叆搴撳瓨",
});
+
+const { proxy } = getCurrentInstance()
const props = defineProps({
visible: {
@@ -80,6 +83,10 @@
}
};
+const downloadTemplate = () => {
+ proxy.download("/stockInventory/downloadStockInventory", {}, "搴撳瓨瀵煎叆妯℃澘.xlsx");
+}
+
const closeModal = () => {
isShow.value = false;
};
diff --git a/src/views/inventoryManagement/stockManagement/Qualified.vue b/src/views/inventoryManagement/stockManagement/Qualified.vue
index 0e78990..2ee39db 100644
--- a/src/views/inventoryManagement/stockManagement/Qualified.vue
+++ b/src/views/inventoryManagement/stockManagement/Qualified.vue
@@ -11,7 +11,6 @@
</div>
<div>
<el-button type="primary" @click="isShowNewModal = true">鏂板搴撳瓨</el-button>
- <el-button @click="importTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
<el-button type="info" plain icon="Upload" @click="isShowImportModal = true">
瀵煎叆搴撳瓨
</el-button>
@@ -161,10 +160,6 @@
}).catch(() => {
proxy.$modal.msg("宸插彇娑�")
})
-}
-
-const importTemplate =() =>{
- proxy.download("/stockInventory/downloadStockInventory", {}, "搴撳瓨瀵煎叆妯℃澘.xlsx");
}
onMounted(() => {
diff --git a/src/views/inventoryManagement/stockReport/index.vue b/src/views/inventoryManagement/stockReport/index.vue
index 0bbfac6..1879ea6 100644
--- a/src/views/inventoryManagement/stockReport/index.vue
+++ b/src/views/inventoryManagement/stockReport/index.vue
@@ -14,17 +14,17 @@
<el-option label="鏈堟姤" value="monthly" />
<el-option label="杩涘嚭瀛樻姤琛�" value="inout" />
</el-select>
-
+
<span class="search_title ml10">鏃堕棿鑼冨洿锛�</span>
- <el-date-picker
- v-if="searchForm.reportType === 'daily'"
- v-model="searchForm.singleDate"
- type="date"
- placeholder="璇烽�夋嫨鏃ユ湡"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- style="width: 200px;"
- />
+ <el-date-picker
+ v-if="searchForm.reportType === 'daily'"
+ v-model="searchForm.singleDate"
+ type="date"
+ placeholder="璇烽�夋嫨鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ style="width: 200px;"
+ />
<el-date-picker
v-else-if="searchForm.reportType === 'monthly'"
v-model="searchForm.monthRange"
@@ -47,99 +47,99 @@
value-format="YYYY-MM-DD"
style="width: 240px;"
/>
-
+
<el-button type="primary" @click="handleQuery" style="margin-left: 10px">
鏌ヨ
</el-button>
<el-button @click="handleReset">閲嶇疆</el-button>
</div>
-
+
<div class="search_right">
-<!-- <el-button type="success" @click="handleExport" icon="Download">-->
-<!-- 瀵煎嚭鎶ヨ〃-->
-<!-- </el-button>-->
+ <!-- <el-button type="success" @click="handleExport" icon="Download">-->
+ <!-- 瀵煎嚭鎶ヨ〃-->
+ <!-- </el-button>-->
</div>
</div>
-<!-- <!– 缁熻鍗$墖 –>-->
-<!-- <div class="stats_cards" v-if="reportData.summary">-->
-<!-- <el-row :gutter="20">-->
-<!-- <el-col :span="6">-->
-<!-- <el-card class="stats_card">-->
-<!-- <div class="stats_content">-->
-<!-- <div class="stats_icon in">-->
-<!-- <el-icon><TrendCharts /></el-icon>-->
-<!-- </div>-->
-<!-- <div class="stats_info">-->
-<!-- <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
-<!-- <div class="stats_label">鎬诲叆搴撻噺</div>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- <el-col :span="6">-->
-<!-- <el-card class="stats_card">-->
-<!-- <div class="stats_content">-->
-<!-- <div class="stats_icon out">-->
-<!-- <el-icon><TrendCharts /></el-icon>-->
-<!-- </div>-->
-<!-- <div class="stats_info">-->
-<!-- <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
-<!-- <div class="stats_label">鎬诲嚭搴撻噺</div>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- <el-col :span="6">-->
-<!-- <el-card class="stats_card">-->
-<!-- <div class="stats_content">-->
-<!-- <div class="stats_icon stock">-->
-<!-- <el-icon><Box /></el-icon>-->
-<!-- </div>-->
-<!-- <div class="stats_info">-->
-<!-- <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
-<!-- <div class="stats_label">褰撳墠搴撳瓨</div>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- <el-col :span="6">-->
-<!-- <el-card class="stats_card">-->
-<!-- <div class="stats_content">-->
-<!-- <div class="stats_icon turnover">-->
-<!-- <el-icon><Refresh /></el-icon>-->
-<!-- </div>-->
-<!-- <div class="stats_info">-->
-<!-- <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
-<!-- <div class="stats_label">鍛ㄨ浆鐜�</div>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- </el-row>-->
-<!-- </div>-->
+ <!-- <!– 缁熻鍗$墖 –>-->
+ <!-- <div class="stats_cards" v-if="reportData.summary">-->
+ <!-- <el-row :gutter="20">-->
+ <!-- <el-col :span="6">-->
+ <!-- <el-card class="stats_card">-->
+ <!-- <div class="stats_content">-->
+ <!-- <div class="stats_icon in">-->
+ <!-- <el-icon><TrendCharts /></el-icon>-->
+ <!-- </div>-->
+ <!-- <div class="stats_info">-->
+ <!-- <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
+ <!-- <div class="stats_label">鎬诲叆搴撻噺</div>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- <el-col :span="6">-->
+ <!-- <el-card class="stats_card">-->
+ <!-- <div class="stats_content">-->
+ <!-- <div class="stats_icon out">-->
+ <!-- <el-icon><TrendCharts /></el-icon>-->
+ <!-- </div>-->
+ <!-- <div class="stats_info">-->
+ <!-- <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
+ <!-- <div class="stats_label">鎬诲嚭搴撻噺</div>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- <el-col :span="6">-->
+ <!-- <el-card class="stats_card">-->
+ <!-- <div class="stats_content">-->
+ <!-- <div class="stats_icon stock">-->
+ <!-- <el-icon><Box /></el-icon>-->
+ <!-- </div>-->
+ <!-- <div class="stats_info">-->
+ <!-- <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
+ <!-- <div class="stats_label">褰撳墠搴撳瓨</div>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- <el-col :span="6">-->
+ <!-- <el-card class="stats_card">-->
+ <!-- <div class="stats_content">-->
+ <!-- <div class="stats_icon turnover">-->
+ <!-- <el-icon><Refresh /></el-icon>-->
+ <!-- </div>-->
+ <!-- <div class="stats_info">-->
+ <!-- <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
+ <!-- <div class="stats_label">鍛ㄨ浆鐜�</div>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- </el-row>-->
+ <!-- </div>-->
-<!-- <!– 鍥捐〃鍖哄煙 –>-->
-<!-- <div class="chart_section" v-if="reportData.chartData">-->
-<!-- <el-row :gutter="20">-->
-<!-- <el-col :span="12">-->
-<!-- <el-card>-->
-<!-- <template #header>-->
-<!-- <span>搴撳瓨瓒嬪娍鍥�</span>-->
-<!-- </template>-->
-<!-- <div ref="trendChart" style="height: 300px;"></div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- <el-col :span="12">-->
-<!-- <el-card>-->
-<!-- <template #header>-->
-<!-- <span>杩涘嚭搴撳姣�</span>-->
-<!-- </template>-->
-<!-- <div ref="comparisonChart" style="height: 300px;"></div>-->
-<!-- </el-card>-->
-<!-- </el-col>-->
-<!-- </el-row>-->
-<!-- </div>-->
+ <!-- <!– 鍥捐〃鍖哄煙 –>-->
+ <!-- <div class="chart_section" v-if="reportData.chartData">-->
+ <!-- <el-row :gutter="20">-->
+ <!-- <el-col :span="12">-->
+ <!-- <el-card>-->
+ <!-- <template #header>-->
+ <!-- <span>搴撳瓨瓒嬪娍鍥�</span>-->
+ <!-- </template>-->
+ <!-- <div ref="trendChart" style="height: 300px;"></div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- <el-col :span="12">-->
+ <!-- <el-card>-->
+ <!-- <template #header>-->
+ <!-- <span>杩涘嚭搴撳姣�</span>-->
+ <!-- </template>-->
+ <!-- <div ref="comparisonChart" style="height: 300px;"></div>-->
+ <!-- </el-card>-->
+ <!-- </el-col>-->
+ <!-- </el-row>-->
+ <!-- </div>-->
<!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
<div class="table_section">
@@ -147,87 +147,88 @@
<template #header>
<span>{{ getTableTitle() }}</span>
</template>
- <el-table
- v-loading="tableLoading"
- :data="reportData.tableData"
- border
- height="400"
- style="width: 100%"
- :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
- >
+ <el-table
+ v-loading="tableLoading"
+ :data="reportData.tableData"
+ border
+ height="400"
+ style="width: 100%"
+ :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+ >
<el-table-column
- align="center"
- label="搴忓彿"
- type="index"
- width="60"
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
/>
- <el-table-column
- label="鍏ュ簱鏃堕棿"
- prop="createTime"
- width="200"
- show-overflow-tooltip
- v-if="!searchForm.reportType === 'inout'"
- />
- <el-table-column
- label="鍏ュ簱鎵规"
- prop="inboundBatches"
- width="240"
- show-overflow-tooltip
- v-if="!searchForm.reportType === 'inout'"
- />
- <el-table-column
- label="浜у搧澶х被"
- prop="productName"
- show-overflow-tooltip
- />
- <el-table-column
- label="瑙勬牸鍨嬪彿"
- prop="model"
- show-overflow-tooltip
- />
- <el-table-column
- label="鍗曚綅"
- prop="unit"
- show-overflow-tooltip
- />
- <el-table-column
- label="鍏ュ簱鏁伴噺"
- prop="totalStockIn"
- align="center"
- v-if="searchForm.reportType === 'inout'"
- />
- <el-table-column
- label="鍏ュ簱鏁伴噺"
- prop="stockInNum"
- align="center"
- v-else
- />
- <el-table-column
- label="鍑哄簱鏁伴噺"
- prop="totalStockOut"
- width="100"
- align="center"
- />
- <el-table-column
- label="鐜板湪搴撳瓨"
- prop="currentStock"
- align="center"
- />
- <el-table-column label="鏉ユ簮"
- prop="recordType"
- v-if="!searchForm.reportType === 'inout'"
- show-overflow-tooltip>
- <template #default="scope">
- {{ getRecordType(scope.row.recordType) }}
- </template>
- </el-table-column>
- <el-table-column
- label="鍏ュ簱浜�"
- prop="createBy"
- width="80"
- v-if="!searchForm.reportType === 'inout'"
- show-overflow-tooltip
- />
+ <el-table-column
+ label="鍏ュ簱鏃堕棿"
+ prop="createTime"
+ width="200"
+ show-overflow-tooltip
+ v-if="searchForm.reportType !== 'inout'"
+ />
+ <el-table-column
+ label="鍏ュ簱鎵规"
+ prop="inboundBatches"
+ width="240"
+ show-overflow-tooltip
+ v-if="searchForm.reportType !== 'inout'"
+ />
+ <el-table-column
+ label="浜у搧澶х被"
+ prop="productName"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="瑙勬牸鍨嬪彿"
+ prop="model"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="鍗曚綅"
+ prop="unit"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="鍏ュ簱鏁伴噺"
+ prop="totalStockIn"
+ align="center"
+ v-if="searchForm.reportType === 'inout'"
+ />
+ <el-table-column
+ label="鍏ュ簱鏁伴噺"
+ prop="stockInNum"
+ align="center"
+ v-else
+ />
+ <el-table-column
+ label="鍑哄簱鏁伴噺"
+ prop="totalStockOut"
+ width="100"
+ align="center"
+ v-if="searchForm.reportType === 'inout'"
+ />
+ <el-table-column
+ label="鐜板湪搴撳瓨"
+ prop="currentStock"
+ align="center"
+ />
+ <el-table-column label="鏉ユ簮"
+ prop="recordType"
+ v-if="searchForm.reportType !== 'inout'"
+ show-overflow-tooltip>
+ <template #default="scope">
+ {{ getRecordType(scope.row.recordType) }}
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="鍏ュ簱浜�"
+ prop="createBy"
+ width="80"
+ v-if="searchForm.reportType !== 'inout'"
+ show-overflow-tooltip
+ />
</el-table>
</el-card>
</div>
@@ -306,7 +307,7 @@
if (!validateSearchForm()) {
return
}
-
+
tableLoading.value = true
try {
const params = getQueryParams()
@@ -324,7 +325,7 @@
// nextTick(() => {
// initCharts()
// })
-
+
}
} catch (error) {
ElMessage.error('鏌ヨ澶辫触锛�' + error.message)
@@ -394,7 +395,7 @@
startDate: "",
endDate: ""
}
-
+
if (searchForm.reportType === 'daily') {
params.reportDate = searchForm.singleDate
} else if (searchForm.reportType === 'monthly') {
@@ -404,7 +405,7 @@
params.startDate = searchForm.dateRange[0]
params.endDate = searchForm.dateRange[1]
}
-
+
return params
}
@@ -426,7 +427,7 @@
if (!validateSearchForm()) {
return
}
-
+
try {
const params = getQueryParams()
// const response = await exportStockReport(params)
@@ -441,7 +442,7 @@
// link.click()
// document.body.removeChild(link)
// window.URL.revokeObjectURL(url)
-
+
// ElMessage.success('瀵煎嚭鎴愬姛')
} catch (error) {
ElMessage.error('瀵煎嚭澶辫触锛�' + error.message)
@@ -451,7 +452,7 @@
// 鍒濆鍖栧浘琛�
const initCharts = () => {
if (!reportData.value.chartData) return
-
+
initTrendChart()
initComparisonChart()
}
@@ -459,7 +460,7 @@
// 鍒濆鍖栬秼鍔垮浘
const initTrendChart = () => {
if (!trendChart.value) return
-
+
const chart = echarts.init(trendChart.value)
const option = {
title: {
@@ -496,7 +497,7 @@
// 鍒濆鍖栧姣斿浘
const initComparisonChart = () => {
if (!comparisonChart.value) return
-
+
const chart = echarts.init(comparisonChart.value)
const option = {
title: {
@@ -543,7 +544,7 @@
onMounted(() => {
const today = new Date()
searchForm.singleDate = today.toISOString().split('T')[0]
-
+
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000)
searchForm.dateRange = [
yesterday.toISOString().split('T')[0],
diff --git a/src/views/salesManagement/deliveryLedger/index.vue b/src/views/salesManagement/deliveryLedger/index.vue
index 688741b..983a3e5 100644
--- a/src/views/salesManagement/deliveryLedger/index.vue
+++ b/src/views/salesManagement/deliveryLedger/index.vue
@@ -51,13 +51,13 @@
link
type="primary"
size="small"
- :disabled="!isApproved(scope.row.status)"
+ :disabled="isApproving(scope.row.status)"
@click="openForm('edit', scope.row)">缂栬緫</el-button>
<el-button
link
type="danger"
size="small"
- :disabled="!isApproved(scope.row.status)"
+ :disabled="isApproving(scope.row.status)"
@click="handleDeleteSingle(scope.row)">鍒犻櫎</el-button>
</template>
</el-table-column>
@@ -284,9 +284,9 @@
// 鎵撳紑寮规
const openForm = async (type, row) => {
- // 缂栬緫鏃舵鏌ュ鏍哥姸鎬�
- if (type === 'edit' && row && !isApproved(row.status)) {
- proxy.$modal.msgWarning("鍙兘缂栬緫瀹℃牳閫氳繃鐨勬暟鎹�");
+ // 缂栬緫鏃舵鏌ュ鏍哥姸鎬侊紝鍙湁瀹℃牳涓笉鑳界紪杈�
+ if (type === 'edit' && row && isApproving(row.status)) {
+ proxy.$modal.msgWarning("瀹℃牳涓殑鏁版嵁涓嶈兘缂栬緫");
return;
}
@@ -430,10 +430,10 @@
return;
}
- // 妫�鏌ラ�変腑鐨勮鏄惁閮芥槸"瀹℃牳閫氳繃"鐘舵��
- const notApprovedRows = selectedRows.value.filter(row => !isApproved(row.status));
- if (notApprovedRows.length > 0) {
- proxy.$modal.msgWarning("鍙兘鍒犻櫎瀹℃牳閫氳繃鐨勬暟鎹�");
+ // 妫�鏌ラ�変腑鐨勮鏄惁鏈�"瀹℃牳涓�"鐘舵��
+ const approvingRows = selectedRows.value.filter(row => isApproving(row.status));
+ if (approvingRows.length > 0) {
+ proxy.$modal.msgWarning("瀹℃牳涓殑鏁版嵁涓嶈兘鍒犻櫎");
return;
}
@@ -456,9 +456,9 @@
// 鍗曚釜鍒犻櫎
const handleDeleteSingle = (row) => {
- // 妫�鏌ユ槸鍚︿负"瀹℃牳閫氳繃"鐘舵��
- if (!isApproved(row.deliveryLedger)) {
- proxy.$modal.msgWarning("鍙兘鍒犻櫎瀹℃牳閫氳繃鐨勬暟鎹�");
+ // 妫�鏌ユ槸鍚︿负"瀹℃牳涓�"鐘舵��
+ if (isApproving(row.status)) {
+ proxy.$modal.msgWarning("瀹℃牳涓殑鏁版嵁涓嶈兘鍒犻櫎");
return;
}
@@ -635,6 +635,20 @@
return statusStr === '瀹℃牳閫氳繃' || statusStr === '3';
};
+// 妫�鏌ュ鏍哥姸鎬佹槸鍚︿负"瀹℃牳涓�"
+const isApproving = (status) => {
+ if (status === null || status === undefined || status === '') {
+ return false;
+ }
+ // 濡傛灉鏄暟瀛楋紝1 琛ㄧず瀹℃牳涓�
+ if (typeof status === 'number') {
+ return status === 1;
+ }
+ // 濡傛灉鏄瓧绗︿覆
+ const statusStr = String(status).trim();
+ return statusStr === '瀹℃牳涓�' || statusStr === '1';
+};
+
onMounted(() => {
getList();
});
diff --git a/src/views/salesManagement/indicatorStats/index.vue b/src/views/salesManagement/indicatorStats/index.vue
index 65dae96..8cbeb24 100644
--- a/src/views/salesManagement/indicatorStats/index.vue
+++ b/src/views/salesManagement/indicatorStats/index.vue
@@ -1,82 +1,161 @@
<template>
<div class="app-container indicator-stats">
- <el-card class="box-card">
- <!-- KPI 姹囨�� -->
- <el-row :gutter="20" class="stats-row">
- <el-col :span="8">
- <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">{{ indicatorKpis.orderCount.toLocaleString() }}</div>
- <div class="stat-label">璁㈠崟鏁伴噺</div>
+ <!-- KPI 姹囨�� -->
+ <el-row :gutter="20" class="stats-row">
+ <el-col :xs="24" :sm="12" :md="8">
+ <div class="stat-card stat-card-blue">
+ <div class="stat-icon-wrapper">
+ <div class="stat-icon">
+ <el-icon :size="32"><Document /></el-icon>
</div>
</div>
- </el-col>
- <el-col :span="8">
- <div class="stat-card">
- <div class="stat-icon" style="background: #f0f9ff;">
- <el-icon :size="30" color="#67c23a"><Tickets /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">楼{{ indicatorKpis.salesAmount.toLocaleString() }}</div>
- <div class="stat-label">閿�鍞</div>
+ <div class="stat-content">
+ <div class="stat-value">{{ indicatorKpis.orderCount.toLocaleString() }}</div>
+ <div class="stat-label">璁㈠崟鏁伴噺</div>
+ </div>
+ <div class="stat-bg-decoration"></div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="8">
+ <div class="stat-card stat-card-green">
+ <div class="stat-icon-wrapper">
+ <div class="stat-icon">
+ <el-icon :size="32"><Tickets /></el-icon>
</div>
</div>
- </el-col>
- <el-col :span="8">
- <div class="stat-card">
- <div class="stat-icon" style="background: #fef0f0;">
- <el-icon :size="30" color="#e6a23c"><Van /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">{{ indicatorKpis.shipRate }}%</div>
- <div class="stat-label">鍙戣揣鐜�</div>
+ <div class="stat-content">
+ <div class="stat-value">楼{{ indicatorKpis.salesAmount.toLocaleString() }}</div>
+ <div class="stat-label">閿�鍞</div>
+ </div>
+ <div class="stat-bg-decoration"></div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="8">
+ <div class="stat-card stat-card-orange">
+ <div class="stat-icon-wrapper">
+ <div class="stat-icon">
+ <el-icon :size="32"><Van /></el-icon>
</div>
</div>
- </el-col>
- </el-row>
+ <div class="stat-content">
+ <div class="stat-value">{{ indicatorKpis.shipRate }}%</div>
+ <div class="stat-label">鍙戣揣鐜�</div>
+ </div>
+ <div class="stat-bg-decoration"></div>
+ </div>
+ </el-col>
+ </el-row>
- <!-- 缁村害绛涢�� -->
- <el-row :gutter="20" class="search-row">
- <el-col :span="6">
- <el-tree-select v-model="indicatorFilter.productCategory" placeholder="浜у搧绫诲埆" clearable check-strictly
- :data="productOptions" :render-after-expand="false" style="width: 100%" />
- </el-col>
- <el-col :span="6">
- <el-select v-model="indicatorFilter.customerName" placeholder="瀹㈡埛" clearable filterable>
- <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName" />
- </el-select>
- </el-col>
- <el-col :span="6">
- <el-date-picker v-model="indicatorFilter.dateRange" type="daterange" range-separator="鑷�"
- start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" value-format="YYYY-MM-DD" style="width: 100%" />
- </el-col>
- <el-col :span="6" style="text-align: right;">
- <el-button type="primary" @click="applyIndicatorFilter">鏌ヨ</el-button>
- <el-button @click="resetIndicatorFilter">閲嶇疆</el-button>
- </el-col>
- </el-row>
-
- <!-- 鍥捐〃鍖� -->
- <div class="chart-container">
- <div ref="indicatorChartRef" class="chart-wrapper"></div>
+ <!-- 鍥捐〃鍖猴紙鍖呭惈绛涢�夋潯浠讹級 -->
+ <el-card class="chart-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <div class="header-left">
+ <span class="card-title">閿�鍞秼鍔垮垎鏋�</span>
+ <span class="card-subtitle">绛涢�夋潯浠朵粎褰卞搷涓嬫柟鍥捐〃鏁版嵁</span>
+ </div>
+ </div>
+ </template>
+
+ <!-- 鍥捐〃绛涢�夋潯浠� -->
+ <div class="chart-filter-section">
+ <el-row :gutter="16" class="search-row">
+ <el-col :xs="24" :sm="12" :md="6">
+ <div class="filter-item">
+ <label class="filter-label">浜у搧绫诲埆</label>
+ <el-tree-select
+ v-model="indicatorFilter.productCategory"
+ placeholder="璇烽�夋嫨浜у搧绫诲埆"
+ clearable
+ check-strictly
+ :data="productOptions"
+ :render-after-expand="false"
+ style="width: 100%"
+ />
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="6">
+ <div class="filter-item">
+ <label class="filter-label">瀹㈡埛</label>
+ <el-select
+ v-model="indicatorFilter.customerName"
+ placeholder="璇烽�夋嫨瀹㈡埛"
+ clearable
+ filterable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in customerOption"
+ :key="item.id"
+ :label="item.customerName"
+ :value="item.customerName"
+ />
+ </el-select>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="6">
+ <div class="filter-item">
+ <label class="filter-label">鏃ユ湡鑼冨洿</label>
+ <el-date-picker
+ v-model="indicatorFilter.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ />
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="6">
+ <div class="filter-item filter-buttons">
+ <el-button type="primary" :loading="loading" @click="applyIndicatorFilter">
+ <el-icon><Search /></el-icon>
+ 鏌ヨ鍥捐〃
+ </el-button>
+ <el-button @click="resetIndicatorFilter">
+ <el-icon><Refresh /></el-icon>
+ 閲嶇疆
+ </el-button>
+ </div>
+ </el-col>
+ </el-row>
</div>
- <!-- 涓氱哗缁熻锛堝洟闃熺淮搴︼紝鏃犱釜浜哄鍚嶏級 -->
- <el-table v-if="showTeamPerformance" :data="teamPerformanceList" border stripe style="margin-top: 20px;">
- <el-table-column prop="team" label="閿�鍞洟闃�"/>
- <el-table-column prop="orderCount" label="璁㈠崟鏁�"/>
- <el-table-column prop="salesAmount" label="閿�鍞">
+ <!-- 鍥捐〃灞曠ず鍖� -->
+ <div class="chart-container" v-loading="loading">
+ <div ref="indicatorChartRef" class="chart-wrapper"></div>
+ </div>
+ </el-card>
+
+ <!-- 涓氱哗缁熻锛堝洟闃熺淮搴︼紝鏃犱釜浜哄鍚嶏級 -->
+ <el-card v-if="showTeamPerformance" class="table-card" shadow="hover">
+ <template #header>
+ <div class="card-header">
+ <span class="card-title">鍥㈤槦涓氱哗缁熻</span>
+ </div>
+ </template>
+ <el-table
+ :data="teamPerformanceList"
+ border
+ stripe
+ style="width: 100%"
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 'bold' }"
+ >
+ <el-table-column prop="team" label="閿�鍞洟闃�" min-width="120"/>
+ <el-table-column prop="orderCount" label="璁㈠崟鏁�" align="right" min-width="100"/>
+ <el-table-column prop="salesAmount" label="閿�鍞" align="right" min-width="140">
<template #default="scope">楼{{ scope.row.salesAmount.toLocaleString() }}</template>
</el-table-column>
- <el-table-column prop="shipRate" label="鍙戣揣鐜�">
- <template #default="scope">{{ scope.row.shipRate }}</template>
+ <el-table-column prop="shipRate" label="鍙戣揣鐜�" align="right" min-width="100">
+ <template #default="scope">{{ scope.row.shipRate }}%</template>
</el-table-column>
- <el-table-column prop="attainment" label="鐩爣杈炬垚鐜�">
+ <el-table-column prop="attainment" label="鐩爣杈炬垚鐜�" align="center" min-width="120">
<template #default="scope">
- <el-tag :type="scope.row.attainment >= 100 ? 'success' : scope.row.attainment >= 80 ? 'warning' : 'danger'">
+ <el-tag
+ :type="scope.row.attainment >= 100 ? 'success' : scope.row.attainment >= 80 ? 'warning' : 'danger'"
+ effect="dark"
+ >
{{ scope.row.attainment }}%
</el-tag>
</template>
@@ -88,7 +167,7 @@
<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
-import { Document, Van, Tickets } from '@element-plus/icons-vue'
+import { Document, Van, Tickets, Search, Refresh } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import { getTotalStatistics, getStatisticsTable } from '@/api/salesManagement/indicatorStats'
import { productTreeList } from '@/api/basicData/product.js'
@@ -325,10 +404,8 @@
}
const applyIndicatorFilter = async () => {
- await Promise.all([
- fetchTotalStatistics(),
- fetchStatisticsTable()
- ])
+ // 绛涢�夋潯浠跺彧褰卞搷鍥捐〃鏁版嵁锛屼笉褰卞搷KPI姹囨��
+ await fetchStatisticsTable()
}
const resetIndicatorFilter = () => {
@@ -368,31 +445,313 @@
})
</script>
-<style scoped>
+<style scoped lang="scss">
.indicator-stats {
- padding: 0;
+ padding: 20px;
+ background: #f5f7fa;
+ min-height: calc(100vh - 84px);
}
-.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; }
-.chart-container {
- margin: 20px 0;
- padding: 20px;
- background: #fff;
- border-radius: 8px;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+.page-header {
+ margin-bottom: 24px;
+ padding: 20px 0;
+
+ .page-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #303133;
+ margin: 0 0 8px 0;
+ }
+
+ .page-desc {
+ font-size: 14px;
+ color: #909399;
+ margin: 0;
+ }
+}
+
+.stats-row {
+ margin-bottom: 24px;
+}
+
+.stat-card {
+ position: relative;
+ display: flex;
+ align-items: center;
+ padding: 24px;
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ overflow: hidden;
+
+ &:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.12);
+ }
+
+ .stat-icon-wrapper {
+ margin-right: 20px;
+
+ .stat-icon {
+ width: 64px;
+ height: 64px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 12px;
+ transition: all 0.3s ease;
+ }
+ }
+
+ .stat-content {
+ flex: 1;
+ z-index: 1;
+
+ .stat-value {
+ font-size: 32px;
+ font-weight: 700;
+ color: #303133;
+ margin-bottom: 8px;
+ line-height: 1.2;
+ }
+
+ .stat-label {
+ font-size: 14px;
+ color: #909399;
+ font-weight: 500;
+ }
+ }
+
+ .stat-bg-decoration {
+ position: absolute;
+ right: -20px;
+ top: -20px;
+ width: 120px;
+ height: 120px;
+ border-radius: 50%;
+ opacity: 0.1;
+ z-index: 0;
+ }
+
+ &.stat-card-blue {
+ .stat-icon {
+ background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
+ color: #fff;
+ }
+
+ .stat-bg-decoration {
+ background: #409eff;
+ }
+ }
+
+ &.stat-card-green {
+ .stat-icon {
+ background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
+ color: #fff;
+ }
+
+ .stat-bg-decoration {
+ background: #67c23a;
+ }
+ }
+
+ &.stat-card-orange {
+ .stat-icon {
+ background: linear-gradient(135deg, #e6a23c 0%, #ebb563 100%);
+ color: #fff;
+ }
+
+ .stat-bg-decoration {
+ background: #e6a23c;
+ }
+ }
+}
+
+.chart-card,
+.table-card {
+ margin-bottom: 20px;
+ border-radius: 12px;
+ border: none;
+
+ :deep(.el-card__header) {
+ padding: 18px 20px;
+ border-bottom: 1px solid #ebeef5;
+ background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
+ }
+
+ :deep(.el-card__body) {
+ padding: 0;
+ }
+}
+
+.card-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ .header-left {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ .card-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .card-subtitle {
+ font-size: 12px;
+ color: #909399;
+ font-weight: normal;
+ }
+}
+
+.chart-filter-section {
+ padding: 20px;
+ background: #fafbfc;
+ border-bottom: 1px solid #ebeef5;
+ margin-bottom: 0;
+}
+
+.search-row {
+ .filter-item {
+ margin-bottom: 0;
+
+ .filter-label {
+ display: block;
+ font-size: 13px;
+ color: #606266;
+ margin-bottom: 8px;
+ font-weight: 500;
+ }
+
+ &.filter-buttons {
+ display: flex;
+ align-items: flex-end;
+ gap: 10px;
+ padding-top: 28px;
+
+ .el-button {
+ flex: 1;
+ font-size: 14px;
+ }
+ }
+ }
+}
+
+.chart-container {
width: 100%;
overflow: hidden;
+ position: relative;
+ padding: 20px;
+ background: #fff;
+
+ .chart-wrapper {
+ width: 100%;
+ height: 420px;
+ min-width: 0;
+ }
}
-.chart-wrapper {
- width: 100%;
- height: 360px;
- min-width: 0;
+
+.table-card {
+ :deep(.el-table) {
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ :deep(.el-table__header-wrapper) {
+ .el-table__header {
+ th {
+ background: #f5f7fa;
+ color: #606266;
+ font-weight: 600;
+ }
+ }
+ }
+
+ :deep(.el-table__body-wrapper) {
+ .el-table__body {
+ tr:hover {
+ background-color: #f5f7fa;
+ }
+ }
+ }
+}
+
+// 鍝嶅簲寮忚璁�
+@media (max-width: 768px) {
+ .indicator-stats {
+ padding: 12px;
+ }
+
+ .stat-card {
+ padding: 20px;
+
+ .stat-content .stat-value {
+ font-size: 24px;
+ }
+
+ .stat-icon-wrapper .stat-icon {
+ width: 56px;
+ height: 56px;
+ }
+ }
+
+ .chart-filter-section {
+ padding: 16px;
+ }
+
+ .search-row {
+ .filter-item.filter-buttons {
+ padding-top: 0;
+ margin-top: 12px;
+ }
+ }
+
+ .chart-container {
+ padding: 16px;
+
+ .chart-wrapper {
+ height: 320px;
+ }
+ }
+
+ .card-header {
+ .header-left {
+ .card-title {
+ font-size: 15px;
+ }
+
+ .card-subtitle {
+ font-size: 11px;
+ }
+ }
+ }
+}
+
+@media (max-width: 576px) {
+ .page-header {
+ .page-title {
+ font-size: 20px;
+ }
+
+ .page-desc {
+ font-size: 12px;
+ }
+ }
+
+ .stat-card {
+ flex-direction: column;
+ text-align: center;
+
+ .stat-icon-wrapper {
+ margin-right: 0;
+ margin-bottom: 12px;
+ }
+ }
}
</style>
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index f273d54..d9a180f 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -6,10 +6,6 @@
<el-input v-model="searchForm.customerName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
@change="handleQuery" />
</el-form-item>
- <el-form-item label="瀹㈡埛鍚堝悓鍙凤細">
- <el-input v-model="searchForm.customerContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
- @change="handleQuery" />
- </el-form-item>
<el-form-item label="閿�鍞悎鍚屽彿锛�">
<el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
@change="handleQuery" />
@@ -61,14 +57,20 @@
type="danger">涓嶈冻</el-tag>
</template>
</el-table-column>
- <el-table-column label="鍙戣揣鐘舵��" prop="shippingStatus" width="140" align="center" show-overflow-tooltip />
+ <el-table-column label="鍙戣揣鐘舵��" width="140" align="center">
+ <template #default="scope">
+ <el-tag :type="getShippingStatusType(scope.row)" size="small">
+ {{ getShippingStatusText(scope.row) }}
+ </el-tag>
+ </template>
+ </el-table-column>
<el-table-column label="蹇�掑叕鍙�" prop="expressCompany" show-overflow-tooltip />
<el-table-column label="蹇�掑崟鍙�" prop="expressNumber" show-overflow-tooltip />
<el-table-column label="鍙戣揣杞︾墝" minWidth="100px" align="center">
<template #default="scope">
<div>
<el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag>
- <el-tag v-else type="info">鏈彂璐�</el-tag>
+ <el-tag v-else type="info">-</el-tag>
</div>
</template>
</el-table-column>
@@ -94,8 +96,8 @@
<el-button
link
type="primary"
- size="small"
- :disabled="scope.row.approveStatus !== 1 || !!scope.row.shippingDate || !!scope.row.shippingCarNumber"
+ size="small"
+ :disabled="!canShip(scope.row)"
@click="openDeliveryForm(scope.row)">
鍙戣揣
</el-button>
@@ -106,7 +108,6 @@
</el-table-column>
<el-table-column align="center" label="搴忓彿" type="index" width="60" />
<el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
- <el-table-column label="瀹㈡埛鍚堝悓鍙�" prop="customerContractNo" width="180" show-overflow-tooltip />
<el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" width="300" show-overflow-tooltip />
<el-table-column label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
<el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
@@ -148,11 +149,6 @@
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="瀹㈡埛鍚堝悓鍙凤細" prop="customerContractNo">
- <el-input v-model="form.customerContractNo" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
<el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerId">
<el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'">
<el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
@@ -163,17 +159,22 @@
</el-select>
</el-form-item>
</el-col>
+ <el-col :span="12">
+ <el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
+ <el-input v-model="form.projectName" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-col>
</el-row>
<el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
- <el-input v-model="form.projectName" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
- </el-form-item>
- </el-col>
<el-col :span="12">
<el-form-item label="绛捐鏃ユ湡锛�" prop="executionDate">
<el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
format="YYYY-MM-DD" type="date" placeholder="璇烽�夋嫨" clearable :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="浠樻鏂瑰紡">
+ <el-input v-model="form.paymentMethod" placeholder="璇疯緭鍏�" clearable :disabled="operationType === 'view'" />
</el-form-item>
</el-col>
</el-row>
@@ -195,7 +196,6 @@
</el-form-item>
</el-col>
</el-row>
-
<el-row>
<el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
<el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">娣诲姞</el-button>
@@ -1186,19 +1186,15 @@
const openProductForm = async (type, row, index) => {
productOperationType.value = type;
productForm.value = {};
- modelOptions.value = []; // 娓呯┖瑙勬牸鍨嬪彿閫夐」
proxy.resetForm("productFormRef");
-
- // 纭繚浜у搧澶х被鏁版嵁宸插姞杞�
- const options = productOptions.value && productOptions.value.length > 0
- ? productOptions.value
- : await getProductOptions();
-
if (type === "edit") {
productForm.value = { ...row };
productIndex.value = index;
// 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
try {
+ const options = productOptions.value && productOptions.value.length > 0
+ ? productOptions.value
+ : await getProductOptions();
const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
if (categoryId) {
const models = await modelList({ id: categoryId });
@@ -1215,6 +1211,8 @@
// 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
}
+ } else {
+ getProductOptions()
}
productFormVisible.value = true;
};
@@ -1884,6 +1882,92 @@
isCalculating.value = false;
};
/**
+ * 鑾峰彇鍙戣揣鐘舵�佹枃鏈�
+ * @param row 琛屾暟鎹�
+ */
+const getShippingStatusText = (row) => {
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀�"宸插彂璐�"
+ if (row.shippingDate || row.shippingCarNumber) {
+ return '宸插彂璐�';
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+ const status = row.shippingStatus;
+
+ // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓�"寰呭彂璐�"
+ if (status === null || status === undefined || status === '') {
+ return '寰呭彂璐�';
+ }
+
+ // 鐘舵�佹槸瀛楃涓�
+ const statusStr = String(status).trim();
+ const statusTextMap = {
+ '寰呭彂璐�': '寰呭彂璐�',
+ '寰呭鏍�': '寰呭鏍�',
+ '瀹℃牳涓�': '瀹℃牳涓�',
+ '瀹℃牳鎷掔粷': '瀹℃牳鎷掔粷',
+ '瀹℃牳閫氳繃': '瀹℃牳閫氳繃',
+ '宸插彂璐�': '宸插彂璐�'
+ };
+ return statusTextMap[statusStr] || '寰呭彂璐�';
+};
+
+/**
+ * 鑾峰彇鍙戣揣鐘舵�佹爣绛剧被鍨嬶紙棰滆壊锛�
+ * @param row 琛屾暟鎹�
+ */
+const getShippingStatusType = (row) => {
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀虹豢鑹�
+ if (row.shippingDate || row.shippingCarNumber) {
+ return 'success';
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+ const status = row.shippingStatus;
+
+ // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓虹伆鑹诧紙寰呭彂璐э級
+ if (status === null || status === undefined || status === '') {
+ return 'info';
+ }
+
+ // 鐘舵�佹槸瀛楃涓�
+ const statusStr = String(status).trim();
+ const typeTextMap = {
+ '寰呭彂璐�': 'info',
+ '寰呭鏍�': 'info',
+ '瀹℃牳涓�': 'warning',
+ '瀹℃牳鎷掔粷': 'danger',
+ '瀹℃牳閫氳繃': 'success',
+ '宸插彂璐�': 'success'
+ };
+ return typeTextMap[statusStr] || 'info';
+};
+
+/**
+ * 鍒ゆ柇鏄惁鍙互鍙戣揣
+ * 鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐у拰瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣
+ * @param row 琛屾暟鎹�
+ */
+const canShip = (row) => {
+ // 浜у搧鐘舵�佸繀椤绘槸鍏呰冻锛坅pproveStatus === 1锛�
+ if (row.approveStatus !== 1) {
+ return false;
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵��
+ const shippingStatus = row.shippingStatus;
+
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屼笉鑳藉啀娆″彂璐�
+ if (row.shippingDate || row.shippingCarNumber) {
+ return false;
+ }
+
+ // 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
+ const statusStr = shippingStatus ? String(shippingStatus).trim() : '';
+ return statusStr === '寰呭彂璐�' || statusStr === '瀹℃牳鎷掔粷';
+};
+
+/**
* 涓嬭浇鏂囦欢
*
* @param row 涓嬭浇鏂囦欢鐨勭浉鍏充俊鎭璞�
@@ -1900,15 +1984,12 @@
// 鎵撳紑鍙戣揣寮规
const openDeliveryForm = (row) => {
- // 鏍¢獙锛氬彧鏈変骇鍝佺姸鎬佷负鍏呰冻涓旀湭鍙戣揣鏃舵墠鑳藉彂璐�
- if (row.approveStatus !== 1) {
- proxy.$modal.msgWarning("浜у搧鐘舵�佷笉瓒筹紝鏃犳硶鍙戣揣");
+ // 妫�鏌ユ槸鍚﹀彲浠ュ彂璐�
+ if (!canShip(row)) {
+ proxy.$modal.msgWarning("鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐ф垨瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣");
return;
}
- if (row.shippingDate || row.shippingCarNumber) {
- proxy.$modal.msgWarning("璇ヤ骇鍝佸凡鍙戣揣锛屾棤娉曢噸澶嶅彂璐�");
- return;
- }
+
currentDeliveryRow.value = row;
deliveryForm.value = {
type: "璐ц溅",
--
Gitblit v1.9.3