From 01b53033db11aa30ed6d408f6b5c8f27cd851b17 Mon Sep 17 00:00:00 2001
From: yaowanxin <3588231647@qq.com>
Date: 星期五, 09 一月 2026 11:42:03 +0800
Subject: [PATCH] 1.基础数据-供应商黑名单,添加资质管理字段,可上传资质文件 2.采购管理-收货管理-添加入库数量输入和合格状态选择功能,实现采购异常记录的添加和更新接口 3.客户档案-分类功能,零售客户和进销商客户 4.添加采购审批页面,显示台账审批状态 5.固定资产核算界面,库存核算统计页面-移至军泰伟业
---
src/views/basicData/supplierManage/index.vue | 554 ------
src/api/procurementManagement/procurementLedger.js | 9
src/api/procurementManagement/transferManagement.js | 34
src/api/inventoryManagement/stockIn.js | 8
src/views/financialManagement/fixedAssetAccounting/index.vue | 547 +++++++
src/api/basicData/supplierManageFile.js | 25
src/api/equipmentManagement/ledger.js | 8
src/views/basicData/supplierManage/filesDia.vue | 199 ++
src/views/procurementManagement/procurementLedger/index.vue | 97 +
src/views/collaborativeApproval/purchaseApproval/index.vue | 1071 ++++++++++++++
src/views/basicData/customerFile/index.vue | 35
src/views/financialManagement/inventoryAccounting/index.vue | 390 +++++
src/views/basicData/supplierManage/components/BlacklistTab.vue | 564 +++++++
src/views/procurementManagement/transferManagement/index.vue | 434 +++++
src/views/basicData/supplierManage/components/HomeTab.vue | 569 +++++++
15 files changed, 4,000 insertions(+), 544 deletions(-)
diff --git a/src/api/basicData/supplierManageFile.js b/src/api/basicData/supplierManageFile.js
index 3b1ab97..6d3f28b 100644
--- a/src/api/basicData/supplierManageFile.js
+++ b/src/api/basicData/supplierManageFile.js
@@ -49,4 +49,27 @@
data: ids
})
}
-
+// 鏌ヨ闄勪欢鍒楄〃
+export function fileListPage(query) {
+ return request({
+ url: "/basic/supplierManageFile/listPage",
+ method: "get",
+ params: query,
+ });
+}
+// 淇濆瓨闄勪欢鍒楄〃
+export function fileAdd(query) {
+ return request({
+ url: "/basic/supplierManageFile/add",
+ method: "post",
+ data: query,
+ });
+}
+// 鍒犻櫎闄勪欢鍒楄〃
+export function fileDel(query) {
+ return request({
+ url: "/basic/supplierManageFile/del",
+ method: "delete",
+ data: query,
+ });
+}
diff --git a/src/api/equipmentManagement/ledger.js b/src/api/equipmentManagement/ledger.js
index d1b65b0..7e8d8d8 100644
--- a/src/api/equipmentManagement/ledger.js
+++ b/src/api/equipmentManagement/ledger.js
@@ -42,3 +42,11 @@
method: "get",
});
};
+// 璁惧鍙拌处鍥捐〃
+export const getAssetInfo = (params) => {
+ return request({
+ url: "/device/ledger/report/forms",
+ method: "get",
+ params
+ });
+}
\ No newline at end of file
diff --git a/src/api/inventoryManagement/stockIn.js b/src/api/inventoryManagement/stockIn.js
index 70f07a7..c43d2c0 100644
--- a/src/api/inventoryManagement/stockIn.js
+++ b/src/api/inventoryManagement/stockIn.js
@@ -142,5 +142,11 @@
}
-//
+//鏌ヨ搴撳瓨鍥捐〃鏁版嵁
+export function getStockInChartData() {
+ return request({
+ url: '/stockin/listReport',
+ method: 'get'
+ })
+}
diff --git a/src/api/procurementManagement/procurementLedger.js b/src/api/procurementManagement/procurementLedger.js
index de5f811..e1fb72d 100644
--- a/src/api/procurementManagement/procurementLedger.js
+++ b/src/api/procurementManagement/procurementLedger.js
@@ -57,7 +57,7 @@
params: query,
});
}
-
+// 鏌ヨ閲囪喘鍙拌处鍒楄〃
export function purchaseListPage(query) {
return request({
url: "/purchase/ledger/listPage",
@@ -99,3 +99,10 @@
params: query,
});
}
+export function updateApprovalStatus(query) {
+ return request({
+ url: "/purchase/ledger/updateApprovalStatus",
+ method: "post",
+ data: query,
+ });
+}
\ No newline at end of file
diff --git a/src/api/procurementManagement/transferManagement.js b/src/api/procurementManagement/transferManagement.js
new file mode 100644
index 0000000..fa404d1
--- /dev/null
+++ b/src/api/procurementManagement/transferManagement.js
@@ -0,0 +1,34 @@
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ
+export function getPurchaseOrders(query) {
+ return request({
+ url: "/purchase/ledger/listPage",
+ method: "get",
+ params: query,
+ });
+}
+//
+export function confirmReceipt(query) {
+ return request({
+ url: "",
+ method: "post",
+ data: query,
+ });
+}
+// 澧炴坊閲囪喘寮傚父璁板綍
+export function addPurchaseException(query) {
+ return request({
+ url: "/procurementExceptionRecord/add",
+ method: "post",
+ data: query,
+ });
+}
+// 淇敼閲囪喘寮傚父璁板綍
+export function updatePurchaseException(query) {
+ return request({
+ url: "/procurementExceptionRecord/update",
+ method: "post",
+ data: query,
+ });
+}
\ No newline at end of file
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index e5bab03..a961d57 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -5,12 +5,23 @@
<span class="search_title">瀹㈡埛鍚嶇О锛�</span>
<el-input
v-model="searchForm.customerName"
- style="width: 240px"
+ style="width: 240px;margin-right: 10px"
placeholder="璇疯緭鍏�"
@change="handleQuery"
clearable
:prefix-icon="Search"
/>
+ <span class="search_title">瀹㈡埛鍒嗙被锛�</span>
+ <el-select
+ v-model="searchForm.customerType"
+ placeholder="璇烽�夋嫨"
+ style="width: 240px"
+ clearable
+ @change="handleQuery"
+ >
+ <el-option label="闆跺敭瀹㈡埛" value="闆跺敭瀹㈡埛" />
+ <el-option label="杩涢攢鍟嗗鎴�" value="杩涢攢鍟嗗鎴�" />
+ </el-select>
<el-button type="primary" @click="handleQuery" style="margin-left: 10px"
>鎼滅储</el-button
>
@@ -120,6 +131,14 @@
placeholder="璇疯緭鍏�"
clearable
/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="瀹㈡埛鍒嗙被锛�" prop="customerType">
+ <el-select v-model="form.customerType" placeholder="璇烽�夋嫨" clearable>
+ <el-option label="闆跺敭瀹㈡埛" value="闆跺敭瀹㈡埛" />
+ <el-option label="杩涢攢鍟嗗鎴�" value="杩涢攢鍟嗗鎴�" />
+ </el-select>
</el-form-item>
</el-col>
</el-row>
@@ -249,6 +268,11 @@
const tableColumn = ref([
{
+ label: "瀹㈡埛鍒嗙被",
+ prop: "customerType",
+ width: 120,
+ },
+ {
label: "瀹㈡埛鍚嶇О",
prop: "customerName",
width: 220,
@@ -337,6 +361,7 @@
const data = reactive({
searchForm: {
customerName: "",
+ customerType: "",
},
form: {
customerName: "",
@@ -350,6 +375,7 @@
basicBankAccount: "",
bankAccount: "",
bankCode: "",
+ customerType: "",
},
rules: {
customerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -367,6 +393,7 @@
basicBankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
bankAccount: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
bankCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ customerType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
},
});
const upload = reactive({
@@ -557,6 +584,12 @@
const handleDelete = () => {
let ids = [];
if (selectedRows.value.length > 0) {
+ // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+ const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+ if (unauthorizedData.length > 0) {
+ proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+ return;
+ }
ids = selectedRows.value.map((item) => item.id);
} else {
proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
diff --git a/src/views/basicData/supplierManage/components/BlacklistTab.vue b/src/views/basicData/supplierManage/components/BlacklistTab.vue
new file mode 100644
index 0000000..894a286
--- /dev/null
+++ b/src/views/basicData/supplierManage/components/BlacklistTab.vue
@@ -0,0 +1,564 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">渚涘簲鍟嗘。妗堬細</span>
+ <el-input
+ v-model="searchForm.supplierName"
+ style="width: 240px"
+ placeholder="杈撳叆渚涘簲鍟嗗悕绉版悳绱�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ </div>
+ <div>
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </div>
+ </div>
+ <div class="table_list">
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ :tableLoading="tableLoading"
+ @pagination="pagination"
+ ></PIMTable>
+ </div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ :title="operationType === 'add' ? '鏂板渚涘簲鍟嗕俊鎭�' : '缂栬緫渚涘簲鍟嗕俊鎭�'"
+ width="70%"
+ @close="closeDia"
+ >
+ <el-form
+ :model="form"
+ label-width="140px"
+ label-position="top"
+ :rules="rules"
+ ref="formRef"
+ >
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="渚涘簲鍟嗗悕绉帮細" prop="supplierName">
+ <el-input
+ v-model="form.supplierName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="绾崇◣浜鸿瘑鍒彿锛�"
+ prop="taxpayerIdentificationNum"
+ >
+ <el-input
+ v-model="form.taxpayerIdentificationNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鍏徃鍦板潃锛�" prop="companyAddress">
+ <el-input
+ v-model="form.companyAddress"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍏徃鐢佃瘽锛�" prop="companyPhone">
+ <el-input
+ v-model="form.companyPhone"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="寮�鎴疯锛�" prop="bankAccountName">
+ <el-input
+ v-model="form.bankAccountName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璐﹀彿锛�" prop="bankAccountNum">
+ <el-input
+ v-model="form.bankAccountNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴浜猴細" prop="contactUserName">
+ <el-input
+ v-model="form.contactUserName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="contactUserPhone">
+ <el-input
+ v-model="form.contactUserPhone"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="缁存姢浜猴細" prop="maintainUserId">
+ <el-select
+ v-model="form.maintainUserId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ disabled
+ >
+ <el-option
+ v-for="item in userList"
+ :key="item.nickName"
+ :label="item.nickName"
+ :value="item.userId"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="缁存姢鏃堕棿锛�" prop="maintainTime">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.maintainTime"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鏄惁鐧藉悕鍗曪細" prop="isWhite">
+ <el-select v-model="form.isWhite" placeholder="璇烽�夋嫨" clearable>
+ <el-option label="鏄�" :value="0" />
+ <el-option label="鍚�" :value="1" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭</el-button>
+ <el-button @click="closeDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+
+ <!-- 渚涘簲鍟嗗鍏ュ璇濇 -->
+ <el-dialog
+ :title="upload.title"
+ v-model="upload.open"
+ width="400px"
+ append-to-body
+ >
+ <el-upload
+ ref="uploadRef"
+ :limit="1"
+ accept=".xlsx, .xls"
+ :headers="upload.headers"
+ :action="upload.url + '?updateSupport=' + upload.updateSupport"
+ :disabled="upload.isUploading"
+ :on-progress="handleFileUploadProgress"
+ :on-success="handleFileSuccess"
+ :on-error="handleFileError"
+ :auto-upload="false"
+ drag
+ >
+ <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+ <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+ <template #tip>
+ <div class="el-upload__tip text-center">
+ <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+ <el-link
+ type="primary"
+ :underline="false"
+ style="font-size: 12px; vertical-align: baseline"
+ @click="importTemplate"
+ >涓嬭浇妯℃澘</el-link
+ >
+ </div>
+ </template>
+ </el-upload>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
+ <el-button @click="upload.open = false">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ <files-dia ref="filesDia"></files-dia>
+ </div>
+</template>
+
+<script setup>
+import { onMounted, ref } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { delSupplier } from "@/api/basicData/supplierManageFile.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import {
+ addSupplier,
+ getSupplier,
+ listSupplier,
+ updateSupplier,
+} from "@/api/basicData/supplierManageFile.js";
+import useUserStore from "@/store/modules/user";
+import { getToken } from "@/utils/auth.js";
+import FilesDia from "../filesDia.vue";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+ {
+ label: "渚涘簲鍟嗗悕绉�",
+ prop: "supplierName",
+ width: 250,
+ },
+ {
+ label: "绾崇◣浜鸿瘑鍒彿",
+ prop: "taxpayerIdentificationNum",
+ width: 230,
+ },
+ {
+ label: "鍏徃鍦板潃",
+ prop: "companyAddress",
+ width: 220,
+ },
+ {
+ label: "鑱旂郴鏂瑰紡",
+ prop: "companyPhone",
+ width:150
+ },
+ {
+ label: "寮�鎴疯",
+ prop: "bankAccountName",
+ width: 220,
+ },
+ {
+ label: "璐﹀彿",
+ prop: "bankAccountNum",
+ width: 220,
+ },
+ {
+ label: "鑱旂郴浜�",
+ prop: "contactUserName",
+ },
+ {
+ label: "鑱旂郴鐢佃瘽",
+ prop: "contactUserPhone",
+ width: 150,
+ },
+ {
+ label: "缁存姢浜�",
+ prop: "maintainUserName",
+ },
+
+ {
+ label: "缁存姢鏃堕棿",
+ prop: "maintainTime",
+ width:100
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ width: 150,
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm("edit", row);
+ },
+ },
+ {
+ //璧勮川闄勪欢
+ name: "璧勮川鏂囦欢",
+ type: "text",
+ clickFun: (row) => {
+ openFilesFormDia(row)
+ }
+ }
+ ],
+ },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+});
+const filesDia = ref()
+// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+ searchForm: {
+ supplierName: "",
+ },
+ form: {
+ supplierName: "",
+ taxpayerIdentificationNum: "",
+ companyAddress: "",
+ companyPhone: "",
+ bankAccountName: "",
+ bankAccountNum: "",
+ contactUserName: "",
+ contactUserPhone: "",
+ maintainUserId: "",
+ maintainTime: "",
+ isWhite: "",
+ },
+ rules: {
+ supplierName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ taxpayerIdentificationNum: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ companyPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ bankAccountName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ bankAccountNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactUserName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactUserPhone: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ maintainUserId: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ maintainTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+/** 鎻愪氦涓婁紶鏂囦欢 */
+function submitFileForm() {
+ upload.isUploading = true;
+ proxy.$refs["uploadRef"].submit();
+}
+const getList = () => {
+ tableLoading.value = true;
+ listSupplier({ ...searchForm.value, ...page, isWhite: 1 }).then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ });
+};
+const upload = reactive({
+ // 鏄惁鏄剧ず寮瑰嚭灞傦紙渚涘簲鍟嗗鍏ワ級
+ open: false,
+ // 寮瑰嚭灞傛爣棰橈紙渚涘簲鍟嗗鍏ワ級
+ title: "",
+ // 鏄惁绂佺敤涓婁紶
+ isUploading: false,
+ // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
+ updateSupport: 1,
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
+});
+/** 瀵煎叆鎸夐挳鎿嶄綔 */
+function handleImport() {
+ upload.title = "渚涘簲鍟嗗鍏�";
+ upload.open = true;
+}
+/** 涓嬭浇妯℃澘 */
+function importTemplate() {
+ proxy.download("/system/supplier/downloadTemplate", {}, "渚涘簲鍟嗗鍏ユā鏉�.xlsx");
+}
+
+/**鏂囦欢涓婁紶涓鐞� */
+const handleFileUploadProgress = (event, file, fileList) => {
+ upload.isUploading = true;
+};
+
+/** 鏂囦欢涓婁紶鎴愬姛澶勭悊 */
+const handleFileSuccess = (response, file, fileList) => {
+ upload.isUploading = false;
+ if(response.code === 200){
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ upload.open = false;
+ proxy.$refs["uploadRef"].clearFiles();
+ getList();
+ }else if(response.code === 500){
+ proxy.$modal.msgError(response.msg);
+ }else{
+ proxy.$modal.msgWarning(response.msg);
+ }
+};
+
+/** 鏂囦欢涓婁紶澶辫触澶勭悊 */
+const handleFileError = (error, file, fileList) => {
+ upload.isUploading = false;
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ operationType.value = type;
+ form.value = {};
+ form.value.maintainUserId = userStore.id;
+ form.value.maintainTime = getCurrentDate();
+ userListNoPage().then((res) => {
+ userList.value = res.data;
+ });
+ if (type === "edit") {
+ getSupplier(row.id).then((res) => {
+ form.value = { ...res.data };
+ });
+ }
+ dialogFormVisible.value = true;
+};
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+ proxy.$refs["formRef"].validate((valid) => {
+ if (valid) {
+ if (operationType.value === "edit") {
+ submitEdit();
+ } else {
+ submitAdd();
+ }
+ }
+ });
+};
+// 鎻愪氦鏂板
+const submitAdd = () => {
+ addSupplier(form.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
+};
+// 鎻愪氦淇敼
+const submitEdit = () => {
+ updateSupplier(form.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download("/system/supplier/export", {}, "渚涘簲鍟嗘。妗�.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+ const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName);
+ if (unauthorizedData.length > 0) {
+ proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+ return;
+ }
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ tableLoading.value = true;
+ delSupplier(ids)
+ .then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+ const today = new Date();
+ const year = today.getFullYear();
+ const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+ const day = String(today.getDate()).padStart(2, "0");
+ return `${year}-${month}-${day}`;
+}
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = (row) => {
+ nextTick(() => {
+ filesDia.value?.openDialog(row)
+ })
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+
diff --git a/src/views/basicData/supplierManage/components/HomeTab.vue b/src/views/basicData/supplierManage/components/HomeTab.vue
new file mode 100644
index 0000000..67e3646
--- /dev/null
+++ b/src/views/basicData/supplierManage/components/HomeTab.vue
@@ -0,0 +1,569 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <span class="search_title">渚涘簲鍟嗘。妗堬細</span>
+ <el-input
+ v-model="searchForm.supplierName"
+ style="width: 240px"
+ placeholder="杈撳叆渚涘簲鍟嗗悕绉版悳绱�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+ >鎼滅储</el-button
+ >
+ </div>
+ <div>
+ <el-button type="primary" @click="openForm('add')"
+ >鏂板渚涘簲鍟�</el-button
+ >
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ <el-button type="info" plain icon="Upload" @click="handleImport"
+ >瀵煎叆</el-button
+ >
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </div>
+ </div>
+ <div class="table_list">
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ :tableLoading="tableLoading"
+ @pagination="pagination"
+ ></PIMTable>
+ </div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ :title="operationType === 'add' ? '鏂板渚涘簲鍟嗕俊鎭�' : '缂栬緫渚涘簲鍟嗕俊鎭�'"
+ width="70%"
+ @close="closeDia"
+ >
+ <el-form
+ :model="form"
+ label-width="140px"
+ label-position="top"
+ :rules="rules"
+ ref="formRef"
+ >
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="渚涘簲鍟嗗悕绉帮細" prop="supplierName">
+ <el-input
+ v-model="form.supplierName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="绾崇◣浜鸿瘑鍒彿锛�"
+ prop="taxpayerIdentificationNum"
+ >
+ <el-input
+ v-model="form.taxpayerIdentificationNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鍏徃鍦板潃锛�" prop="companyAddress">
+ <el-input
+ v-model="form.companyAddress"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍏徃鐢佃瘽锛�" prop="companyPhone">
+ <el-input
+ v-model="form.companyPhone"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="寮�鎴疯锛�" prop="bankAccountName">
+ <el-input
+ v-model="form.bankAccountName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璐﹀彿锛�" prop="bankAccountNum">
+ <el-input
+ v-model="form.bankAccountNum"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴浜猴細" prop="contactUserName">
+ <el-input
+ v-model="form.contactUserName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="contactUserPhone">
+ <el-input
+ v-model="form.contactUserPhone"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="缁存姢浜猴細" prop="maintainUserId">
+ <el-select
+ v-model="form.maintainUserId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ disabled
+ >
+ <el-option
+ v-for="item in userList"
+ :key="item.nickName"
+ :label="item.nickName"
+ :value="item.userId"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="缁存姢鏃堕棿锛�" prop="maintainTime">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.maintainTime"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鏄惁鐧藉悕鍗曪細" prop="isWhite">
+ <el-select v-model="form.isWhite" placeholder="璇烽�夋嫨" clearable>
+ <el-option label="鏄�" :value="0" />
+ <el-option label="鍚�" :value="1" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭</el-button>
+ <el-button @click="closeDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+
+ <!-- 渚涘簲鍟嗗鍏ュ璇濇 -->
+ <el-dialog
+ :title="upload.title"
+ v-model="upload.open"
+ width="400px"
+ append-to-body
+ >
+ <el-upload
+ ref="uploadRef"
+ :limit="1"
+ accept=".xlsx, .xls"
+ :headers="upload.headers"
+ :action="upload.url + '?updateSupport=' + upload.updateSupport"
+ :disabled="upload.isUploading"
+ :on-progress="handleFileUploadProgress"
+ :on-success="handleFileSuccess"
+ :on-error="handleFileError"
+ :auto-upload="false"
+ drag
+ >
+ <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+ <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+ <template #tip>
+ <div class="el-upload__tip text-center">
+ <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+ <el-link
+ type="primary"
+ :underline="false"
+ style="font-size: 12px; vertical-align: baseline"
+ @click="importTemplate"
+ >涓嬭浇妯℃澘</el-link
+ >
+ </div>
+ </template>
+ </el-upload>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
+ <el-button @click="upload.open = false">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ <files-dia ref="filesDia"></files-dia>
+ </div>
+</template>
+
+<script setup>
+import { onMounted, ref } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { delSupplier } from "@/api/basicData/supplierManageFile.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import {
+ addSupplier,
+ getSupplier,
+ listSupplier,
+ updateSupplier,
+} from "@/api/basicData/supplierManageFile.js";
+import useUserStore from "@/store/modules/user";
+import { getToken } from "@/utils/auth.js";
+import FilesDia from "../filesDia.vue";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+ {
+ label: "渚涘簲鍟嗗悕绉�",
+ prop: "supplierName",
+ width: 250,
+ },
+ {
+ label: "绾崇◣浜鸿瘑鍒彿",
+ prop: "taxpayerIdentificationNum",
+ width: 230,
+ },
+ {
+ label: "鍏徃鍦板潃",
+ prop: "companyAddress",
+ width: 220,
+ },
+ {
+ label: "鑱旂郴鏂瑰紡",
+ prop: "companyPhone",
+ width:150
+ },
+ {
+ label: "寮�鎴疯",
+ prop: "bankAccountName",
+ width: 220,
+ },
+ {
+ label: "璐﹀彿",
+ prop: "bankAccountNum",
+ width: 220,
+ },
+ {
+ label: "鑱旂郴浜�",
+ prop: "contactUserName",
+ },
+ {
+ label: "鑱旂郴鐢佃瘽",
+ prop: "contactUserPhone",
+ width: 150,
+ },
+ {
+ label: "缁存姢浜�",
+ prop: "maintainUserName",
+ },
+
+ {
+ label: "缁存姢鏃堕棿",
+ prop: "maintainTime",
+ width:100
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: 'right',
+ width: 150,
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm("edit", row);
+ },
+ },
+ {
+ //璧勮川闄勪欢
+ name: "璧勮川鏂囦欢",
+ type: "text",
+ clickFun: (row) => {
+ openFilesFormDia(row)
+ }
+ }
+ ],
+ },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+});
+const filesDia = ref()
+// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+ searchForm: {
+ supplierName: "",
+ },
+ form: {
+ supplierName: "",
+ taxpayerIdentificationNum: "",
+ companyAddress: "",
+ companyPhone: "",
+ bankAccountName: "",
+ bankAccountNum: "",
+ contactUserName: "",
+ contactUserPhone: "",
+ maintainUserId: "",
+ maintainTime: "",
+ isWhite: "",
+ },
+ rules: {
+ supplierName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ taxpayerIdentificationNum: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ companyPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ bankAccountName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ bankAccountNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactUserName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactUserPhone: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ maintainUserId: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ maintainTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+/** 鎻愪氦涓婁紶鏂囦欢 */
+function submitFileForm() {
+ upload.isUploading = true;
+ proxy.$refs["uploadRef"].submit();
+}
+const getList = () => {
+ tableLoading.value = true;
+ listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then((res) => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ });
+};
+const upload = reactive({
+ // 鏄惁鏄剧ず寮瑰嚭灞傦紙渚涘簲鍟嗗鍏ワ級
+ open: false,
+ // 寮瑰嚭灞傛爣棰橈紙渚涘簲鍟嗗鍏ワ級
+ title: "",
+ // 鏄惁绂佺敤涓婁紶
+ isUploading: false,
+ // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
+ updateSupport: 1,
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
+});
+/** 瀵煎叆鎸夐挳鎿嶄綔 */
+function handleImport() {
+ upload.title = "渚涘簲鍟嗗鍏�";
+ upload.open = true;
+}
+/** 涓嬭浇妯℃澘 */
+function importTemplate() {
+ proxy.download("/system/supplier/downloadTemplate", {}, "渚涘簲鍟嗗鍏ユā鏉�.xlsx");
+}
+
+/**鏂囦欢涓婁紶涓鐞� */
+const handleFileUploadProgress = (event, file, fileList) => {
+ upload.isUploading = true;
+};
+
+/** 鏂囦欢涓婁紶鎴愬姛澶勭悊 */
+const handleFileSuccess = (response, file, fileList) => {
+ upload.isUploading = false;
+ if(response.code === 200){
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ upload.open = false;
+ proxy.$refs["uploadRef"].clearFiles();
+ getList();
+ }else if(response.code === 500){
+ proxy.$modal.msgError(response.msg);
+ }else{
+ proxy.$modal.msgWarning(response.msg);
+ }
+};
+
+/** 鏂囦欢涓婁紶澶辫触澶勭悊 */
+const handleFileError = (error, file, fileList) => {
+ upload.isUploading = false;
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ operationType.value = type;
+ form.value = {};
+ form.value.maintainUserId = userStore.id;
+ form.value.maintainTime = getCurrentDate();
+ userListNoPage().then((res) => {
+ userList.value = res.data;
+ });
+ if (type === "edit") {
+ getSupplier(row.id).then((res) => {
+ form.value = { ...res.data };
+ });
+ }
+ dialogFormVisible.value = true;
+};
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+ proxy.$refs["formRef"].validate((valid) => {
+ if (valid) {
+ if (operationType.value === "edit") {
+ submitEdit();
+ } else {
+ submitAdd();
+ }
+ }
+ });
+};
+// 鎻愪氦鏂板
+const submitAdd = () => {
+ addSupplier(form.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
+};
+// 鎻愪氦淇敼
+const submitEdit = () => {
+ updateSupplier(form.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download("/system/supplier/export", {}, "渚涘簲鍟嗘。妗�.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+ const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName);
+ if (unauthorizedData.length > 0) {
+ proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+ return;
+ }
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ tableLoading.value = true;
+ delSupplier(ids)
+ .then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+ const today = new Date();
+ const year = today.getFullYear();
+ const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+ const day = String(today.getDate()).padStart(2, "0");
+ return `${year}-${month}-${day}`;
+}
+// 鎵撳紑闄勪欢寮规
+const openFilesFormDia = (row) => {
+ nextTick(() => {
+ filesDia.value?.openDialog(row)
+ })
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
diff --git a/src/views/basicData/supplierManage/filesDia.vue b/src/views/basicData/supplierManage/filesDia.vue
new file mode 100644
index 0000000..6284d6b
--- /dev/null
+++ b/src/views/basicData/supplierManage/filesDia.vue
@@ -0,0 +1,199 @@
+<template>
+ <div>
+ <el-dialog
+ v-model="dialogFormVisible"
+ title="涓婁紶闄勪欢"
+ width="50%"
+ @close="closeDia"
+ >
+ <div style="margin-bottom: 10px;text-align: right">
+ <el-upload
+ v-model:file-list="fileList"
+ class="upload-demo"
+ :action="uploadUrl"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ name="file"
+ :show-file-list="false"
+ :headers="headers"
+ style="display: inline;margin-right: 10px"
+ >
+ <el-button type="primary">涓婁紶闄勪欢</el-button>
+ </el-upload>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </div>
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :tableLoading="tableLoading"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ height="500"
+ >
+ </PIMTable>
+ <pagination
+ style="margin: 10px 0"
+ v-show="total > 0"
+ @pagination="paginationSearch"
+ :total="total"
+ :page="page.current"
+ :limit="page.size"
+ />
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button @click="closeDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ <filePreview ref="filePreviewRef" />
+ </div>
+</template>
+
+<script setup>
+import {ref} from "vue";
+import {ElMessageBox} from "element-plus";
+import {getToken} from "@/utils/auth.js";
+import filePreview from '@/components/filePreview/index.vue'
+import {
+ fileAdd,
+ fileDel,
+ fileListPage
+} from "@/api/basicData/supplierManageFile.js";
+import Pagination from "@/components/PIMTable/Pagination.vue";
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+
+const dialogFormVisible = ref(false);
+const currentId = ref('')
+const selectedRows = ref([]);
+const filePreviewRef = ref()
+const tableColumn = ref([
+ {
+ label: "鏂囦欢鍚嶇О",
+ prop: "name",
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ operation: [
+ {
+ name: "涓嬭浇",
+ type: "text",
+ clickFun: (row) => {
+ downLoadFile(row);
+ },
+ },
+ {
+ name: "棰勮",
+ type: "text",
+ clickFun: (row) => {
+ lookFile(row);
+ },
+ }
+ ],
+ },
+]);
+const page = reactive({
+ current: 1,
+ size: 100,
+});
+const total = ref(0);
+const tableData = ref([]);
+const fileList = ref([]);
+const tableLoading = ref(false);
+const headers = ref({
+ Authorization: "Bearer " + getToken(),
+});
+const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+
+// 鎵撳紑寮规
+const openDialog = (row) => {
+ dialogFormVisible.value = true;
+ currentId.value = row.id;
+ getList()
+}
+const paginationSearch = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+const getList = () => {
+ fileListPage({supplierId: currentId.value, ...page}).then(res => {
+ tableData.value = res.data.records;
+ total.value = res.data.total;
+ })
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 鍏抽棴寮规
+const closeDia = () => {
+ dialogFormVisible.value = false;
+ emit('close')
+};
+// 涓婁紶鎴愬姛澶勭悊
+function handleUploadSuccess(res, file) {
+ // 濡傛灉涓婁紶鎴愬姛
+ if (res.code == 200) {
+ const fileRow = {}
+ fileRow.name = res.data.originalName
+ fileRow.url = res.data.tempPath
+ uploadFile(fileRow)
+ } else {
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+ }
+}
+function uploadFile(file) {
+ file.supplierId = currentId.value;
+ fileAdd(file).then(res => {
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ getList()
+ })
+}
+// 涓婁紶澶辫触澶勭悊
+function handleUploadError() {
+ proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
+}
+// 涓嬭浇闄勪欢
+const downLoadFile = (row) => {
+ proxy.$download.name(row.url);
+}
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(() => {
+ fileDel(ids).then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ });
+ }).catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 棰勮闄勪欢
+const lookFile = (row) => {
+ filePreviewRef.value.open(row.url)
+}
+
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/basicData/supplierManage/index.vue b/src/views/basicData/supplierManage/index.vue
index 7cb29bd..963a3db 100644
--- a/src/views/basicData/supplierManage/index.vue
+++ b/src/views/basicData/supplierManage/index.vue
@@ -1,538 +1,38 @@
+<!-- 鍦ㄤ綘鐨勪富椤甸潰涓� -->
<template>
<div class="app-container">
- <div class="search_form">
- <div>
- <span class="search_title">渚涘簲鍟嗘。妗堬細</span>
- <el-input
- v-model="searchForm.supplierName"
- style="width: 240px"
- placeholder="杈撳叆渚涘簲鍟嗗悕绉版悳绱�"
- @change="handleQuery"
- clearable
- :prefix-icon="Search"
- />
- <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
- >鎼滅储</el-button
- >
- </div>
- <div>
- <el-button type="primary" @click="openForm('add')"
- >鏂板渚涘簲鍟�</el-button
- >
- <el-button @click="handleOut">瀵煎嚭</el-button>
- <el-button type="info" plain icon="Upload" @click="handleImport"
- >瀵煎叆</el-button
- >
- <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
- </div>
- </div>
- <div class="table_list">
- <PIMTable
- rowKey="id"
- :column="tableColumn"
- :tableData="tableData"
- :page="page"
- :isSelection="true"
- @selection-change="handleSelectionChange"
- :tableLoading="tableLoading"
- @pagination="pagination"
- ></PIMTable>
- </div>
- <el-dialog
- v-model="dialogFormVisible"
- :title="operationType === 'add' ? '鏂板渚涘簲鍟嗕俊鎭�' : '缂栬緫渚涘簲鍟嗕俊鎭�'"
- width="70%"
- @close="closeDia"
- >
- <el-form
- :model="form"
- label-width="140px"
- label-position="top"
- :rules="rules"
- ref="formRef"
- >
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="渚涘簲鍟嗗悕绉帮細" prop="supplierName">
- <el-input
- v-model="form.supplierName"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item
- label="绾崇◣浜鸿瘑鍒彿锛�"
- prop="taxpayerIdentificationNum"
- >
- <el-input
- v-model="form.taxpayerIdentificationNum"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍏徃鍦板潃锛�" prop="companyAddress">
- <el-input
- v-model="form.companyAddress"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鍏徃鐢佃瘽锛�" prop="companyPhone">
- <el-input
- v-model="form.companyPhone"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="寮�鎴疯锛�" prop="bankAccountName">
- <el-input
- v-model="form.bankAccountName"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="璐﹀彿锛�" prop="bankAccountNum">
- <el-input
- v-model="form.bankAccountNum"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鑱旂郴浜猴細" prop="contactUserName">
- <el-input
- v-model="form.contactUserName"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="contactUserPhone">
- <el-input
- v-model="form.contactUserPhone"
- placeholder="璇疯緭鍏�"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="缁存姢浜猴細" prop="maintainUserId">
- <el-select
- v-model="form.maintainUserId"
- placeholder="璇烽�夋嫨"
- clearable
- filterable
- default-first-option
- :reserve-keyword="false"
- >
- <el-option
- v-for="item in userList"
- :key="item.nickName"
- :label="item.nickName"
- :value="item.userId"
- />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="缁存姢鏃堕棿锛�" prop="maintainTime">
- <el-date-picker
- style="width: 100%"
- v-model="form.maintainTime"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- type="date"
- placeholder="璇烽�夋嫨"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitForm">纭</el-button>
- <el-button @click="closeDia">鍙栨秷</el-button>
- </div>
- </template>
- </el-dialog>
-
- <!-- 渚涘簲鍟嗗鍏ュ璇濇 -->
- <el-dialog
- :title="upload.title"
- v-model="upload.open"
- width="400px"
- append-to-body
- >
- <el-upload
- ref="uploadRef"
- :limit="1"
- accept=".xlsx, .xls"
- :headers="upload.headers"
- :action="upload.url + '?updateSupport=' + upload.updateSupport"
- :disabled="upload.isUploading"
- :on-progress="handleFileUploadProgress"
- :on-success="handleFileSuccess"
- :on-error="handleFileError"
- :auto-upload="false"
- drag
- >
- <el-icon class="el-icon--upload"><upload-filled /></el-icon>
- <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
- <template #tip>
- <div class="el-upload__tip text-center">
- <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
- <el-link
- type="primary"
- :underline="false"
- style="font-size: 12px; vertical-align: baseline"
- @click="importTemplate"
- >涓嬭浇妯℃澘</el-link
- >
- </div>
- </template>
- </el-upload>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
- <el-button @click="upload.open = false">鍙� 娑�</el-button>
- </div>
- </template>
- </el-dialog>
+ <el-tabs v-model="activeTab" type="card">
+ <el-tab-pane label="姝e父渚涘簲鍟�" name="home">
+ <HomeTab />
+ </el-tab-pane>
+ <el-tab-pane label="榛戝悕鍗�" name="blacklist">
+ <BlacklistTab />
+ </el-tab-pane>
+ </el-tabs>
</div>
</template>
-<script setup>
-import { onMounted, ref } from "vue";
-import { Search } from "@element-plus/icons-vue";
-import { delSupplier } from "@/api/basicData/supplierManageFile.js";
-import { ElMessageBox } from "element-plus";
-import { userListNoPage } from "@/api/system/user.js";
-import {
- addSupplier,
- getSupplier,
- listSupplier,
- updateSupplier,
-} from "@/api/basicData/supplierManageFile.js";
-import useUserStore from "@/store/modules/user";
-import { getToken } from "@/utils/auth.js";
-const { proxy } = getCurrentInstance();
-const userStore = useUserStore();
+<script>
+import HomeTab from './components/HomeTab.vue'
+import BlacklistTab from './components/BlacklistTab.vue'
-const tableColumn = ref([
- {
- label: "渚涘簲鍟嗗悕绉�",
- prop: "supplierName",
- width: 250,
+export default {
+ name: 'MainPage',
+ components: {
+ HomeTab,
+ BlacklistTab
},
- {
- label: "绾崇◣浜鸿瘑鍒彿",
- prop: "taxpayerIdentificationNum",
- width: 230,
- },
- {
- label: "鍏徃鍦板潃",
- prop: "companyAddress",
- width: 220,
- },
- {
- label: "鑱旂郴鏂瑰紡",
- prop: "companyPhone",
- width:150
- },
- {
- label: "寮�鎴疯",
- prop: "bankAccountName",
- width: 220,
- },
- {
- label: "璐﹀彿",
- prop: "bankAccountNum",
- width: 220,
- },
- {
- label: "鑱旂郴浜�",
- prop: "contactUserName",
- },
- {
- label: "鑱旂郴鐢佃瘽",
- prop: "contactUserPhone",
- width: 150,
- },
- {
- label: "缁存姢浜�",
- prop: "maintainUserName",
- },
-
- {
- label: "缁存姢鏃堕棿",
- prop: "maintainTime",
- width:100
- },
- {
- dataType: "action",
- label: "鎿嶄綔",
- align: "center",
- fixed: 'right',
- operation: [
- {
- name: "缂栬緫",
- type: "text",
- clickFun: (row) => {
- openForm("edit", row);
- },
- },
- ],
- },
-]);
-const tableData = ref([]);
-const selectedRows = ref([]);
-const userList = ref([]);
-const tableLoading = ref(false);
-const page = reactive({
- current: 1,
- size: 100,
- total: 0,
-});
-
-// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
-const operationType = ref("");
-const dialogFormVisible = ref(false);
-const data = reactive({
- searchForm: {
- supplierName: "",
- },
- form: {
- supplierName: "",
- taxpayerIdentificationNum: "",
- companyAddress: "",
- companyPhone: "",
- bankAccountName: "",
- bankAccountNum: "",
- contactUserName: "",
- contactUserPhone: "",
- maintainUserId: "",
- maintainTime: "",
- },
- rules: {
- supplierName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- taxpayerIdentificationNum: [
- { required: true, message: "璇疯緭鍏�", trigger: "blur" },
- ],
- companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- companyPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- bankAccountName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- bankAccountNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- contactUserName: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
- contactUserPhone: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
- maintainUserId: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
- maintainTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
- },
-});
-const { searchForm, form, rules } = toRefs(data);
-
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
- page.current = 1;
- getList();
-};
-const pagination = (obj) => {
- page.current = obj.page;
- page.size = obj.limit;
- getList();
-};
-/** 鎻愪氦涓婁紶鏂囦欢 */
-function submitFileForm() {
- upload.isUploading = true;
- proxy.$refs["uploadRef"].submit();
-}
-const getList = () => {
- tableLoading.value = true;
- listSupplier({ ...searchForm.value, ...page }).then((res) => {
- tableLoading.value = false;
- tableData.value = res.data.records;
- page.total = res.data.total;
- });
-};
-const upload = reactive({
- // 鏄惁鏄剧ず寮瑰嚭灞傦紙渚涘簲鍟嗗鍏ワ級
- open: false,
- // 寮瑰嚭灞傛爣棰橈紙渚涘簲鍟嗗鍏ワ級
- title: "",
- // 鏄惁绂佺敤涓婁紶
- isUploading: false,
- // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
- updateSupport: 1,
- // 璁剧疆涓婁紶鐨勮姹傚ご閮�
- headers: { Authorization: "Bearer " + getToken() },
- // 涓婁紶鐨勫湴鍧�
- url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import",
-});
-/** 瀵煎叆鎸夐挳鎿嶄綔 */
-function handleImport() {
- upload.title = "渚涘簲鍟嗗鍏�";
- upload.open = true;
-}
-/** 涓嬭浇妯℃澘 */
-function importTemplate() {
- proxy.download("/system/supplier/downloadTemplate", {}, "渚涘簲鍟嗗鍏ユā鏉�.xlsx");
-}
-
-/**鏂囦欢涓婁紶涓鐞� */
-const handleFileUploadProgress = (event, file, fileList) => {
- upload.isUploading = true;
-};
-
-/** 鏂囦欢涓婁紶鎴愬姛澶勭悊 */
-const handleFileSuccess = (response, file, fileList) => {
- upload.isUploading = false;
- if(response.code === 200){
- proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
- upload.open = false;
- proxy.$refs["uploadRef"].clearFiles();
- getList();
- }else if(response.code === 500){
- proxy.$modal.msgError(response.msg);
- }else{
- proxy.$modal.msgWarning(response.msg);
- }
-};
-
-/** 鏂囦欢涓婁紶澶辫触澶勭悊 */
-const handleFileError = (error, file, fileList) => {
- upload.isUploading = false;
- proxy.$modal.msgError("鏂囦欢涓婁紶澶辫触");
-};
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
- selectedRows.value = selection;
-};
-// 鎵撳紑寮规
-const openForm = (type, row) => {
- operationType.value = type;
- form.value = {};
- form.value.maintainUserId = userStore.id;
- form.value.maintainTime = getCurrentDate();
- userListNoPage().then((res) => {
- userList.value = res.data;
- });
- if (type === "edit") {
- getSupplier(row.id).then((res) => {
- form.value = { ...res.data };
- });
- }
- dialogFormVisible.value = true;
-};
-// 鎻愪氦琛ㄥ崟
-const submitForm = () => {
- proxy.$refs["formRef"].validate((valid) => {
- if (valid) {
- if (operationType.value === "edit") {
- submitEdit();
- } else {
- submitAdd();
- }
+ data() {
+ return {
+ activeTab: 'home'
}
- });
-};
-// 鎻愪氦鏂板
-const submitAdd = () => {
- addSupplier(form.value).then((res) => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- getList();
- });
-};
-// 鎻愪氦淇敼
-const submitEdit = () => {
- updateSupplier(form.value).then((res) => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
- closeDia();
- getList();
- });
-};
-// 鍏抽棴寮规
-const closeDia = () => {
- proxy.resetForm("formRef");
- dialogFormVisible.value = false;
-};
-// 瀵煎嚭
-const handleOut = () => {
- ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
- confirmButtonText: "纭",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- proxy.download("/system/supplier/export", {}, "渚涘簲鍟嗘。妗�.xlsx");
- })
- .catch(() => {
- proxy.$modal.msg("宸插彇娑�");
- });
-};
-// 鍒犻櫎
-const handleDelete = () => {
- let ids = [];
- if (selectedRows.value.length > 0) {
- ids = selectedRows.value.map((item) => item.id);
- } else {
- proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
- return;
}
- ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
- confirmButtonText: "纭",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- tableLoading.value = true;
- delSupplier(ids)
- .then((res) => {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
- getList();
- })
- .finally(() => {
- tableLoading.value = false;
- });
- })
- .catch(() => {
- proxy.$modal.msg("宸插彇娑�");
- });
-};
-
-// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
-function getCurrentDate() {
- const today = new Date();
- const year = today.getFullYear();
- const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
- const day = String(today.getDate()).padStart(2, "0");
- return `${year}-${month}-${day}`;
+}
+</script>
+<style>
+.main-container :deep(.el-tabs__item.is-active) {
+ color: #1883f6 !important;
+ border-bottom: 2px solid #409EFF;
}
-onMounted(() => {
- getList();
-});
-</script>
-
-<style scoped lang="scss"></style>
+</style>
diff --git a/src/views/collaborativeApproval/purchaseApproval/index.vue b/src/views/collaborativeApproval/purchaseApproval/index.vue
new file mode 100644
index 0000000..aeb931e
--- /dev/null
+++ b/src/views/collaborativeApproval/purchaseApproval/index.vue
@@ -0,0 +1,1071 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <div>
+ <el-form :model="searchForm" :inline="true">
+ <el-form-item label="渚涘簲鍟嗗悕绉帮細">
+ <el-input v-model="searchForm.supplierName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
+ <el-form-item label="閲囪喘鍚堝悓鍙凤細">
+ <el-input
+ v-model="searchForm.purchaseContractNumber"
+ style="width: 240px"
+ placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
+ :prefix-icon="Search"
+ />
+ </el-form-item>
+ <el-form-item label="閿�鍞悎鍚屽彿锛�">
+ <el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
+ <el-form-item label="椤圭洰鍚嶇О锛�">
+ <el-input v-model="searchForm.projectName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery"> 鎼滅储 </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ </div>
+ <div class="table_list">
+ <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+ </div>
+ <el-table
+ :data="tableData"
+ border
+ v-loading="tableLoading"
+ @selection-change="handleSelectionChange"
+ :expand-row-keys="expandedRowKeys"
+ :row-key="(row) => row.id"
+ show-summary
+ :summary-method="summarizeMainTable"
+ @expand-change="expandChange"
+ height="calc(100vh - 18.5em)"
+ :row-class-name="tableRowClassName"
+ >
+ <el-table-column align="center" type="selection" width="55" />
+ <el-table-column type="expand">
+ <template #default="props">
+ <el-table
+ :data="props.row.children"
+ border
+ show-summary
+ :summary-method="summarizeChildrenTable"
+ >
+ <el-table-column
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
+ />
+ <el-table-column label="浜у搧澶х被" prop="productCategory" />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+ <el-table-column label="鍗曚綅" prop="unit" />
+ <el-table-column label="鏁伴噺" prop="quantity" />
+ <el-table-column label="绋庣巼(%)" prop="taxRate" />
+ <el-table-column
+ label="鍚◣鍗曚环(鍏�)"
+ prop="taxInclusiveUnitPrice"
+ :formatter="formattedNumber"
+ />
+ <el-table-column
+ label="鍚◣鎬讳环(鍏�)"
+ prop="taxInclusiveTotalPrice"
+ :formatter="formattedNumber"
+ />
+ <el-table-column
+ label="涓嶅惈绋庢�讳环(鍏�)"
+ prop="taxExclusiveTotalPrice"
+ :formatter="formattedNumber"
+ />
+ </el-table>
+ </template>
+ </el-table-column>
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column
+ label="閲囪喘鍚堝悓鍙�"
+ prop="purchaseContractNumber"
+ width="200"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="閿�鍞悎鍚屽彿"
+ prop="salesContractNo"
+ width="200"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="渚涘簲鍟嗗悕绉�"
+ width="240"
+ prop="supplierName"
+ show-overflow-tooltip
+ />
+ <el-table-column label="璁㈠崟鐘舵��" width="100" align="center">
+ <template #default="scope">
+ <el-tag v-if="scope.row.isInvalid" type="danger" size="small">澶辨晥</el-tag>
+ <el-tag v-else type="success" size="small">姝e父</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="椤圭洰鍚嶇О"
+ prop="projectName"
+ width="420"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="瀹℃壒鐘舵��"
+ prop="approvalStatus"
+ width="200"
+ show-overflow-tooltip
+ >
+ <template #default="scope">
+ <el-tag
+ size="small"
+ >
+ {{ approvalStatusText[scope.row.approvalStatus] || '鏈煡鐘舵��' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="浠樻鏂瑰紡"
+ width="100"
+ prop="paymentMethod"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="鍚堝悓閲戦(鍏�)"
+ prop="contractAmount"
+ width="200"
+ show-overflow-tooltip
+ :formatter="formattedNumber"
+ />
+ <el-table-column
+ label="褰曞叆浜�"
+ prop="recorderName"
+ width="100"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="褰曞叆鏃ユ湡"
+ prop="entryDate"
+ width="100"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ fixed="right"
+ label="鎿嶄綔"
+ min-width="150"
+ align="center"
+ >
+ <template #default="scope">
+ <el-button
+ link
+ type="primary"
+ size="small"
+ @click="approvePurchase(scope.row)"
+ :disabled="scope.row.approvalStatus !== 0"
+ >瀹℃壒</el-button
+ >
+ <el-button
+ link
+ type="primary"
+ size="small"
+ @click="rejectPurchase(scope.row)"
+ :disabled="scope.row.approvalStatus !== 0"
+ >鎷掔粷瀹℃壒</el-button
+ >
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination
+ v-show="total > 0"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationChange"
+ />
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { getToken } from "@/utils/auth";
+import pagination from "@/components/PIMTable/Pagination.vue";
+import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import {
+ getSalesLedgerWithProducts,
+ addOrUpdateSalesLedgerProduct,
+ delProduct,
+ delLedgerFile,
+ getProductInfoByContractNo,
+} from "@/api/salesManagement/salesLedger.js";
+import {
+ addOrEditPurchase,
+ delPurchase,
+ getSalesNo,
+ purchaseListPage,
+ productList,
+ getPurchaseById,
+ getOptions,
+ createPurchaseNo, updateApprovalStatus,
+} from "@/api/procurementManagement/procurementLedger.js";
+import useFormData from "@/hooks/useFormData.js";
+import QRCode from "qrcode";
+
+
+const { proxy } = getCurrentInstance();
+const tableData = ref([]);
+const productData = ref([]);
+const selectedRows = ref([]);
+const productSelectedRows = ref([]);
+const modelOptions = ref([]);
+const userList = ref([]);
+const productOptions = ref([]);
+const salesContractList = ref([]);
+const supplierList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+ current: 1,
+ size: 100,
+});
+const total = ref(0);
+const fileList = ref([]);
+import useUserStore from "@/store/modules/user";
+import { modelList, productTreeList } from "@/api/basicData/product.js";
+import dayjs from "dayjs";
+
+const userStore = useUserStore();
+
+// 浜岀淮鐮佺浉鍏冲彉閲�
+const qrCodeDialogVisible = ref(false);
+const qrCodeUrl = ref("");
+
+// 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
+const approvalStatusText = {
+ 0: '寰呭鎵�',
+ 1: '瀹℃壒閫氳繃',
+ 2: '瀹℃壒澶辫触'
+};
+
+// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+ searchForm: {
+ supplierName: "", // 渚涘簲鍟嗗悕绉�
+ purchaseContractNumber: "", // 閲囪喘鍚堝悓缂栧彿
+ salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+ projectName: "", // 椤圭洰鍚嶇О
+ entryDate: null, // 褰曞叆鏃ユ湡
+ entryDateStart: undefined,
+ entryDateEnd: undefined,
+ },
+ form: {
+ purchaseContractNumber: "",
+ salesLedgerId: "",
+ projectName: "",
+ recorderId: "",
+ entryDate: "",
+ productData: [],
+ supplierName: "",
+ supplierId: "",
+ paymentMethod: "",
+ executionDate: "",
+ approvalStatus: "0",
+ },
+ rules: {
+ purchaseContractNumber: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ projectName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ supplierId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+});
+const { form, rules } = toRefs(data);
+const { form: searchForm } = useFormData(data.searchForm);
+
+// 浜у搧琛ㄥ崟寮规鏁版嵁
+const productFormVisible = ref(false);
+const productOperationType = ref("");
+const productOperationIndex = ref("");
+const currentId = ref("");
+const productFormData = reactive({
+ productForm: {
+ productId: "",
+ productCategory: "",
+ productModelId: "",
+ specificationModel: "",
+ unit: "",
+ quantity: "",
+ taxInclusiveUnitPrice: "",
+ taxRate: "",
+ taxInclusiveTotalPrice: "",
+ taxExclusiveTotalPrice: "",
+ invoiceType: "",
+ warnNum: "",
+ },
+ productRules: {
+ productId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ taxInclusiveUnitPrice: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ warnNum: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ taxInclusiveTotalPrice: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ taxExclusiveTotalPrice: [
+ { required: true, message: "璇疯緭鍏�", trigger: "blur" },
+ ],
+ invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+});
+const { productForm, productRules } = toRefs(productFormData);
+const upload = reactive({
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+});
+
+const changeDaterange = (value) => {
+ if (value) {
+ searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
+ searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+ } else {
+ searchForm.entryDateStart = undefined;
+ searchForm.entryDateEnd = undefined;
+ }
+ handleQuery();
+};
+
+const formattedNumber = (row, column, cellValue) => {
+ return parseFloat(cellValue).toFixed(2);
+};
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+// 瀛愯〃鍚堣鏂规硶
+const summarizeChildrenTable = (param) => {
+ return proxy.summarizeTable(
+ param,
+ [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ "ticketsNum",
+ "ticketsAmount",
+ "futureTickets",
+ "futureTicketsAmount",
+ ],
+ {
+ ticketsNum: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+ futureTickets: { noDecimal: true }, // 涓嶄繚鐣欏皬鏁�
+ }
+ );
+};
+const paginationChange = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+const getList = () => {
+ tableLoading.value = true;
+ const { entryDate, ...rest } = searchForm;
+ purchaseListPage({ ...rest, ...page })
+ .then((res) => {
+ tableLoading.value = false;
+ // tableData.value = res.data.records;
+ // 澶勭悊鏁版嵁锛屾坊鍔犲け鏁堢姸鎬佹爣璁�
+ tableData.value = res.data.records.map(record => ({
+ ...record,
+ isInvalid: record.isWhite === 1
+ }));
+ tableData.value.map((item) => {
+ item.children = [];
+ });
+ total.value = res.data.total;
+ expandedRowKeys.value = [];
+ })
+ .catch(() => {
+ tableLoading.value = false;
+ });
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+const productSelected = (selectedRows) => {
+ productSelectedRows.value = selectedRows;
+};
+const expandedRowKeys = ref([]);
+// 灞曞紑琛�
+const expandChange = (row, expandedRows) => {
+ if (expandedRows.length > 0) {
+ expandedRowKeys.value = [];
+ try {
+ productList({ salesLedgerId: row.id, type: 2 }).then((res) => {
+ const index = tableData.value.findIndex((item) => item.id === row.id);
+ if (index > -1) {
+ tableData.value[index].children = res.data;
+ }
+ expandedRowKeys.value.push(row.id);
+ });
+ } catch (error) {
+ console.log(error);
+ }
+ } else {
+ expandedRowKeys.value = [];
+ }
+};
+// 涓昏〃鍚堣鏂规硶
+const summarizeMainTable = (param) => {
+ return proxy.summarizeTable(param, ["contractAmount"]);
+};
+// 瀛愯〃鍚堣鏂规硶
+const summarizeProTable = (param) => {
+ return proxy.summarizeTable(param, [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ]);
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ operationType.value = type;
+ form.value = {};
+ productData.value = [];
+ fileList.value = [];
+ if (operationType.value == "add") {
+ createPurchaseNo().then((res) => {
+ form.value.purchaseContractNumber = res.data;
+ });
+ }
+ userListNoPage().then((res) => {
+ userList.value = res.data;
+ });
+ getSalesNo().then((res) => {
+ salesContractList.value = res;
+ });
+ getOptions().then((res) => {
+ // 渚涘簲鍟嗚繃婊ゅ嚭isWhite=0 鐨勬暟鎹�
+ supplierList.value = res.data.filter((item) => item.isWhite == 0);
+ });
+ form.value.recorderId = userStore.id;
+ form.value.entryDate = getCurrentDate();
+ if (type === "edit") {
+ currentId.value = row.id;
+ getPurchaseById({ id: row.id, type: 2 }).then((res) => {
+ form.value = { ...res };
+ productData.value = form.value.productData;
+ if (form.value.salesLedgerFiles) {
+ fileList.value = form.value.salesLedgerFiles;
+ } else {
+ fileList.value = [];
+ }
+ });
+ }
+ dialogFormVisible.value = true;
+};
+// 涓婁紶鍓嶆牎妫�
+function handleBeforeUpload(file) {
+ // 鏍℃鏂囦欢澶у皬
+ if (file.size > 1024 * 1024 * 10) {
+ proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!");
+ return false;
+ }
+ proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
+ return true;
+}
+// 涓婁紶澶辫触
+function handleUploadError(err) {
+ proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
+ proxy.$modal.closeLoading();
+}
+// 涓婁紶鎴愬姛鍥炶皟
+function handleUploadSuccess(res, file, uploadFiles) {
+ proxy.$modal.closeLoading();
+ if (res.code === 200) {
+ file.tempId = res.data.tempId;
+ proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+ } else {
+ proxy.$modal.msgError(res.msg);
+ proxy.$refs.fileUpload.handleRemove(file);
+ }
+}
+// 绉婚櫎鏂囦欢
+function handleRemove(file) {
+ console.log("handleRemove", file.id);
+ if (file.size > 1024 * 1024 * 10) {
+ // 浠呭墠绔竻鐞嗭紝涓嶈皟鐢ㄥ垹闄ゆ帴鍙e拰鎻愮ず
+ return;
+ }
+ if (operationType.value === "edit") {
+ let ids = [];
+ ids.push(file.id);
+ delLedgerFile(ids).then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ });
+ }
+}
+// 鎻愪氦琛ㄥ崟
+const submitForm = (n) => {
+ proxy.$refs["formRef"].validate((valid) => {
+ if (valid) {
+ if (productData.value.length > 0) {
+ form.value.productData = proxy.HaveJson(productData.value);
+ } else {
+ proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
+ return;
+ }
+ let tempFileIds = [];
+ if (fileList.value.length > 0) {
+ tempFileIds = fileList.value.map((item) => item.tempId);
+ }
+ form.value.tempFileIds = tempFileIds;
+ form.value.type = 2;
+ form.value.approvalStatus = n;
+ addOrEditPurchase(form.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
+ }
+ });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+};
+// 鎵撳紑浜у搧寮规
+const openProductForm = (type, row, index) => {
+ productOperationType.value = type;
+ productOperationIndex.value = index;
+ productForm.value = {};
+ proxy.resetForm("productFormRef");
+ if (type === "edit") {
+ productForm.value = { ...row };
+ }
+ productFormVisible.value = true;
+ getProductOptions();
+};
+const getProductOptions = () => {
+ productTreeList().then((res) => {
+ productOptions.value = convertIdToValue(res);
+ });
+};
+const getModels = (value) => {
+ if (value) {
+ productForm.value.productCategory = findNodeById(productOptions.value, value) || "";
+ modelList({ id: value }).then((res) => {
+ modelOptions.value = res;
+ });
+ } else {
+ productForm.value.productCategory = "";
+ modelOptions.value = [];
+ }
+};
+const getProductModel = (value) => {
+ const index = modelOptions.value.findIndex((item) => item.id === value);
+ if (index !== -1) {
+ productForm.value.specificationModel = modelOptions.value[index].model;
+ productForm.value.unit = modelOptions.value[index].unit;
+ } else {
+ productForm.value.specificationModel = null;
+ productForm.value.unit = null;
+ }
+};
+const findNodeById = (nodes, productId) => {
+ for (let i = 0; i < nodes.length; i++) {
+ if (nodes[i].value === productId) {
+ return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣鐨刲abel
+ }
+ if (nodes[i].children && nodes[i].children.length > 0) {
+ const foundNode = findNodeById(nodes[i].children, productId);
+ if (foundNode) {
+ return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝鐩存帴杩斿洖锛堝凡缁忔槸label瀛楃涓诧級
+ }
+ }
+ }
+ return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
+};
+function convertIdToValue(data) {
+ return data.map((item) => {
+ const { id, children, ...rest } = item;
+ const newItem = {
+ ...rest,
+ value: id, // 灏� id 鏀逛负 value
+ };
+ if (children && children.length > 0) {
+ newItem.children = convertIdToValue(children);
+ }
+
+ return newItem;
+ });
+}
+// 鎻愪氦浜у搧琛ㄥ崟
+const submitProduct = () => {
+ proxy.$refs["productFormRef"].validate((valid) => {
+ if (valid) {
+ if (operationType.value === "edit") {
+ submitProductEdit();
+ } else {
+ if (productOperationType.value === "add") {
+ productData.value.push({ ...productForm.value });
+ console.log("productData.value---", productData.value);
+ } else {
+ productData.value[productOperationIndex.value] = {
+ ...productForm.value,
+ };
+ }
+ closeProductDia();
+ }
+ }
+ });
+};
+const submitProductEdit = () => {
+ productForm.value.salesLedgerId = currentId.value;
+ productForm.value.type = 2;
+ addOrUpdateSalesLedgerProduct(productForm.value).then((res) => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeProductDia();
+ getPurchaseById({ id: currentId.value, type: 2 }).then((res) => {
+ productData.value = res.productData;
+ });
+ });
+};
+// 鍒犻櫎浜у搧
+const deleteProduct = () => {
+ if (productSelectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ if (operationType.value === "add") {
+ productSelectedRows.value.forEach((selectedRow) => {
+ const index = productData.value.findIndex(
+ (product) => product.id === selectedRow.id
+ );
+ if (index !== -1) {
+ productData.value.splice(index, 1);
+ }
+ });
+ } else {
+ let ids = [];
+ if (productSelectedRows.value.length > 0) {
+ ids = productSelectedRows.value.map((item) => item.id);
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ delProduct(ids).then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ closeProductDia();
+ getSalesLedgerWithProducts({ id: currentId.value, type: 2 }).then(
+ (res) => {
+ productData.value = res.productData;
+ }
+ );
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+ }
+};
+// 鍏抽棴浜у搧寮规
+const closeProductDia = () => {
+ proxy.resetForm("productFormRef");
+ productFormVisible.value = false;
+};
+// 瀹℃壒閫氳繃鏂规硶
+const approvePurchase = (row) => {
+ ElMessageBox.confirm(`纭閫氳繃閲囪喘鍚堝悓鍙蜂负 ${row.purchaseContractNumber} 鐨勫鎵癸紵`, '瀹℃壒纭', {
+ confirmButtonText: '纭',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ }).then(() => {
+ updateApprovalStatus({ id: row.id, approvalStatus: 1}).then((res)=>{
+ proxy.$modal.msgSuccess('瀹℃壒鎴愬姛');
+ getList();
+ })
+ }).catch(() => {
+ proxy.$modal.msg('宸插彇娑堝鎵�');
+ });
+};
+
+// 瀹℃壒鎷掔粷鏂规硶
+const rejectPurchase = (row) => {
+ ElMessageBox.confirm(`纭鎷掔粷閲囪喘鍚堝悓鍙蜂负 ${row.purchaseContractNumber} 鐨勫鎵癸紵`, '瀹℃壒纭', {
+ confirmButtonText: '纭',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ }).then(() => {
+ updateApprovalStatus({ id: row.id, approvalStatus: 2}).then((res)=>{
+ proxy.$modal.msgSuccess('瀹℃壒鎴愬姛');
+ getList();
+ })
+ }).catch(() => {
+ proxy.$modal.msg('宸插彇娑堝鎵�');
+ });
+};
+
+// 瀵煎嚭
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download("/purchase/ledger/export", {}, "閲囪喘鍙拌处.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = [];
+ if (selectedRows.value.length > 0) {
+ // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+ const unauthorizedData = selectedRows.value.filter(item => item.recorderName !== userStore.nickName);
+ if (unauthorizedData.length > 0) {
+ proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+ return;
+ }
+ ids = selectedRows.value.map((item) => item.id);
+ } else {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ delPurchase(ids).then((res) => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+ const today = new Date();
+ const year = today.getFullYear();
+ const month = String(today.getMonth() + 1).padStart(2, "0"); // 鏈堜唤浠�0寮�濮�
+ const day = String(today.getDate()).padStart(2, "0");
+ return `${year}-${month}-${day}`;
+}
+const mathNum = () => {
+ if (!productForm.value.taxRate) {
+ proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ return;
+ }
+ if (!productForm.value.taxInclusiveUnitPrice) {
+ return;
+ }
+ if (!productForm.value.quantity) {
+ return;
+ }
+ // 鍚◣鎬讳环璁$畻
+ productForm.value.taxInclusiveTotalPrice =
+ proxy.calculateTaxIncludeTotalPrice(
+ productForm.value.taxInclusiveUnitPrice,
+ productForm.value.quantity
+ );
+ if (productForm.value.taxRate) {
+ // 涓嶅惈绋庢�讳环璁$畻
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(
+ productForm.value.taxInclusiveTotalPrice,
+ productForm.value.taxRate
+ );
+ }
+};
+const reverseMathNum = (field) => {
+ if (!productForm.value.taxRate) {
+ proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ return;
+ }
+ const taxRate = Number(productForm.value.taxRate);
+ if (!taxRate) return;
+ if (field === 'taxInclusiveTotalPrice') {
+ // 宸茬煡鍚◣鎬讳环鍜屾暟閲忥紝鍙嶇畻鍚◣鍗曚环
+ if (productForm.value.quantity) {
+ productForm.value.taxInclusiveUnitPrice =
+ (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
+ }
+ // 宸茬煡鍚◣鎬讳环鍜屽惈绋庡崟浠凤紝鍙嶇畻鏁伴噺
+ else if (productForm.value.taxInclusiveUnitPrice) {
+ productForm.value.quantity =
+ (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
+ }
+ // 鍙嶇畻涓嶅惈绋庢�讳环
+ productForm.value.taxExclusiveTotalPrice =
+ (Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)).toFixed(2);
+ } else if (field === 'taxExclusiveTotalPrice') {
+ // 鍙嶇畻鍚◣鎬讳环
+ productForm.value.taxInclusiveTotalPrice =
+ (Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)).toFixed(2);
+ // 宸茬煡鏁伴噺锛屽弽绠楀惈绋庡崟浠�
+ if (productForm.value.quantity) {
+ productForm.value.taxInclusiveUnitPrice =
+ (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2);
+ }
+ // 宸茬煡鍚◣鍗曚环锛屽弽绠楁暟閲�
+ else if (productForm.value.taxInclusiveUnitPrice) {
+ productForm.value.quantity =
+ (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2);
+ }
+ }
+};
+// 閿�鍞悎鍚岄�夋嫨鏀瑰彉鏂规硶
+const salesLedgerChange = async (row) => {
+ console.log("row", row);
+ var index = salesContractList.value.findIndex((item) => item.id == row);
+ console.log("index", index);
+ if (index > -1) {
+ form.value.projectName = salesContractList.value[index].projectName;
+ await querygProductInfoByContractNo();
+ }
+};
+
+const querygProductInfoByContractNo = async () => {
+ const { code, data } = await getProductInfoByContractNo({
+ contractNo: form.value.salesLedgerId,
+ });
+ if (code == 200) {
+ productData.value = data;
+ }
+};
+
+// 鏄剧ず浜岀淮鐮�
+const showQRCode = async (row) => {
+ try {
+ // 鏋勫缓浜岀淮鐮佸唴瀹癸紝鍙寘鍚噰璐悎鍚屽彿锛堢函鏂囨湰锛�
+ const qrContent = row.purchaseContractNumber || '';
+ // 妫�鏌ュ唴瀹规槸鍚︿负绌�
+ if (!qrContent || qrContent.trim() === '') {
+ proxy.$modal.msgWarning("璇ヨ娌℃湁閲囪喘鍚堝悓鍙凤紝鏃犳硶鐢熸垚浜岀淮鐮�");
+ return;
+ }
+ qrCodeUrl.value = await QRCode.toDataURL(qrContent, {
+ width: 200,
+ margin: 2,
+ color: {
+ dark: '#000000',
+ light: '#FFFFFF'
+ }
+ });
+ qrCodeDialogVisible.value = true;
+ } catch (error) {
+ console.error('鐢熸垚浜岀淮鐮佸け璐�:', error);
+ proxy.$modal.msgError("鐢熸垚浜岀淮鐮佸け璐ワ細" + error.message);
+ }
+};
+
+// 涓嬭浇浜岀淮鐮�
+const downloadQRCode = () => {
+ if (!qrCodeUrl.value) {
+ proxy.$modal.msgWarning("浜岀淮鐮佹湭鐢熸垚");
+ return;
+ }
+
+ const a = document.createElement('a');
+ a.href = qrCodeUrl.value;
+ a.download = `閲囪喘鍚堝悓鍙蜂簩缁寸爜_${new Date().getTime()}.png`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ proxy.$modal.msgSuccess("涓嬭浇鎴愬姛");
+};
+
+// 鎵爜鏂板瀵硅瘽妗嗙浉鍏冲彉閲�
+const scanAddDialogVisible = ref(false);
+const scanAddForm = reactive({
+ scanContent: "",
+ purchaseContractNumber: "",
+ supplierName: "",
+ projectName: "",
+ contractAmount: "",
+ paymentMethod: "",
+ recorderName: "",
+ scanRemark: "",
+});
+const scanAddRules = {
+ purchaseContractNumber: [{ required: true, message: "璇疯緭鍏ラ噰璐悎鍚屽彿", trigger: "blur" }],
+ supplierName: [{ required: true, message: "璇疯緭鍏ヤ緵搴斿晢鍚嶇О", trigger: "blur" }],
+ projectName: [{ required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" }],
+};
+
+// 鎵爜鐧昏瀵硅瘽妗嗙浉鍏冲彉閲�
+const scanDialogVisible = ref(false);
+const scanForm = reactive({
+ purchaseContractNumber: "",
+ supplierName: "",
+ projectName: "",
+ scanTime: "",
+ scannerName: "",
+ scanStatus: "鏈壂鐮�",
+ scanRemark: "",
+});
+const scanRules = {
+ scanRemark: [{ required: true, message: "璇疯緭鍏ユ壂鐮佸娉�", trigger: "blur" }],
+};
+const scanRecords = ref([]);
+
+// 鎵撳紑鎵爜鏂板瀵硅瘽妗�
+const openScanAddDialog = () => {
+ scanAddForm.scanContent = "";
+ scanAddForm.purchaseContractNumber = "";
+ scanAddForm.supplierName = "";
+ scanAddForm.projectName = "";
+ scanAddForm.contractAmount = "";
+ scanAddForm.paymentMethod = "";
+ scanAddForm.recorderName = userStore.nickName;
+ scanAddForm.scanRemark = "";
+ scanAddDialogVisible.value = true;
+};
+
+// 瑙f瀽鎵爜鍐呭锛堟ā鎷熻В鏋愪簩缁寸爜鏁版嵁锛�
+const parseScanContent = (content) => {
+ if (!content) return;
+
+ // 妯℃嫙瑙f瀽浜岀淮鐮佸唴瀹癸紝杩欓噷鍙互鏍规嵁瀹為檯闇�姹傝皟鏁磋В鏋愰�昏緫
+ // 鍋囪鎵爜鍐呭鏍煎紡涓猴細鍚堝悓鍙穦渚涘簲鍟唡椤圭洰|閲戦|浠樻鏂瑰紡
+ const parts = content.split('|');
+ if (parts.length >= 3) {
+ scanAddForm.purchaseContractNumber = parts[0] || "";
+ scanAddForm.supplierName = parts[1] || "";
+ scanAddForm.projectName = parts[2] || "";
+ scanAddForm.contractAmount = parts[3] || "";
+ scanAddForm.paymentMethod = parts[4] || "";
+ }
+};
+
+// 鍏抽棴鎵爜鏂板瀵硅瘽妗�
+const closeScanAddDialog = () => {
+ scanAddDialogVisible.value = false;
+ proxy.resetForm("scanAddFormRef");
+};
+
+// 鎻愪氦鎵爜鏂板
+const submitScanAdd = () => {
+ proxy.$refs["scanAddFormRef"].validate((valid) => {
+ if (valid) {
+ // 鏋勫缓鏂板鏁版嵁
+ const newData = {
+ purchaseContractNumber: scanAddForm.purchaseContractNumber,
+ supplierName: scanAddForm.supplierName,
+ projectName: scanAddForm.projectName,
+ contractAmount: scanAddForm.contractAmount,
+ paymentMethod: scanAddForm.paymentMethod,
+ recorderName: scanAddForm.recorderName,
+ entryDate: getCurrentDate(),
+ remark: scanAddForm.scanRemark,
+ type: 2
+ };
+
+ // 妯℃嫙鏂板鎴愬姛
+ proxy.$modal.msgSuccess("鎵爜鏂板鎴愬姛锛�");
+ closeScanAddDialog();
+
+ // 鍙互閫夋嫨鏄惁鍒锋柊鍒楄〃
+ // getList();
+ }
+ });
+};
+
+// 鎵撳紑鎵爜鐧昏瀵硅瘽妗�
+const openScanDialog = (row) => {
+ scanForm.purchaseContractNumber = row.purchaseContractNumber;
+ scanForm.supplierName = row.supplierName;
+ scanForm.projectName = row.projectName;
+ scanForm.scanTime = getCurrentDateTime();
+ scanForm.scannerName = userStore.nickName;
+ scanForm.scanStatus = "鏈壂鐮�";
+ scanForm.scanRemark = "";
+ scanRecords.value = [];
+ scanDialogVisible.value = true;
+};
+
+// 鍏抽棴鎵爜鐧昏瀵硅瘽妗�
+const closeScanDialog = () => {
+ scanDialogVisible.value = false;
+ proxy.resetForm("scanFormRef");
+};
+
+// 鎻愪氦鎵爜鐧昏
+const submitScan = () => {
+ proxy.$refs["scanFormRef"].validate((valid) => {
+ if (valid) {
+ // 娣诲姞鎵爜璁板綍
+ scanRecords.value.push({
+ ...scanForm,
+ id: Date.now(), // 妯℃嫙ID
+ scanTime: getCurrentDateTime(),
+ });
+ scanForm.scanStatus = "宸叉壂鐮�";
+ scanForm.scanRemark = scanForm.scanRemark || "鏃�";
+ proxy.$modal.msgSuccess("鎵爜鐧昏鎴愬姛锛�");
+ closeScanDialog();
+ }
+ });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡鏃堕棿
+function getCurrentDateTime() {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = String(now.getMonth() + 1).padStart(2, "0");
+ const day = String(now.getDate()).padStart(2, "0");
+ const hours = String(now.getHours()).padStart(2, "0");
+ const minutes = String(now.getMinutes()).padStart(2, "0");
+ const seconds = String(now.getSeconds()).padStart(2, "0");
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+
+// 娣诲姞琛岀被鍚嶆柟娉�
+const tableRowClassName = ({ row }) => {
+ return row.isInvalid ? 'invalid-row' : '';
+};
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped lang="scss">
+.invalid-row {
+ opacity: 0.6;
+ background-color: #f5f7fa;
+}
+</style>
diff --git a/src/views/financialManagement/fixedAssetAccounting/index.vue b/src/views/financialManagement/fixedAssetAccounting/index.vue
new file mode 100644
index 0000000..ad7df9a
--- /dev/null
+++ b/src/views/financialManagement/fixedAssetAccounting/index.vue
@@ -0,0 +1,547 @@
+<template>
+ <div style="padding: 20px;">
+ <!-- 椤甸潰鏍囬鍜岀瓫閫夋潯浠� -->
+ <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;">
+ <el-button
+ type="primary"
+ icon="Refresh"
+ @click="resetFilters"
+ size="default"
+ >
+ 鏌ヨ
+ </el-button>
+ </div>
+
+ <main class="container mx-auto px-4 pb-10">
+ <!-- 鍥哄畾璧勪骇鎸囨爣鍗$墖 -->
+ <div class="grid-container">
+ <!-- 璁惧鎬绘暟 -->
+ <el-card class="bg2">
+ <p>璁惧鎬绘暟</p>
+ <h3>
+ {{ assetInfo.totalEquipment }}
+ </h3>
+ </el-card>
+
+ <!-- 璧勪骇鍘熷�� -->
+ <el-card class="bg3">
+ <p>璧勪骇鍘熷��</p>
+ <h3>
+ 楼{{ assetInfo.totalOriginalValue }}
+ </h3>
+ </el-card>
+
+ <!-- 绱鎶樻棫 -->
+ <el-card class="bg4">
+ <p>绱鎶樻棫</p>
+ <h3>
+ 楼{{ assetInfo.totalDepreciation }}
+ </h3>
+ </el-card>
+
+ <!-- 鍑�鍊� -->
+ <el-card class="bg5">
+ <p>鍑�鍊�</p>
+ <h3>
+ 楼{{ assetInfo.totalNetValue }}
+ </h3>
+ </el-card>
+ </div>
+
+ <!-- 鍥哄畾璧勪骇缁熻鍥捐〃 -->
+ <div class="grid-layout">
+ <!-- 鎸夎澶囩被鍨嬬粺璁� -->
+ <el-card style="margin-bottom: 20px;">
+ <h2 class="section-title">璁惧绫诲瀷鍒嗗竷</h2>
+ <div class="echarts">
+ <Echarts
+ :legend="typeDistributionLegend"
+ :chartStyle="chartStylePie"
+ :series="typeDistributionSeries"
+ :tooltip="pieTooltip"
+ style="height: 260px; width: 35%;">
+ <div class="chart-num">
+ <span style="font-size: 22px;">璁惧绫诲瀷</span>
+ <span style="font-size: 36px; font-weight: 500; font-family: 'MyCustomFont', sans-serif;">{{ assetInfo.totalEquipment }}</span>
+ </div>
+ </Echarts>
+ <Echarts
+ ref="chart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="lineLegend"
+ :series="typeDistributionLineSeries"
+ :tooltip="tooltip"
+ :xAxis="xAxis"
+ :yAxis="yAxis"
+ style="height: 260px; width: 64%;"></Echarts>
+ </div>
+ </el-card>
+ </div>
+ <!-- 璁惧鍙拌处琛ㄦ牸 -->
+ <el-card style="margin-bottom: 20px;">
+ <el-table
+ :data="equipmentList"
+ stripe
+ style="width: 100%"
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
+ >
+ <el-table-column prop="id" label="璧勪骇缂栧彿" width="120" />
+ <el-table-column prop="deviceName" label="璁惧鍚嶇О" width="250" />
+ <el-table-column prop="deviceModel" label="鍨嬪彿瑙勬牸" min-width="150" />
+ <el-table-column prop="supplierName" label="渚涘簲鍟�" min-width="120" />
+ <el-table-column prop="unit" label="鍗曚綅" width="120" />
+ <el-table-column prop="number" label="鏁伴噺" width="120" />
+ <el-table-column prop="originalValue" label="鍘熷��(鍏�)" width="120">
+ <template #default="{ row }">
+ 楼{{ formatCurrency(row.taxIncludingPriceTotal) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="depreciation" label="绱鎶樻棫(鍏�)" width="140">
+ <template #default="{ row }">
+ 楼{{ formatCurrency(row.taxIncludingPriceTotal-row.unTaxIncludingPriceTotal) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="netValue" label="鍑�鍊�(鍏�)" width="120">
+ <template #default="{ row }">
+ 楼{{ formatCurrency(row.unTaxIncludingPriceTotal) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="status" label="鐘舵��" width="100">
+ <template #default="{ row }">
+ <el-tag
+ :type="getStatusTagType(row.status)"
+ size="small"
+ >
+ {{ row.status }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <div class="pagination-container">
+ <el-pagination
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ :current-page="pagination.currentPage"
+ :page-sizes="[10, 20, 50, 100]"
+ :page-size="pagination.pageSize"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="pagination.total"
+ />
+ </div>
+ </el-card>
+ </main>
+
+ </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, reactive } from 'vue';
+import 'element-plus/dist/index.css';
+import Echarts from "@/components/Echarts/echarts.vue";
+import { getLedgerPage, getAssetInfo } from "@/api/equipmentManagement/ledger";
+import dayjs from "dayjs";
+
+// 绛涢�夋潯浠�
+const dateRange = ref(null);
+const equipmentType = ref('');
+
+
+// 鍥哄畾璧勪骇淇℃伅
+const assetInfo = ref({
+ totalEquipment: 0,
+ totalOriginalValue: 0,
+ totalDepreciation: 0,
+ totalNetValue: 0
+});
+
+// 璁惧鍒楄〃
+const equipmentList = ref([]);
+const pagination = ref({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0
+});
+
+// 鍥捐〃閰嶇疆
+const chartStyle = {
+ width: '100%',
+ height: '100%',
+ position: 'relative',
+};
+
+const grid = {
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true
+};
+
+const lineLegend = {
+ show: false,
+};
+
+// 鎶樼嚎鍥炬彁绀烘
+const tooltip = reactive({
+ trigger: 'axis',
+ axisPointer: {
+ type: 'line',
+ lineStyle: { color: '#aaa' }
+ },
+ // 鑷畾涔夊唴瀹�
+ formatter: function (params) {
+ if (!params || !params.length) return '';
+ const axisLabel = params[0].axisValueLabel || params[0].axisValue || '';
+ const rows = params
+ .map(p => {
+ const colorDot = `<span style="display:inline-block;margin-right:6px;width:8px;height:8px;border-radius:50%;background:${p.color}"></span>`;
+ return `${colorDot}${p.seriesName}: ${p.value}`;
+ })
+ .join('<br/>');
+ return `<div>${axisLabel}</div><div>${rows}</div>`;
+ }
+});
+
+const xAxis = ref([
+ {
+ type: 'category',
+ axisTick: { show: true, alignWithLabel: true },
+ data: [],
+ },
+]);
+
+const yAxis = [
+ {
+ type: 'value',
+ name: '鏁伴噺/閲戦', // 宸︿晶y杞�
+ position: 'left',
+ min: 0,
+ // 鍧愭爣杞村悕绉版牱寮�
+ nameTextStyle: {
+ color: '#000',
+ fontSize: 14,
+ },
+ }
+];
+
+const chartStylePie = {
+ width: '100%',
+ height: '100%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+};
+
+const pieColors = ['#F04864', '#FACC14', '#8543E0', '#1890FF', '#13C2C2', '#2FC25B']; // 鍙牴鎹疄闄呰皟鏁�
+
+// 楗煎浘鏁版嵁
+const typeDistributionData = ref([]);
+const departmentDistributionData = ref([]);
+
+// 楗煎浘鍥句緥
+const typeDistributionLegend = computed(() => ({
+ show: true,
+ top: 'center',
+ left: '60%',
+ orient: 'vertical',
+ icon: 'circle',
+ data: typeDistributionData.value.map(item => item.name),
+ formatter: function(name) {
+ const item = typeDistributionData.value.find(i => i.name === name);
+ if (!item) return name;
+ return `${name} | ${item.count} 鍙� | ${item.amount}`;
+ },
+ textStyle: {
+ color: '#333',
+ fontSize: 14,
+ lineHeight: 26,
+ }
+}));
+
+
+// 楗煎浘绯诲垪
+const typeDistributionSeries = computed(() => [
+ {
+ type: 'pie',
+ radius: ['50%', '65%'],
+ center: ['25%', '50%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: false
+ },
+ data: typeDistributionData.value,
+ color: pieColors
+ }
+]);
+
+// 鎶樼嚎鍥炬暟鎹�
+const typeDistributionLineSeries = ref([]);
+
+
+// 楗煎浘鎻愮ず妗�
+const pieTooltip = reactive({
+ trigger: 'item',
+ formatter: function(params) {
+ // 妫�鏌ユ暟鎹槸鍚﹀瓨鍦�
+ if (!params.data) return params.name;
+ // 鎷兼帴瀹屾暣鍐呭
+ return `
+ <div>
+ <div style="color:${params.color};font-size:16px;">鈼�</div>
+ <div>${params.name}</div>
+ <div>鏁伴噺锛�${params.data.count} 鍙�</div>
+ <div>閲戦锛�${params.data.amount}</div>
+ </div>
+ `;
+ }
+});
+
+// 閫夐」鏁版嵁
+const equipmentTypeOptions = ref([]);
+
+// 鑾峰彇鏁版嵁
+const fetchData = async () => {
+ try {
+ // 鑾峰彇鍥哄畾璧勪骇姹囨�讳俊鎭�
+ const assetInfoRes = await getAssetInfo({
+ startDate: dateRange.value ? dateRange.value[0] : null,
+ endDate: dateRange.value ? dateRange.value[1] : null,
+ equipmentType: equipmentType.value
+ });
+
+ if (assetInfoRes.code === 200) {
+ assetInfo.value = assetInfoRes.data;
+ }
+
+ // 鑾峰彇璁惧鍒楄〃
+ const equipmentListRes = await getLedgerPage({
+ current: pagination.value.currentPage,
+ size: pagination.value.pageSize,
+ startDate: dateRange.value ? dateRange.value[0] : null,
+ endDate: dateRange.value ? dateRange.value[1] : null,
+ equipmentType: equipmentType.value
+ });
+
+ if (equipmentListRes.code === 200) {
+ equipmentList.value = equipmentListRes.data.records;
+ pagination.value.total = equipmentListRes.data.total;
+
+ // 鏍规嵁 equipmentList 鎸� deviceName 杩涜鍒嗙被缁熻
+ const deviceNameMap = {};
+ equipmentList.value.forEach(item => {
+ const deviceName = item.deviceName;
+ if (!deviceNameMap[deviceName]) {
+ deviceNameMap[deviceName] = {
+ name: deviceName,
+ count: 0,
+ totalValue: 0
+ };
+ }
+ deviceNameMap[deviceName].count += item.number || 1; // 鍋囪 number 涓鸿澶囨暟閲�
+ deviceNameMap[deviceName].totalValue += item.taxIncludingPriceTotal || 0; // 绱姞鍚◣鎬讳环
+ });
+
+ // 杞崲涓� typeDistributionData 鏍煎紡
+ typeDistributionData.value = Object.values(deviceNameMap).map(item => ({
+ name: item.name,
+ value: item.count,
+ count: item.count,
+ amount: `楼${formatCurrency(item.totalValue)}`
+ }));
+
+ // 鏇存柊x杞存暟鎹�
+ xAxis.value[0].data = typeDistributionData.value.map(item => item.name);
+
+ // 鏋勫缓鎶樼嚎鍥炬暟鎹�
+ typeDistributionLineSeries.value = [
+ {
+ name: '璁惧鏁伴噺',
+ type: 'line',
+ data: typeDistributionData.value.map(item => item.count)
+ }
+ ];
+ }
+ } catch (error) {
+ console.error('鑾峰彇鍥哄畾璧勪骇鏁版嵁澶辫触锛�', error);
+ }
+};
+
+// 鍒濆鍖�
+onMounted(() => {
+ // 鑾峰彇鍒楄〃鏁版嵁
+ fetchData();
+});
+
+// 鏍煎紡鍖栬揣甯�
+const formatCurrency = (value) => {
+ if (!value) return '0.00';
+ return Number(value).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+};
+
+// 鑾峰彇鐘舵�佹爣绛剧被鍨�
+const getStatusTagType = (status) => {
+ switch (status) {
+ case '鍦ㄧ敤':
+ return 'success';
+ case '闂茬疆':
+ return 'info';
+ case '缁翠慨涓�':
+ return 'warning';
+ case '鎶ュ簾':
+ return 'danger';
+ default:
+ return 'info';
+ }
+};
+
+// 閲嶇疆绛涢�夋潯浠�
+const resetFilters = () => {
+ dateRange.value = null;
+ equipmentType.value = '';
+ fetchData();
+};
+
+// 鍒嗛〉澶勭悊
+const handleSizeChange = (size) => {
+ pagination.value.pageSize = size;
+ fetchData();
+};
+
+const handleCurrentChange = (page) => {
+ pagination.value.currentPage = page;
+ fetchData();
+};
+</script>
+
+<style scoped lang="scss">
+/* 鍩虹鏍峰紡琛ュ厖 */
+:root {
+ --el-color-primary: #4f46e5;
+}
+
+.el-card {
+ position: relative;
+ border-radius: 12px;
+ padding: 14px 10px 10px 10px;
+ box-shadow: 0 2px 8px #eee;
+
+ :deep(.el-card__body) {
+ padding: 10px 20px !important;
+ }
+
+ &.bg1 {
+ background: url(@/assets/icons/png/1.png) no-repeat 100% 100% !important;
+ }
+
+ &.bg2 {
+ background: url(@/assets/icons/png/2.png) no-repeat 100% 100% !important;
+ }
+
+ &.bg3 {
+ background: url(@/assets/icons/png/3.png) no-repeat 100% 100% !important;
+ }
+
+ &.bg4 {
+ background: url(@/assets/icons/png/4.png) no-repeat 100% 100% !important;
+ }
+
+ &.bg5 {
+ background: url(@/assets/icons/png/5.png) no-repeat 100% 100% !important;
+ }
+}
+
+.grid-container {
+ /* grid 瀹瑰櫒鍩虹鏍峰紡 */
+ display: grid;
+ gap: 1rem; /* gap-4 瀵瑰簲 1rem (16px) */
+ margin-bottom: 2rem; /* mb-8 瀵瑰簲 2rem (32px) */
+
+ p {
+ font-size: 22px;
+ margin-top: 0px;
+ color: #fff;
+ }
+
+ h3 {
+ font-size: 36px;
+ font-weight: 500;
+ font-family: 'MyCustomFont', sans-serif;
+ margin: 10px 0;
+ color: #fff;
+ }
+}
+
+/* 绉诲姩绔粯璁ゆ牱寮� (grid-cols-1) */
+.grid-container {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+}
+
+/* 灏忓睆骞曞強浠ヤ笂 (sm:grid-cols-2) */
+@media (min-width: 640px) {
+ .grid-container {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
+
+/* 澶у睆骞曞強浠ヤ笂 (lg:grid-cols-5) */
+@media (min-width: 1024px) {
+ .grid-container {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+}
+
+/* 鍗$墖鎮仠鏁堟灉澧炲己 */
+.el-card:hover {
+ transform: translateY(-2px);
+}
+
+.echarts {
+ display: flex;
+ justify-content: space-between;
+}
+
+/* 鍥捐〃瀹瑰櫒鏍峰紡 */
+.el-chart {
+ width: 100%;
+ height: 100%;
+}
+
+.section-title {
+ position: relative;
+ font-size: 18px;
+ color: #333;
+ padding-left: 10px;
+ margin-bottom: 10px;
+ font-weight: 700;
+}
+
+.section-title::before {
+ position: absolute;
+ left: 0;
+ top: 0px;
+ content: '';
+ width: 4px;
+ height: 18px;
+ background-color: #002FA7;
+ border-radius: 2px;
+}
+
+.chart-num {
+ position: absolute;
+ z-index: 3;
+ top: 92px;
+ left: 92px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.pagination-container {
+ margin-top: 20px;
+ display: flex;
+ justify-content: center;
+}
+</style>
diff --git a/src/views/financialManagement/inventoryAccounting/index.vue b/src/views/financialManagement/inventoryAccounting/index.vue
new file mode 100644
index 0000000..3acf5d9
--- /dev/null
+++ b/src/views/financialManagement/inventoryAccounting/index.vue
@@ -0,0 +1,390 @@
+<template>
+ <div class="inventory-statistics">
+ <!-- 绛涢�夎〃鍗� -->
+ <div class="filter-form">
+ <el-form :model="filterForm" inline>
+<!-- <el-form-item label="鏃堕棿鑼冨洿">-->
+<!-- <el-date-picker-->
+<!-- v-model="filterForm.dateRange"-->
+<!-- type="daterange"-->
+<!-- range-separator="鑷�"-->
+<!-- start-placeholder="寮�濮嬫棩鏈�"-->
+<!-- end-placeholder="缁撴潫鏃ユ湡"-->
+<!-- />-->
+<!-- </el-form-item>-->
+<!-- <el-form-item label="渚涘簲鍟嗗悕绉�">-->
+<!-- <el-input v-model="filterForm.supplierName" style="width: 240px" placeholder="璇疯緭鍏�" clearable prefix-icon="Search" />-->
+<!-- </el-form-item>-->
+<!-- <el-form-item label="浜у搧鍚嶇О">-->
+<!-- <el-input v-model="filterForm.productCategory" style="width: 240px" placeholder="璇疯緭鍏�" clearable prefix-icon="Search" />-->
+<!-- </el-form-item>-->
+ <el-form-item>
+ <el-button type="primary" @click="handleSearch">鏌ヨ</el-button>
+<!-- <el-button @click="handleReset">閲嶇疆</el-button>-->
+<!-- <el-button type="success" @click="handleExport">瀵煎嚭</el-button>-->
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <!-- 缁熻姹囨�诲崱鐗� -->
+ <div class="summary-cards">
+ <el-row :gutter="20">
+ <el-col :span="6">
+ <el-card class="summary-card">
+ <div class="summary-item">
+ <p class="summary-title">鎬诲簱瀛樻暟閲�</p>
+ <p class="summary-value">{{ summaryData.totalInventoryCount }}</p>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="summary-card">
+ <div class="summary-item">
+ <p class="summary-title">鎬诲簱瀛橀噾棰�</p>
+ <p class="summary-value">楼{{ summaryData.totalInventoryValue }}</p>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="summary-card">
+ <div class="summary-item">
+ <p class="summary-title">搴撳瓨鍙樺姩鏁伴噺</p>
+ <p class="summary-value">{{ summaryData.inventoryChangeCount }}</p>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="6">
+ <el-card class="summary-card">
+ <div class="summary-item">
+ <p class="summary-title">搴撳瓨鍙樺姩閲戦</p>
+ <p class="summary-value">楼{{ summaryData.inventoryChangeValue }}</p>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鍥捐〃鍖哄煙 -->
+ <div class="chart-section">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-card class="chart-card">
+ <template #header>
+ <div class="card-header">
+ <span>搴撳瓨鍒嗙被鍗犳瘮</span>
+ </div>
+ </template>
+ <div id="category-pie-chart" style="height: 400px;"></div>
+ </el-card>
+ </el-col>
+ <el-col :span="12">
+ <el-card class="chart-card">
+ <template #header>
+ <div class="card-header">
+ <span>搴撳瓨閲戦瓒嬪娍</span>
+ </div>
+ </template>
+ <div id="amount-trend-chart" style="height: 400px;"></div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鏁版嵁琛ㄦ牸 -->
+ <div class="table_list">
+ <el-table
+ :data="tableData"
+ v-loading="loading"
+ border
+ style="width: 100%"
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
+ >
+ <el-table-column align="center" type="selection" width="55" />
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column label="渚涘簲鍟嗗悕绉�" prop="supplierName" width="240" show-overflow-tooltip />
+ <el-table-column label="浜у搧" prop="productCategory" min-width="100" show-overflow-tooltip />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" min-width="200" show-overflow-tooltip />
+ <el-table-column label="鍗曚綅" prop="unit" width="70" show-overflow-tooltip />
+ <el-table-column label="鍏ュ簱鏁伴噺" prop="inboundNum" width="90" show-overflow-tooltip />
+ <el-table-column label="搴撳瓨鏁伴噺" prop="inboundNum0" width="90" show-overflow-tooltip />
+ <el-table-column label="鍚◣鍗曚环" prop="taxInclusiveUnitPrice" width="100" show-overflow-tooltip />
+ <el-table-column label="鍚◣鎬讳环" prop="taxInclusiveTotalPrice" width="100" show-overflow-tooltip />
+ <el-table-column label="绋庣巼(%)" prop="taxRate" width="80" show-overflow-tooltip />
+ <el-table-column label="涓嶅惈绋庢�讳环" prop="taxExclusiveTotalPrice" width="100" show-overflow-tooltip />
+ <el-table-column label="鍏ュ簱浜�" prop="createBy" width="100" show-overflow-tooltip />
+ </el-table>
+ <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" />
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, nextTick } from 'vue'
+import * as echarts from 'echarts'
+import {getStockInChartData, getStockInPage} from "@/api/inventoryManagement/stockIn.js";
+
+// 鐘舵�佸彉閲�
+const loading = ref(false)
+const total = ref(0)
+const tableData = ref([])
+const summaryData = ref({})
+const page = reactive({
+ current: 1,
+ size: 100,
+})
+
+// 鍥捐〃瀹炰緥
+const categoryPieChart = ref(null)
+const amountTrendChart = ref(null)
+
+// 绛涢�夎〃鍗�
+const filterForm = reactive({
+ dateRange: [],
+ supplierName: '',
+ productCategory: ''
+})
+
+const paginationChange = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ loadData()
+}
+
+// 鍒濆鍖栨暟鎹�
+onMounted(() => {
+ loadSummaryData()
+ loadData()
+})
+
+// 鍔犺浇缁熻姹囨�绘暟鎹�
+const loadSummaryData = () => {
+ getStockInChartData().then(res => {
+ summaryData.value = res.data
+ })
+}
+
+// 鍔犺浇搴撳瓨鏁版嵁
+const loadData = () => {
+ loading.value = true
+ getStockInPage({ ...filterForm, ...page }).then(res => {
+ loading.value = false
+ tableData.value = res.data.records
+ total.value = res.data.total
+ console.log('res', res.data.records)
+
+ // 鏁版嵁鍔犺浇瀹屾垚鍚庢覆鏌撳浘琛�
+ nextTick(() => {
+ renderCategoryPieChart()
+ renderAmountTrendChart()
+ })
+ }).catch(() => {
+ loading.value = false
+ })
+}
+
+// 娓叉煋鍒嗙被鍗犳瘮楗煎浘
+const renderCategoryPieChart = () => {
+ if (!categoryPieChart.value) {
+ categoryPieChart.value = echarts.init(document.getElementById('category-pie-chart'))
+ }
+ // 鏍规嵁 tableData 鎸� productCategory 鍒嗙被骞惰绠� inboundNum0 鏁伴噺鎬诲拰
+ const categoryMap = tableData.value.reduce((acc, cur) => {
+ acc[cur.productCategory] = (acc[cur.productCategory] || 0) + cur.inboundNum0
+ return acc
+ }, {})
+
+ // 灏嗗垎绫荤粨鏋滆浆鎹负 ECharts 楗煎浘鎵�闇�鐨勬暟鎹牸寮�
+ const categoryData = Object.entries(categoryMap).map(([name, value]) => ({
+ name: name,
+ value: value
+ }))
+ const option = {
+ title: {
+ text: '搴撳瓨鍒嗙被鍗犳瘮',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b}: {c} ({d}%)'
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'left'
+ },
+ series: [
+ {
+ name: '搴撳瓨鍒嗙被',
+ type: 'pie',
+ radius: ['40%', '70%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderRadius: 10,
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: true,
+ formatter: '{b}: {d}%'
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: '16',
+ fontWeight: 'bold'
+ }
+ },
+ data: categoryData
+ }
+ ]
+ }
+
+ categoryPieChart.value.setOption(option)
+}
+// 娓叉煋閲戦瓒嬪娍鎶樼嚎鍥�
+const renderAmountTrendChart = () => {
+ if (!amountTrendChart.value) {
+ amountTrendChart.value = echarts.init(document.getElementById('amount-trend-chart'))
+ }
+ // 鎸夋湀浠藉垎缁勫苟璁$畻taxInclusiveTotalPrice鎬诲拰
+ const monthlyAmounts = tableData.value.reduce((acc, cur) => {
+ const date = new Date(cur.createTime);
+ const month = date.getMonth() + 1;
+
+ // 纭繚month鍦�1-12鑼冨洿鍐�
+ if (month >= 1 && month <= 12) {
+ acc[month] = (acc[month] || 0) + cur.taxInclusiveTotalPrice;
+ }
+ return acc;
+ }, {});
+
+ // 鐢熸垚12涓湀鐨勬暟鎹紝缂哄け鏈堜唤鐢�0浠f浛
+ const amounts = [];
+ for (let i = 1; i <= 12; i++) {
+ amounts.push(monthlyAmounts[i] || 0);
+ }
+ const dates = ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�']
+
+ const option = {
+ title: {
+ text: '搴撳瓨閲戦瓒嬪娍',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis',
+ formatter: '{b}: 楼{c}'
+ },
+ xAxis: {
+ type: 'category',
+ data: dates
+ },
+ yAxis: {
+ type: 'value',
+ axisLabel: {
+ formatter: '楼{value}'
+ }
+ },
+ series: [
+ {
+ name: '搴撳瓨閲戦',
+ type: 'line',
+ data: amounts,
+ smooth: true,
+ areaStyle: {}
+ }
+ ]
+ }
+
+ amountTrendChart.value.setOption(option)
+}
+
+// 鏌ヨ鎿嶄綔
+const handleSearch = () => {
+ loadData()
+}
+
+// 閲嶇疆鎿嶄綔
+const handleReset = () => {
+ filterForm.dateRange = []
+ filterForm.supplierName = ''
+ filterForm.productCategory = ''
+ loadData()
+}
+
+// 瀵煎嚭鎿嶄綔
+const handleExport = () => {
+ console.log('瀵煎嚭鏁版嵁')
+}
+
+// 绐楀彛澶у皬鏀瑰彉鏃讹紝閲嶆柊璋冩暣鍥捐〃澶у皬
+window.addEventListener('resize', () => {
+ if (categoryPieChart.value) categoryPieChart.value.resize()
+ if (amountTrendChart.value) amountTrendChart.value.resize()
+})
+</script>
+
+<style scoped>
+.inventory-statistics {
+ padding: 20px;
+}
+
+.filter-form {
+ margin-bottom: 20px;
+}
+
+.summary-cards {
+ margin-bottom: 20px;
+}
+
+.summary-card {
+ text-align: center;
+ height: 100px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.summary-item {
+ width: 100%;
+}
+
+.summary-title {
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 5px;
+}
+
+.summary-value {
+ font-size: 24px;
+ font-weight: bold;
+ color: #303133;
+}
+
+.summary-value.warning {
+ color: #e6a23c;
+}
+
+.summary-value.danger {
+ color: #f56c6c;
+}
+
+.chart-section {
+ margin-bottom: 20px;
+}
+
+.chart-card {
+ height: 460px;
+}
+
+.card-header {
+ font-weight: bold;
+}
+
+.table_list {
+ margin-top: 20px;
+}
+
+.pagination {
+ text-align: right;
+ margin-top: 20px;
+}
+</style>
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index 7b81814..80e0cc7 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -21,6 +21,10 @@
<el-input v-model="searchForm.salesContractNo" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
@change="handleQuery" />
</el-form-item>
+ <el-form-item label="椤圭洰鍚嶇О锛�">
+ <el-input v-model="searchForm.projectName" placeholder="璇疯緭鍏�" clearable prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
<el-form-item label="褰曞叆鏃ユ湡锛�">
<el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
@@ -50,6 +54,7 @@
:summary-method="summarizeMainTable"
@expand-change="expandChange"
height="calc(100vh - 19em)"
+ :row-class-name="tableRowClassName"
>
<el-table-column align="center" type="selection" width="55" />
<el-table-column type="expand">
@@ -106,6 +111,32 @@
prop="supplierName"
show-overflow-tooltip
/>
+ <el-table-column label="璁㈠崟鐘舵��" width="100" align="center">
+ <template #default="scope">
+ <el-tag v-if="scope.row.isInvalid" type="danger" size="small">澶辨晥</el-tag>
+ <el-tag v-else type="success" size="small">姝e父</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="椤圭洰鍚嶇О"
+ prop="projectName"
+ width="420"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ label="瀹℃壒鐘舵��"
+ prop="approvalStatus"
+ width="200"
+ show-overflow-tooltip
+ >
+ <template #default="scope">
+ <el-tag
+ size="small"
+ >
+ {{ approvalStatusText[scope.row.approvalStatus] || '鏈煡鐘舵��' }}
+ </el-tag>
+ </template>
+ </el-table-column>
<el-table-column
label="绛捐鏃ユ湡"
prop="executionDate"
@@ -208,6 +239,7 @@
placeholder="璇烽�夋嫨"
filterable
clearable
+ @change="salesLedgerChange"
>
<el-option
v-for="item in salesContractList"
@@ -683,6 +715,15 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
+ <el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
+ <el-input
+ v-model="scanAddForm.projectName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
<el-form-item label="鍚堝悓閲戦(鍏�)锛�" prop="contractAmount">
<el-input-number
v-model="scanAddForm.contractAmount"
@@ -761,6 +802,11 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
+ <el-form-item label="椤圭洰鍚嶇О锛�">
+ <el-input v-model="scanForm.projectName" disabled />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
<el-form-item label="鎵爜鏃堕棿锛�">
<el-input v-model="scanForm.scanTime" disabled />
</el-form-item>
@@ -824,7 +870,7 @@
</template>
<script setup>
-import { getToken } from "@/utils/auth";
+import {getToken} from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
import { Search } from "@element-plus/icons-vue";
@@ -840,18 +886,20 @@
} from "@/api/salesManagement/salesLedger.js";
import {
addOrEditPurchase,
+ addPurchaseTemplate,
+ createPurchaseNo,
delPurchase,
getSalesNo,
purchaseListPage,
productList,
getPurchaseById,
getOptions,
- createPurchaseNo,
- getPurchaseTemplateList,
- addPurchaseTemplate,
+ getPurchaseTemplateList
} from "@/api/procurementManagement/procurementLedger.js";
import useFormData from "@/hooks/useFormData.js";
import QRCode from "qrcode";
+
+
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const productData = ref([]);
@@ -984,6 +1032,7 @@
supplierName: "", // 渚涘簲鍟嗗悕绉�
purchaseContractNumber: "", // 閲囪喘鍚堝悓缂栧彿
salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+ projectName: "", // 椤圭洰鍚嶇О
entryDate: null, // 褰曞叆鏃ユ湡
entryDateStart: undefined,
entryDateEnd: undefined,
@@ -991,6 +1040,7 @@
form: {
purchaseContractNumber: "",
salesLedgerId: "",
+ projectName: "",
recorderId: "",
entryDate: "",
productData: [],
@@ -1005,6 +1055,7 @@
],
approverId:[{ required: true, message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change" }],
projectName:[{ required:true, message:"璇疯緭鍏ラ」鐩悕绉�", trigger:"blur"}],
+ supplierId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
},
@@ -1192,8 +1243,13 @@
purchaseListPage({ ...rest, ...page })
.then((res) => {
tableLoading.value = false;
- tableData.value = res.data.records;
- tableData.value.map((item) => {
+ // tableData.value = res.data.records;
+ tableData.value = res.data.records.map(record => ({
+ ...record,
+ isInvalid: record.isWhite === 1
+ }));
+ // 鍒濆鍖栧瓙鏁版嵁鏁扮粍
+ tableData.value.forEach((item) => {
item.children = [];
});
total.value = res.data.total;
@@ -1333,18 +1389,24 @@
}
}
// 绉婚櫎鏂囦欢
-function handleRemove(file) {
+async function handleRemove(file) {
+ if (!file?.id) {
+ return;
+ }
console.log("handleRemove", file.id);
if (file.size > 1024 * 1024 * 10) {
// 浠呭墠绔竻鐞嗭紝涓嶈皟鐢ㄥ垹闄ゆ帴鍙e拰鎻愮ず
- return;
+ return;
}
- if (operationType.value === "edit") {
- let ids = [];
- ids.push(file.id);
- delLedgerFile(ids).then((res) => {
+
+ if (operationType.value === "edit" && file.id) {
+ try {
+ await delLedgerFile([file.id]);
proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
- });
+ } catch (error) {
+ console.error('鍒犻櫎鏂囦欢澶辫触:', error);
+ proxy.$modal.msgError("鍒犻櫎鏂囦欢澶辫触");
+ }
}
}
// 鎻愪氦琛ㄥ崟
@@ -1711,6 +1773,7 @@
scanContent: "",
purchaseContractNumber: "",
supplierName: "",
+ projectName: "",
contractAmount: "",
paymentMethod: "",
recorderName: "",
@@ -1719,6 +1782,7 @@
const scanAddRules = {
purchaseContractNumber: [{ required: true, message: "璇疯緭鍏ラ噰璐悎鍚屽彿", trigger: "blur" }],
supplierName: [{ required: true, message: "璇疯緭鍏ヤ緵搴斿晢鍚嶇О", trigger: "blur" }],
+ projectName: [{ required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" }],
};
// 鎵爜鐧昏瀵硅瘽妗嗙浉鍏冲彉閲�
@@ -1726,6 +1790,7 @@
const scanForm = reactive({
purchaseContractNumber: "",
supplierName: "",
+ projectName: "",
scanTime: "",
scannerName: "",
scanStatus: "鏈壂鐮�",
@@ -1741,6 +1806,7 @@
scanAddForm.scanContent = "";
scanAddForm.purchaseContractNumber = "";
scanAddForm.supplierName = "";
+ scanAddForm.projectName = "";
scanAddForm.contractAmount = "";
scanAddForm.paymentMethod = "";
scanAddForm.recorderName = userStore.nickName;
@@ -1760,6 +1826,9 @@
scanAddForm.supplierName = parts[1] || "";
scanAddForm.contractAmount = parts[2] || "";
scanAddForm.paymentMethod = parts[3] || "";
+ scanAddForm.projectName = parts[4] || "";
+ // scanAddForm.contractAmount = parts[3] || "";
+ // scanAddForm.paymentMethod = parts[4] || "";
}
};
@@ -1777,6 +1846,7 @@
const newData = {
purchaseContractNumber: scanAddForm.purchaseContractNumber,
supplierName: scanAddForm.supplierName,
+ projectName: scanAddForm.projectName,
contractAmount: scanAddForm.contractAmount,
paymentMethod: scanAddForm.paymentMethod,
recorderName: scanAddForm.recorderName,
@@ -1799,6 +1869,7 @@
const openScanDialog = (row) => {
scanForm.purchaseContractNumber = row.purchaseContractNumber;
scanForm.supplierName = row.supplierName;
+ scanForm.projectName = row.projectName;
scanForm.scanTime = getCurrentDateTime();
scanForm.scannerName = userStore.nickName;
scanForm.scanStatus = "鏈壂鐮�";
diff --git a/src/views/procurementManagement/transferManagement/index.vue b/src/views/procurementManagement/transferManagement/index.vue
new file mode 100644
index 0000000..0a443f2
--- /dev/null
+++ b/src/views/procurementManagement/transferManagement/index.vue
@@ -0,0 +1,434 @@
+<template>
+ <div class="app-container">
+ <!-- 鎼滅储杩囨护鍖� -->
+ <el-form :model="searchForm" :inline="true">
+ <el-form-item label="閲囪喘鍚堝悓鍙�">
+ <el-input v-model="searchForm.purchaseContractNumber" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ <el-form-item label="渚涘簲鍟�">
+ <el-input v-model="searchForm.supplierName" placeholder="璇疯緭鍏�" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="search">鎼滅储</el-button>
+ <el-button @click="resetSearch">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 琛ㄦ牸灞曠ず鍖� -->
+ <el-table :data="orderList" border v-loading="loading" height="calc(100vh - 12em)">
+ <!-- 娣诲姞搴忓彿鍒� -->
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column prop="purchaseContractNumber" label="閲囪喘鍚堝悓鍙�" show-overflow-tooltip />
+ <el-table-column prop="supplierName" label="渚涘簲鍟�" show-overflow-tooltip />
+ <el-table-column label="浠樻鐘舵��">
+ <template #default="scope">
+ <el-tag
+ :type="getPaymentStatusType(scope.row.paymentStatus)"
+ size="small"
+ >
+ {{ getPaymentStatusText(scope.row.paymentStatus) }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏀惰揣鐘舵��">
+ <template #default="scope">
+ <el-tag
+ :type="getReceiptStatusType(scope.row.receiptStatus)"
+ size="small"
+ >
+ {{ getReceiptStatusText(scope.row.receiptStatus) }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="receivedQuantity" label="宸叉敹璐ф暟閲�"/>
+ <el-table-column prop="unreceivedQuantity" label="鏈敹璐ф暟閲�"/>
+ <el-table-column label="鎿嶄綔" width="200" fixed="right" align="center">
+ <template #default="scope">
+ <el-button
+ type="primary"
+ size="small"
+ @click="confirmReceipter(scope.row)"
+ >
+ 纭鏀惰揣
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <!-- 鍦ㄨ〃鏍间笅鏂规坊鍔犲垎椤� -->
+ <pagination
+ v-show="total > 0"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationChange"
+ />
+ <!-- 纭鏀惰揣瀵硅瘽妗� -->
+ <el-dialog v-model="receiptDialogVisible" title="纭鏀惰揣" width="70%">
+ <el-form :model="receiptForm" label-width="120px" ref="formRef">
+ <el-form-item label="閲囪喘鍚堝悓鍙�">
+ <el-input v-model="receiptForm.purchaseContractNumber" disabled />
+ </el-form-item>
+ <el-form-item label="寮傚父鍘熷洜">
+ <el-input
+ v-model="receiptForm.exceptionReason"
+ type="textarea"
+ placeholder="璇疯緭鍏ュ紓甯稿師鍥狅紙涓嶅悎鏍兼椂濉啓锛�"
+ />
+ </el-form-item>
+ <el-table
+ :data="productList"
+ border
+ v-loading="loadingProducts"
+ @selection-change="handleSelectionChange"
+ >
+ <el-table-column align="center" type="selection" width="55" />
+ <el-table-column
+ align="center"
+ label="搴忓彿"
+ type="index"
+ width="60"
+ />
+ <el-table-column label="浜у搧澶х被" prop="productCategory" />
+ <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
+ <el-table-column label="鍗曚綅" prop="unit" width="70" />
+ <el-table-column label="渚涘簲鍟�" prop="supplierName" width="100" />
+ <el-table-column label="閲囪喘鏁伴噺" prop="quantity" width="100" />
+ <el-table-column label="寰呭叆搴撴暟閲�" prop="quantity0" width="100" />
+ <el-table-column label="鏈鍏ュ簱鏁伴噺" prop="quantityStock" width="150">
+ <template #default="scope">
+ <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="scope.row.quantityStock" />
+ </template>
+ </el-table-column>
+<!-- 鍚堟牸鎴栦笉鍚堟牸-->
+ <el-table-column label="鏄惁鍚堟牸" width="100">
+ <template #default="scope">
+ <el-select v-model="scope.row.isQualified" placeholder="璇烽�夋嫨">
+ <el-option label="鍚堟牸" value="1" />
+ <el-option label="涓嶅悎鏍�" value="2" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="绋庣巼(%)" prop="taxRate" width="120" />
+ <el-table-column
+ label="鍚◣鍗曚环(鍏�)"
+ prop="taxInclusiveUnitPrice"
+ :formatter="formattedNumber"
+ width="150"
+ />
+ <el-table-column
+ label="鍚◣鎬讳环(鍏�)"
+ prop="taxInclusiveTotalPrice"
+ :formatter="formattedNumber"
+ width="150"
+ />
+ <el-table-column
+ label="涓嶅惈绋庢�讳环(鍏�)"
+ prop="taxExclusiveTotalPrice"
+ :formatter="formattedNumber"
+ width="150"
+ />
+ </el-table>
+ </el-form>
+ <template #footer>
+ <el-button @click="receiptDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="submitReceipt">纭鏀惰揣</el-button>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import {ref, onMounted, getCurrentInstance} from 'vue'
+import {
+ getPurchaseOrders,
+ confirmReceipt,
+ addPurchaseException
+} from '@/api/procurementManagement/transferManagement.js'
+import {selectProductRecordListByPuechaserId, addSutockIn, updateStockIn} from "@/api/inventoryManagement/stockIn.js";
+import useUserStore from "@/store/modules/user.js";
+
+
+const userStore = useUserStore()
+const { proxy } = getCurrentInstance()
+
+// 鏁版嵁瀹氫箟
+const orderList = ref([])
+const receiptDialogVisible = ref(false)
+const receiptForm = ref({
+ purchaseContractNumber: '',
+ exceptionReason: '',
+ purchaseLedgerId: '',
+})
+const operationType = ref('')// 鎿嶄綔绫诲瀷: 'add' 鎴� 'edit'
+const productList = ref([]);// 浜у搧鍒楄〃鏁版嵁
+const loadingProducts = ref(false);// 浜у搧鍔犺浇鐘舵��
+const selectedRows = ref([]);
+const loading = ref(false);
+const total = ref(0); // 鎬昏褰曟暟
+// 鎼滅储琛ㄥ崟
+const searchForm = ref({
+ purchaseContractNumber: '',
+ supplierName: '',
+})
+// 鍒嗛〉鏁版嵁
+const page = reactive({
+ current: 1,
+ size: 100, // 姣忛〉鏄剧ず鏁伴噺
+});
+
+// 鍒嗛〉鍙樺寲澶勭悊
+const paginationChange = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getReceiptOrders(); // 閲嶆柊鑾峰彇鏁版嵁
+};
+// 鑾峰彇璁㈠崟鍒楄〃
+const getReceiptOrders = async () => {
+ loading.value = true;
+ try {
+ const response = await getPurchaseOrders({
+ ...searchForm.value,
+ current: page.current,
+ size: page.size
+ });
+ // 浣跨敤 Promise.all 澶勭悊鎵�鏈夊紓姝ヨ姹�
+ const processedOrders = await Promise.all(response.data.records.map(async (order) => {
+ // 绛夊緟寮傛鑾峰彇浜у搧璁板綍
+ const productRes = await selectProductRecordListByPuechaserId({
+ purchaseContractNumber: order.purchaseContractNumber
+ });
+
+ // 纭繚 productRes.data 瀛樺湪
+ if (productRes && productRes.data && Array.isArray(productRes.data)) {
+ // 璁$畻鎬绘暟閲�
+ order.totalQuantity = productRes.data.reduce((acc, cur) => acc + (cur.quantity || 0), 0);
+ // 璁$畻鏈敹璐ф暟閲�
+ order.unreceivedQuantity = productRes.data.reduce((acc, cur) => acc + (cur.quantity0 || 0), 0);
+ // 璁$畻宸叉敹璐ф暟閲�
+ order.receivedQuantity = order.totalQuantity - order.unreceivedQuantity;
+
+ // 淇鐘舵�佸垽鏂�昏緫锛堜娇鐢� === 杩涜姣旇緝锛�
+ if (order.unreceivedQuantity === 0) {
+ order.paymentStatus = 1;
+ order.receiptStatus = 1;
+ } else if (order.receivedQuantity === 0) {
+ order.paymentStatus = 3;
+ order.receiptStatus = 3;
+ } else {
+ order.paymentStatus = 2;
+ order.receiptStatus = 2;
+ }
+ } else {
+ // 濡傛灉娌℃湁浜у搧璁板綍锛岃缃粯璁ゅ��
+ order.totalQuantity = 0;
+ order.unreceivedQuantity = 0;
+ order.receivedQuantity = 0;
+ order.receiptStatus = 3; // 鏈叆搴�
+ }
+
+ return order;
+ }));
+
+ // 姝g‘璧嬪�肩粰 orderList
+ orderList.value = processedOrders;
+ total.value = response.data.total;
+ } catch (error) {
+ console.error('鑾峰彇璁㈠崟鍒楄〃澶辫触:', error);
+ proxy.$modal.msgError('鑾峰彇璁㈠崟鍒楄〃澶辫触');
+ } finally {
+ loading.value = false;
+ }
+}
+
+// 浠樻鐘舵�佹樉绀哄鐞�
+const getPaymentStatusText = (status) => {
+ const statusMap = { '1': '宸蹭粯娆�', '2': '閮ㄥ垎浠樻', '3': '鏈粯娆�' }
+ return statusMap[status] || '鏈煡'
+}
+
+const getPaymentStatusType = (status) => {
+ const typeMap = { '1': 'success', '2': 'warning', '3': 'danger' }
+ return typeMap[status] || 'info'
+}
+
+// 鏀惰揣鐘舵�佸鐞�
+const getReceiptStatusText = (status) => {
+ const statusMap = { '1': '鏀惰揣瀹屾垚', '2': '閮ㄥ垎鍏ュ簱', '3': '鏈叆搴�' }
+ return statusMap[status] || '鏈煡'
+}
+
+const getReceiptStatusType = (status) => {
+ const typeMap = { '1': 'success', '2': 'warning', '3': 'info' }
+ return typeMap[status] || 'info'
+}
+const exceedsAddLimit = (product) => {
+ const stock = Number(product?.quantityStock ?? 0);
+ const waiting = Number(product?.quantity0 ?? 0);
+ if (!Number.isFinite(stock) || !Number.isFinite(waiting)) {
+ return false;
+ }
+ return stock > waiting;
+};
+const exceedsEditLimit = (product) => {
+ const stock = Number(product?.quantityStock ?? 0);
+ const waiting = Number(product?.quantity0 ?? 0);
+ const original = Number(product?.originalQuantityStock ?? 0);
+ if (!Number.isFinite(stock) || !Number.isFinite(waiting) || !Number.isFinite(original)) {
+ return false;
+ }
+ return stock > waiting + original;
+};
+const updatePro = async () => {
+ const target = selectedRows.value[0];
+ const stock = Number(target?.quantityStock ?? 0);
+ if (!Number.isFinite(stock) || stock <= 0) {
+ proxy.$modal.msgWarning('璇峰~鍐欐湁鏁堢殑鍏ュ簱鏁伴噺');
+ return;
+ }
+ if (exceedsEditLimit(target)) {
+ proxy.$modal.msgError('鏈鍏ュ簱鏁伴噺涓嶈兘瓒呰繃鍘熷叆搴撴暟閲忎笌寰呭叆搴撴暟閲忎箣鍜�');
+ return;
+ }
+ const stockInData = {
+ id: selectedRows.value[0].recordId,
+ quantityStock: Number(selectedRows.value[0].quantityStock),// 浣跨敤鏂版牸寮忓寲鍑芥暟
+ };
+ await updateStockIn(stockInData)
+ proxy.$modal.msgSuccess('淇敼鍏ュ簱鎴愬姛')
+ closeDia()
+ getReceiptOrders() // 鍒锋柊鍒楄〃
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ // 杩囨护鎺夊瓙鏁版嵁
+ selectedRows.value = selection.filter(item => item.id);
+}
+// 鎵撳紑寮规-纭鏀惰揣
+const confirmReceipter = (row) => {
+ receiptForm.value = {
+ purchaseContractNumber: row.purchaseContractNumber,
+ purchaseLedgerId: row.id,
+ exceptionReason: ''
+ }
+ selectedRows.value = []
+ receiptDialogVisible.value = true
+ fetchProductsByContract()
+}
+
+const fetchProductsByContract = async () =>
+{
+ try {
+ loadingProducts.value = true
+ // 鏍规嵁鍚堝悓鏌ヨ浜у搧璁板綍
+ const productRes = await selectProductRecordListByPuechaserId({
+ purchaseContractNumber: receiptForm.value.purchaseContractNumber
+ });
+ console.log('productRes:', productRes)
+ operationType.value = 'add'
+ if (!productRes.data || productRes.data.length === 0) {
+ proxy.$modal.msgWarning('璇ュ悎鍚屼笅娌℃湁浜у搧璁板綍')
+ productList.value = [];
+ return
+ }
+ // 澶勭悊浜у搧鏁版嵁锛屾坊鍔犳湰娆″叆搴撴暟閲忓瓧娈�
+ productList.value = productRes.data.map(item => ({
+ ...item,
+ quantityStock: 0,
+ originalQuantityStock: Number(item.quantityStock ?? item.inboundQuantity ?? 0),
+ }))
+ selectedRows.value = productList.value
+ } catch (error) {
+ console.error('鏌ヨ浜у搧璁板綍澶辫触:', error)
+ proxy.$modal.msgError('鏌ヨ浜у搧璁板綍澶辫触')
+ productList.value = [];
+ } finally {
+ loadingProducts.value = false
+ }
+}
+
+
+// 鎻愪氦鏀惰揣纭
+const submitReceipt = async () => {
+ if(operationType.value !== 'add'){
+ await updatePro()
+ return
+ }
+ try {
+ await proxy.$refs.formRef.validate()
+ // 楠岃瘉鍏ュ簱鏁伴噺
+ const invalidProducts = selectedRows.value.filter((product) => {
+ const stock = Number(product?.quantityStock ?? 0);
+ if (!Number.isFinite(stock) || stock <= 0) {
+ return true;
+ }
+ return exceedsAddLimit(product);
+ })
+
+ if (invalidProducts.length > 0) {
+ proxy.$modal.msgError('鏈鍏ュ簱鏁伴噺闇�澶т簬0锛屼笖涓嶈兘瓒呰繃寰呭叆搴撴暟閲忥紝鎴栬�呭嬀閫変骇鍝�')
+ return
+ }
+ loading.value = true
+ // 鍑嗗鎻愪氦鏁版嵁 - 淇敼涓哄悗绔渶瑕佺殑鏍煎紡
+ const stockInData = {
+ // 鍏ュ簱鍗曞熀鏈俊鎭�
+ ...receiptForm.value,
+ nickName: userStore.nickName,
+ details: selectedRows.value.map(product => ({
+ id: product.id,
+ inboundQuantity: Number(product.quantityStock)
+ })),
+ };
+ //濡傛灉浜у搧鍚堟牸
+ if(productList.value.every(product => product.isQualified === '1')){
+ await addSutockIn(stockInData)
+
+ proxy.$modal.msgSuccess('纭鏀惰揣,鍏ュ簱鎴愬姛')
+ }else{
+ stockInData.details.forEach(item => {
+ const ProcurementExceptionRecord = {
+ purchaseContractNumber: receiptForm.value.purchaseContractNumber,
+ purchaseLedgerId: receiptForm.value.purchaseLedgerId,
+ exceptionNum: item.inboundQuantity,
+ exceptionReason: receiptForm.value.exceptionReason
+ }
+ addPurchaseException(ProcurementExceptionRecord).then(response => {
+ proxy.$modal.msgSuccess('浜у搧涓嶅悎鏍硷紝閲囪喘寮傚父璁板綍鎴愬姛')
+ })
+ })
+ }
+ closeDia()
+ getReceiptOrders() // 鍒锋柊鍒楄〃
+
+ } catch (error) {
+ console.error('鎻愪氦澶辫触:', error)
+ if (!error.errors) {
+ proxy.$modal.msgError('鎿嶄綔澶辫触锛岃閲嶈瘯')
+ }
+ } finally {
+ loading.value = false
+ }
+}
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.$refs.formRef.resetFields()
+ receiptDialogVisible.value = false
+}
+// 鎼滅储鍜岄噸缃�
+const search = () => {
+ getReceiptOrders()
+}
+
+const resetSearch = () => {
+ searchForm.value = {
+ purchaseContractNumber: '',
+ supplierName: '',
+ }
+ getReceiptOrders()
+}
+
+onMounted(() => {
+ getReceiptOrders()
+})
+</script>
--
Gitblit v1.9.3