进销存-升级
1.供应商往来展示联调修改
2.指标统计页面展示联调修改
3.用户管理新增修改时字段修改
4.不需要多用户登录
5.采购报表展示修改联调
6.借款管理页面开发联调
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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 代表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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | // ç»è®¡æ°æ® |
| | | const businessSummaryStats = ref({ |
| | | totalAmount: 0, |
| | | productTypes: 0, |
| | | supplierCount: 0 |
| | | productTypes: 0 |
| | | }) |
| | | |
| | | // è¡¨æ ¼åé
ç½®ï¼æ ¹æ®åç«¯åæ®µå®ä¹ï¼ |
| | |
| | | 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 |
| | | } |
| | | } |
| | | } |
| | |
| | | <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" />
|
| | |
| | | <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">
|
| | |
| | | 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)
|
| | |
| | | }
|
| | |
|
| | | /** æ ¹æ®åç§°çéé¨é¨æ */
|
| | | watch(deptName, val => {
|
| | | watch(deptNames, val => {
|
| | | proxy.$refs["deptTreeRef"].filter(val)
|
| | | })
|
| | |
|
| | |
| | | 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()
|