From ae2a253b23738b9b33daedbe50fc599d8d0eac52 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 15 一月 2026 18:00:47 +0800
Subject: [PATCH] 进销存-升级 1.供应商往来展示联调修改 2.指标统计页面展示联调修改 3.用户管理新增修改时字段修改 4.不需要多用户登录 5.采购报表展示修改联调 6.借款管理页面开发联调
---
src/views/system/user/index.vue | 17 +
src/views/procurementManagement/procurementReport/index.vue | 7
src/views/financialManagement/loanManagement/Modal.vue | 222 ++++++++++++++++++++++
src/views/financialManagement/loanManagement/index.vue | 276 +++++++++++++++++++++++++++
src/api/financialManagement/loanManagement.js | 37 +++
5 files changed, 548 insertions(+), 11 deletions(-)
diff --git a/src/api/financialManagement/loanManagement.js b/src/api/financialManagement/loanManagement.js
new file mode 100644
index 0000000..46ea749
--- /dev/null
+++ b/src/api/financialManagement/loanManagement.js
@@ -0,0 +1,37 @@
+import request from "@/utils/request";
+
+// 鏌ヨ鍒楄〃
+export const listPage = (params) => {
+ return request({
+ url: "/borrowInfo/listPage",
+ method: "get",
+ params,
+ });
+};
+
+// 鏂板
+export function add(data) {
+ return request({
+ url: "/borrowInfo/add",
+ method: "post",
+ data: data,
+ });
+}
+
+// 缂栬緫
+export function update(data) {
+ return request({
+ url: "/borrowInfo/update",
+ method: "post",
+ data: data,
+ });
+}
+
+// 鍒犻櫎
+export const delAccountLoan = (data) => {
+ return request({
+ url: "/borrowInfo/delete",
+ method: "delete",
+ data,
+ });
+};
diff --git a/src/views/financialManagement/loanManagement/Modal.vue b/src/views/financialManagement/loanManagement/Modal.vue
new file mode 100644
index 0000000..73b2cc3
--- /dev/null
+++ b/src/views/financialManagement/loanManagement/Modal.vue
@@ -0,0 +1,222 @@
+<template>
+ <FormDialog
+ v-model="dialogVisible"
+ :title="dialogTitle"
+ :operationType="operationType"
+ width="60%"
+ @confirm="sendForm"
+ @close="close"
+ @cancel="close"
+ >
+ <el-form
+ ref="formRef"
+ :model="form"
+ :rules="formRules"
+ label-width="120px"
+ >
+ <el-form-item label="鍊熸浜哄鍚�" prop="borrowerName">
+ <el-input v-model="form.borrowerName" placeholder="璇疯緭鍏ュ�熸浜哄鍚�" />
+ </el-form-item>
+ <el-form-item label="鍊熸閲戦锛堝厓锛�" prop="borrowAmount">
+ <el-input-number
+ :step="0.01"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ v-model="form.borrowAmount"
+ placeholder="璇疯緭鍏ュ�熸閲戦"
+ />
+ </el-form-item>
+ <el-form-item label="鍊熸鍒╃巼锛�%锛�" prop="interestRate">
+ <el-input-number
+ :step="0.01"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ v-model="form.interestRate"
+ placeholder="璇疯緭鍏ュ�熸鍒╃巼锛屽锛�5.85"
+ />
+ </el-form-item>
+ <el-form-item label="鍊熸鏃ユ湡" prop="borrowDate">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.borrowDate"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨鍊熸鏃ユ湡"
+ clearable
+ />
+ </el-form-item>
+ <!-- 瀹為檯杩樻鏃ユ湡锛氫粎鈥滆繕娆锯�濇椂鍙~ -->
+ <el-form-item
+ v-if="operationType === 'repay'"
+ label="瀹為檯杩樻鏃ユ湡"
+ prop="repayDate"
+ >
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.repayDate"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨瀹為檯杩樻鏃ユ湡锛堣繕娆惧悗濉啓锛�"
+ clearable
+ />
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input
+ v-model="form.remark"
+ type="textarea"
+ :rows="3"
+ placeholder="璇疯緭鍏ュ娉紙鍊熸璇存槑锛�"
+ />
+ </el-form-item>
+ </el-form>
+ </FormDialog>
+</template>
+
+<script setup>
+import { add, update } from "@/api/financialManagement/loanManagement";
+import useFormData from "@/hooks/useFormData";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { ElMessage } from "element-plus";
+import { ref } from "vue";
+
+defineOptions({
+ name: "鍊熸鏂板缂栬緫",
+});
+
+const emits = defineEmits(["success"]);
+
+const formRef = ref(null);
+const dialogVisible = ref(false);
+const operationType = ref("add"); // add | edit
+const id = ref(undefined);
+const submitting = ref(false);
+
+const dialogTitle = (type) => {
+ if (type === "edit") return "缂栬緫鍊熸";
+ if (type === "repay") return "杩樻";
+ return "鏂板鍊熸";
+};
+
+const formRules = {
+ borrowerName: [{ required: true, trigger: "blur", message: "璇疯緭鍏ュ�熸浜哄鍚�" }],
+ borrowAmount: [{ required: true, trigger: "blur", message: "璇疯緭鍏ュ�熸閲戦" }],
+ interestRate: [{ required: true, trigger: "blur", message: "璇疯緭鍏ュ�熸鍒╃巼" }],
+ borrowDate: [{ required: true, trigger: "change", message: "璇烽�夋嫨鍊熸鏃ユ湡" }],
+ repayDate: [
+ {
+ validator: (_rule, value, callback) => {
+ if (operationType.value === "repay" && !value) {
+ callback(new Error("璇烽�夋嫨瀹為檯杩樻鏃ユ湡"));
+ return;
+ }
+ callback();
+ },
+ trigger: "change",
+ },
+ ],
+};
+
+const { form, resetForm } = useFormData({
+ borrowerName: undefined, // 鍊熸浜哄鍚�
+ borrowAmount: undefined, // 鍊熸閲戦锛堝厓锛�
+ interestRate: undefined, // 鍊熸鍒╃巼锛堝锛�5.85 浠h〃5.85%锛�
+ borrowDate: undefined, // 鍊熸鏃ユ湡
+ repayDate: undefined, // 瀹為檯杩樻鏃ユ湡锛堣繕娆惧悗濉厖锛�
+ remark: undefined, // 澶囨敞锛堝�熸璇存槑锛�
+});
+
+const sendForm = () => {
+ if (submitting.value) return;
+ formRef.value?.validate(async (valid) => {
+ if (valid) {
+ submitting.value = true;
+ try {
+ const isRepay = operationType.value === "repay";
+ // 杩樻锛氫笉灞曠ず status锛屼絾鎻愪氦鏃跺己鍒朵紶 status=2锛岃蛋鏇存柊鎺ュ彛
+ const payload = isRepay
+ ? { id: id.value, ...form, status: 2 }
+ : id.value
+ ? { id: id.value, ...form }
+ : form;
+
+ const { code } = isRepay
+ ? await update(payload)
+ : id.value
+ ? await update(payload)
+ : await add(payload);
+ if (code == 200) {
+ emits("success");
+ ElMessage({ message: "鎿嶄綔鎴愬姛", type: "success" });
+ close();
+ }
+ } finally {
+ submitting.value = false;
+ }
+ }
+ });
+};
+
+const close = () => {
+ resetForm();
+ formRef.value?.clearValidate();
+ id.value = undefined;
+ dialogVisible.value = false;
+};
+
+// 缂栬緫锛氱洿鎺ョ敤鍒楄〃琛屾暟鎹洖濉紙閬垮厤渚濊禆璇︽儏鎺ュ彛锛�
+const loadForm = async (row) => {
+ const rowId = row?.id;
+ operationType.value = "edit";
+ id.value = rowId;
+ dialogVisible.value = true;
+ if (rowId) {
+ form.borrowerName = row.borrowerName;
+ form.borrowAmount = row.borrowAmount;
+ form.interestRate = row.interestRate;
+ form.borrowDate = row.borrowDate;
+ form.repayDate = row.repayDate;
+ form.remark = row.remark;
+ } else {
+ resetForm();
+ formRef.value?.clearValidate();
+ }
+};
+
+// 杩樻锛氭墦寮�寮圭獥锛屼粎濉啓瀹為檯杩樻鏃ユ湡锛屾彁浜ゆ椂寮哄埗 status=2
+const repay = async (row) => {
+ const rowId = row?.id;
+ operationType.value = "repay";
+ id.value = rowId;
+ dialogVisible.value = true;
+ if (rowId) {
+ // 涓轰簡璧� update 鎺ュ彛鏇寸ǔ濡ワ紝甯︿笂鍘熸湁鏁版嵁锛涘彧璁╃敤鎴烽�� repayDate
+ form.borrowerName = row.borrowerName;
+ form.borrowAmount = row.borrowAmount;
+ form.interestRate = row.interestRate;
+ form.borrowDate = row.borrowDate;
+ form.remark = row.remark;
+ form.repayDate = undefined;
+ } else {
+ resetForm();
+ formRef.value?.clearValidate();
+ }
+};
+
+const openModal = () => {
+ operationType.value = "add";
+ id.value = undefined;
+ resetForm();
+ formRef.value?.clearValidate();
+ dialogVisible.value = true;
+};
+
+defineExpose({
+ openModal,
+ loadForm,
+ repay,
+});
+</script>
diff --git a/src/views/financialManagement/loanManagement/index.vue b/src/views/financialManagement/loanManagement/index.vue
new file mode 100644
index 0000000..202313a
--- /dev/null
+++ b/src/views/financialManagement/loanManagement/index.vue
@@ -0,0 +1,276 @@
+<template>
+ <div class="app-container">
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="鍊熸浜哄鍚�:">
+ <el-input
+ v-model="filters.borrowerName"
+ placeholder="璇疯緭鍏ュ�熸浜哄鍚�"
+ clearable
+ style="width: 200px;"
+ />
+ </el-form-item>
+ <el-form-item label="鍊熸鏃ユ湡:">
+ <el-date-picker
+ v-model="filters.borrowDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ @change="changeDaterange"
+ />
+ </el-form-item>
+ <el-form-item label="鍊熸鐘舵��:">
+ <el-select
+ v-model="filters.status"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 200px;"
+ >
+ <el-option label="寰呰繕娆�" :value="1" />
+ <el-option label="宸茶繕娆�" :value="2" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getTableData">鎼滅储</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ <div class="table_list">
+ <div class="actions">
+ <div></div>
+ <div>
+ <el-button type="primary" @click="add" icon="Plus"> 鏂板 </el-button>
+ <el-button @click="handleOut" icon="download">瀵煎嚭</el-button>
+ <el-button
+ type="danger"
+ icon="Delete"
+ :disabled="multipleList.length <= 0"
+ @click="deleteRow(multipleList.map((item) => item.id))"
+ >
+ 鎵归噺鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ <PIMTable
+ rowKey="id"
+ isSelection
+ :column="columns"
+ :tableData="dataList"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="changePage"
+ >
+ <template #operation="{ row }">
+ <el-button type="primary" link @click="edit(row)">
+ 缂栬緫
+ </el-button>
+ <el-button
+ v-if="row.status == 1"
+ type="primary"
+ link
+ @click="repay(row)"
+ >
+ 杩樻
+ </el-button>
+ </template>
+ </PIMTable>
+ </div>
+ <Modal ref="modalRef" @success="getTableData"></Modal>
+ </div>
+</template>
+
+<script setup>
+import { usePaginationApi } from "@/hooks/usePaginationApi";
+import { listPage, delAccountLoan } from "@/api/financialManagement/loanManagement";
+import { onMounted, getCurrentInstance, ref, nextTick } from "vue";
+import Modal from "./Modal.vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+import dayjs from "dayjs";
+
+defineOptions({
+ name: "鍊熸绠$悊",
+});
+
+// 琛ㄦ牸澶氶�夋閫変腑椤�
+const multipleList = ref([]);
+const { proxy } = getCurrentInstance();
+const modalRef = ref();
+
+const {
+ filters,
+ columns,
+ dataList,
+ pagination,
+ getTableData,
+ resetFilters,
+ onCurrentChange,
+} = usePaginationApi(
+ listPage,
+ {
+ borrowerName: undefined,
+ borrowDate: undefined,
+ status: undefined,
+ },
+ [
+ {
+ label: "鍊熸浜哄鍚�",
+ prop: "borrowerName",
+ width: 150,
+ },
+ {
+ label: "鍊熸閲戦锛堝厓锛�",
+ prop: "borrowAmount",
+ width: 150,
+ formatData: (val) => {
+ return val ? `楼${parseFloat(val).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : '楼0.00';
+ },
+ },
+ {
+ label: "鍊熸鍒╃巼锛�%锛�",
+ prop: "interestRate",
+ width: 130,
+ formatData: (val) => {
+ return val ? `${parseFloat(val).toFixed(2)}%` : '-';
+ },
+ },
+ {
+ label: "鍊熸鏃ユ湡",
+ prop: "borrowDate",
+ width: 120,
+ },
+ {
+ label: "瀹為檯杩樻鏃ユ湡",
+ prop: "repayDate",
+ width: 130,
+ },
+ {
+ label: "鍊熸鐘舵��",
+ prop: "status",
+ width: 100,
+ dataType: "tag",
+ formatData: (params) => {
+ if (params == 1) {
+ return "寰呰繕娆�";
+ } else if (params == 2) {
+ return "宸茶繕娆�";
+ }
+ return null;
+ },
+ formatType: (params) => {
+ if (params == 1) {
+ return "error";
+ } else if (params == 2) {
+ return "success";
+ }
+ return null;
+ },
+ },
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "120px",
+ },
+ ],
+ null,
+ {
+ // 灏嗗墠绔�熸鏃ユ湡鑼冨洿杞崲涓哄悗绔渶瑕佺殑 entryDateStart / entryDateEnd锛屽苟涓斾笉浼� borrowDate
+ borrowDate: (val) => {
+ if (val && val.length === 2) {
+ return {
+ entryDateStart: dayjs(val[0]).format("YYYY-MM-DD"),
+ entryDateEnd: dayjs(val[1]).format("YYYY-MM-DD"),
+ };
+ }
+ return {};
+ },
+ }
+);
+
+// 澶氶�夊悗鍋氫粈涔�
+const handleSelectionChange = (selectionList) => {
+ multipleList.value = selectionList;
+};
+
+const add = () => {
+ modalRef.value.openModal();
+};
+
+const edit = (row) => {
+ modalRef.value.loadForm(row);
+};
+
+const repay = (row) => {
+ modalRef.value.repay(row);
+};
+
+const changePage = ({ page, limit }) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
+ onCurrentChange(page);
+};
+
+const deleteRow = (id) => {
+ ElMessageBox.confirm("姝ゆ搷浣滃皢姘镐箙鍒犻櫎璇ユ暟鎹�, 鏄惁缁х画?", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(async () => {
+ const { code } = await delAccountLoan(id);
+ if (code == 200) {
+ ElMessage({
+ type: "success",
+ message: "鍒犻櫎鎴愬姛",
+ });
+ getTableData();
+ }
+ });
+};
+
+const changeDaterange = (value) => {
+ if (value) {
+ filters.borrowDate = value;
+ } else {
+ filters.borrowDate = null;
+ }
+ getTableData();
+};
+
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download(`/borrowInfo/export`, {}, "鍊熸鍙拌处.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
+
+onMounted(() => {
+ getTableData();
+});
+</script>
+
+<style lang="scss" scoped>
+.table_list {
+ margin-top: unset;
+}
+.actions {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+</style>
diff --git a/src/views/procurementManagement/procurementReport/index.vue b/src/views/procurementManagement/procurementReport/index.vue
index 60a900d..8c8f3f6 100644
--- a/src/views/procurementManagement/procurementReport/index.vue
+++ b/src/views/procurementManagement/procurementReport/index.vue
@@ -95,8 +95,7 @@
// 缁熻鏁版嵁
const businessSummaryStats = ref({
totalAmount: 0,
- productTypes: 0,
- supplierCount: 0
+ productTypes: 0
})
// 琛ㄦ牸鍒楅厤缃紙鏍规嵁鍚庣瀛楁瀹氫箟锛�
@@ -243,12 +242,10 @@
return sum + (parseFloat(item.purchaseAmount) || 0)
}, 0)
businessSummaryStats.value.productTypes = new Set(businessSummaryData.value.map(item => item.productCategory)).size
- businessSummaryStats.value.supplierCount = new Set(businessSummaryData.value.map(item => item.supplierName).filter(Boolean)).size
} else {
businessSummaryStats.value = {
totalAmount: 0,
- productTypes: 0,
- supplierCount: 0
+ productTypes: 0
}
}
}
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index 0855f11..f28463b 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -6,7 +6,7 @@
<pane size="16">
<el-col style="padding: 10px">
<div class="head-container">
- <el-input v-model="deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" clearable prefix-icon="Search" style="margin-bottom: 20px" />
+ <el-input v-model="deptNames" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" clearable prefix-icon="Search" style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="{ label: 'label', children: 'children' }" :expand-on-click-node="false" :filter-node-method="filterNode" ref="deptTreeRef" node-key="id" highlight-current default-expand-all @node-click="handleNodeClick" />
@@ -61,7 +61,7 @@
<el-table-column label="鐢ㄦ埛缂栧彿" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="鐧诲綍璐﹀彿" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="鐢ㄦ埛鏄电О" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
- <el-table-column label="閮ㄩ棬" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
+ <el-table-column label="閮ㄩ棬" align="center" key="deptNames" prop="deptNames" v-if="columns[3].visible" :show-overflow-tooltip="true" />
<el-table-column label="鎵嬫満鍙风爜" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column label="鐘舵��" align="center" key="status" v-if="columns[5].visible">
<template #default="scope">
@@ -235,7 +235,7 @@
const total = ref(0)
const title = ref("")
const dateRange = ref([])
-const deptName = ref("")
+const deptNames = ref("")
const deptOptions = ref(undefined)
const enabledDeptOptions = ref(undefined)
const initPassword = ref(undefined)
@@ -298,7 +298,7 @@
}
/** 鏍规嵁鍚嶇О绛涢�夐儴闂ㄦ爲 */
-watch(deptName, val => {
+watch(deptNames, val => {
proxy.$refs["deptTreeRef"].filter(val)
})
@@ -519,14 +519,19 @@
function submitForm() {
proxy.$refs["userRef"].validate(valid => {
if (valid) {
+ // 褰掑睘閮ㄩ棬铏界劧鏄崟閫夛紝浣嗗悗绔渶瑕佷紶鏁扮粍瀛楁 deptIds
+ const payload = {
+ ...form.value,
+ deptIds: form.value.deptId ? [form.value.deptId] : []
+ }
if (form.value.userId != undefined) {
- updateUser(form.value).then(response => {
+ updateUser(payload).then(response => {
proxy.$modal.msgSuccess("淇敼鎴愬姛")
open.value = false
getList()
})
} else {
- addUser(form.value).then(response => {
+ addUser(payload).then(response => {
proxy.$modal.msgSuccess("鏂板鎴愬姛")
open.value = false
getList()
--
Gitblit v1.9.3